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