RawIORequest.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #if compiler(>=6.2) && $Lifetimes
  2. #if os(Linux)
  3. import CSystem
  4. #if canImport(Glibc)
  5. import Glibc
  6. #elseif canImport(Musl)
  7. import Musl
  8. #endif
  9. @usableFromInline
  10. internal struct RawIORequest: ~Copyable {
  11. // swift_io_uring_sqe is a typedef of io_uring_sqe on platforms where
  12. // IORing is supported (currently requires kernel version >= 5.15).
  13. @usableFromInline var rawValue: swift_io_uring_sqe
  14. @inlinable public init() {
  15. self.rawValue = swift_io_uring_sqe()
  16. }
  17. }
  18. extension RawIORequest {
  19. @usableFromInline
  20. enum Operation: UInt8 {
  21. case nop = 0
  22. case readv = 1
  23. case writev = 2
  24. case fsync = 3
  25. case readFixed = 4
  26. case writeFixed = 5
  27. case pollAdd = 6
  28. case pollRemove = 7
  29. case syncFileRange = 8
  30. case sendMessage = 9
  31. case receiveMessage = 10
  32. // ...
  33. case asyncCancel = 14
  34. case link_timeout = 15
  35. // ...
  36. case openAt = 18
  37. case close = 19
  38. case filesUpdate = 20
  39. case statx = 21
  40. case read = 22
  41. case write = 23
  42. // ...
  43. case openAt2 = 28
  44. // ...
  45. case unlinkAt = 36
  46. }
  47. public struct Flags: OptionSet, Hashable, Codable {
  48. public let rawValue: UInt8
  49. @inlinable public init(rawValue: UInt8) {
  50. self.rawValue = rawValue
  51. }
  52. @inlinable public static var fixedFile: RawIORequest.Flags { Flags(rawValue: 1 << 0) }
  53. @inlinable public static var drainQueue: RawIORequest.Flags { Flags(rawValue: 1 << 1) }
  54. @inlinable public static var linkRequest: RawIORequest.Flags { Flags(rawValue: 1 << 2) }
  55. @inlinable public static var hardlinkRequest: RawIORequest.Flags { Flags(rawValue: 1 << 3) }
  56. @inlinable public static var asynchronous: RawIORequest.Flags { Flags(rawValue: 1 << 4) }
  57. @inlinable public static var selectBuffer: RawIORequest.Flags { Flags(rawValue: 1 << 5) }
  58. @inlinable public static var skipSuccess: RawIORequest.Flags { Flags(rawValue: 1 << 6) }
  59. }
  60. @inlinable var operation: Operation {
  61. get { Operation(rawValue: rawValue.opcode)! }
  62. set { rawValue.opcode = newValue.rawValue }
  63. }
  64. @inlinable var cancel_flags: UInt32 {
  65. get { rawValue.cancel_flags }
  66. set { rawValue.cancel_flags = newValue }
  67. }
  68. @inlinable var addr: UInt64 {
  69. get { rawValue.addr }
  70. set { rawValue.addr = newValue }
  71. }
  72. @inlinable public var flags: Flags {
  73. get { Flags(rawValue: rawValue.flags) }
  74. set { rawValue.flags = newValue.rawValue }
  75. }
  76. @inlinable public mutating func linkToNextRequest() {
  77. flags = Flags(rawValue: flags.rawValue | Flags.linkRequest.rawValue)
  78. }
  79. @inlinable public var fileDescriptor: FileDescriptor {
  80. get { FileDescriptor(rawValue: rawValue.fd) }
  81. set { rawValue.fd = newValue.rawValue }
  82. }
  83. @inlinable public var offset: UInt64? {
  84. get {
  85. if (rawValue.off == UInt64.max) {
  86. return nil
  87. } else {
  88. return rawValue.off
  89. }
  90. }
  91. set {
  92. if let val = newValue {
  93. rawValue.off = val
  94. } else {
  95. rawValue.off = UInt64.max
  96. }
  97. }
  98. }
  99. @inlinable public var buffer: UnsafeMutableRawBufferPointer {
  100. get {
  101. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(exactly: rawValue.addr)!)
  102. return UnsafeMutableRawBufferPointer(start: ptr, count: Int(rawValue.len))
  103. }
  104. set {
  105. rawValue.addr = UInt64(Int(bitPattern: newValue.baseAddress!))
  106. rawValue.len = UInt32(exactly: newValue.count)!
  107. }
  108. }
  109. public enum RequestFlags {
  110. case readWriteFlags(ReadWriteFlags)
  111. // case fsyncFlags(FsyncFlags?)
  112. // poll_events
  113. // poll32_events
  114. // sync_range_flags
  115. // msg_flags
  116. case timeoutFlags(TimeOutFlags)
  117. // accept_flags
  118. // cancel_flags
  119. case openFlags(FileDescriptor.OpenOptions)
  120. // statx_flags
  121. // fadvise_advice
  122. // splice_flags
  123. }
  124. public struct ReadWriteFlags: OptionSet, Hashable, Codable {
  125. public var rawValue: UInt32
  126. @inlinable public init(rawValue: UInt32) {
  127. self.rawValue = rawValue
  128. }
  129. @inlinable public static var highPriority: RawIORequest.ReadWriteFlags { ReadWriteFlags(rawValue: 1 << 0) }
  130. // sync with only data integrity
  131. @inlinable public static var dataSync: RawIORequest.ReadWriteFlags { ReadWriteFlags(rawValue: 1 << 1) }
  132. // sync with full data + file integrity
  133. @inlinable public static var fileSync: RawIORequest.ReadWriteFlags { ReadWriteFlags(rawValue: 1 << 2) }
  134. // return -EAGAIN if operation blocks
  135. @inlinable public static var noWait: RawIORequest.ReadWriteFlags { ReadWriteFlags(rawValue: 1 << 3) }
  136. // append to end of the file
  137. @inlinable public static var append: RawIORequest.ReadWriteFlags { ReadWriteFlags(rawValue: 1 << 4) }
  138. }
  139. public struct TimeOutFlags: OptionSet, Hashable, Codable {
  140. public var rawValue: UInt32
  141. @inlinable public init(rawValue: UInt32) {
  142. self.rawValue = rawValue
  143. }
  144. @inlinable public static var relativeTime: RawIORequest.TimeOutFlags { TimeOutFlags(rawValue: 0) }
  145. @inlinable public static var absoluteTime: RawIORequest.TimeOutFlags { TimeOutFlags(rawValue: 1 << 0) }
  146. }
  147. }
  148. extension RawIORequest {
  149. @inlinable
  150. static func nop() -> RawIORequest {
  151. var req: RawIORequest = RawIORequest()
  152. req.operation = .nop
  153. return req
  154. }
  155. @inlinable
  156. static func withTimeoutRequest<R, E: Error>(
  157. linkedTo opEntry: UnsafeMutablePointer<swift_io_uring_sqe>,
  158. in timeoutEntry: UnsafeMutablePointer<swift_io_uring_sqe>,
  159. duration: Duration,
  160. flags: TimeOutFlags,
  161. work: () throws(E) -> R) throws(E) -> R {
  162. opEntry.pointee.flags |= Flags.linkRequest.rawValue
  163. opEntry.pointee.off = 1
  164. var ts = timespec(
  165. tv_sec: Int(duration.components.seconds),
  166. tv_nsec: Int(duration.components.attoseconds / 1_000_000_000)
  167. )
  168. return try withUnsafePointer(to: &ts) { tsPtr throws(E) -> R in
  169. var req: RawIORequest = RawIORequest()
  170. req.operation = .link_timeout
  171. req.rawValue.timeout_flags = flags.rawValue
  172. req.rawValue.len = 1
  173. req.rawValue.addr = UInt64(UInt(bitPattern: tsPtr))
  174. timeoutEntry.pointee = req.rawValue
  175. return try work()
  176. }
  177. }
  178. }
  179. #endif // os(Linux)
  180. #endif // compiler(>=6.2) && $Lifetimes