Skip to content

Commit 5fedb10

Browse files
committed
Fix IORing build for older Linux kernel versions
1 parent a067a07 commit 5fedb10

File tree

3 files changed

+119
-83
lines changed

3 files changed

+119
-83
lines changed

Sources/CSystem/include/io_uring.h

Lines changed: 101 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,112 @@
33
#include <sys/uio.h>
44
#include <signal.h>
55

6+
#define __SWIFT_IORING_SQE_FALLBACK_STRUCT { \
7+
__u8 opcode; \
8+
__u8 flags; \
9+
__u16 ioprio; \
10+
__s32 fd; \
11+
union { \
12+
__u64 off; \
13+
__u64 addr2; \
14+
struct { \
15+
__u32 cmd_op; \
16+
__u32 __pad1; \
17+
}; \
18+
}; \
19+
union { \
20+
__u64 addr; \
21+
__u64 splice_off_in; \
22+
struct { \
23+
__u32 level; \
24+
__u32 optname; \
25+
}; \
26+
}; \
27+
__u32 len; \
28+
union { \
29+
__kernel_rwf_t rw_flags; \
30+
__u32 fsync_flags; \
31+
__u16 poll_events; \
32+
__u32 poll32_events; \
33+
__u32 sync_range_flags; \
34+
__u32 msg_flags; \
35+
__u32 timeout_flags; \
36+
__u32 accept_flags; \
37+
__u32 cancel_flags; \
38+
__u32 open_flags; \
39+
__u32 statx_flags; \
40+
__u32 fadvise_advice; \
41+
__u32 splice_flags; \
42+
__u32 rename_flags; \
43+
__u32 unlink_flags; \
44+
__u32 hardlink_flags; \
45+
__u32 xattr_flags; \
46+
__u32 msg_ring_flags; \
47+
__u32 uring_cmd_flags; \
48+
__u32 waitid_flags; \
49+
__u32 futex_flags; \
50+
__u32 install_fd_flags; \
51+
__u32 nop_flags; \
52+
}; \
53+
__u64 user_data; \
54+
union { \
55+
__u16 buf_index; \
56+
__u16 buf_group; \
57+
} __attribute__((packed)); \
58+
__u16 personality; \
59+
union { \
60+
__s32 splice_fd_in; \
61+
__u32 file_index; \
62+
__u32 optlen; \
63+
struct { \
64+
__u16 addr_len; \
65+
__u16 __pad3[1]; \
66+
}; \
67+
}; \
68+
union { \
69+
struct { \
70+
__u64 addr3; \
71+
__u64 __pad2[1]; \
72+
}; \
73+
__u64 optval; \
74+
__u8 cmd[0]; \
75+
}; \
76+
}
77+
678
#if __has_include(<linux/io_uring.h>)
779
#include <linux/io_uring.h>
80+
81+
#ifdef IORING_TIMEOUT_BOOTTIME
82+
// Kernel version >= 5.15, io_uring_sqe has file_index
83+
// and all current Swift operations are supported.
84+
#define __SWIFT_IORING_SUPPORTED true
85+
typedef struct io_uring_sqe swift_io_uring_sqe;
86+
#else
87+
// io_uring_sqe is missing properties that IORequest expects.
88+
// This configuration is not supported for now.
89+
//
90+
// Define a fallback struct to avoid build errors, but IORing
91+
// will throw ENOTSUP on initialization.
92+
#define __SWIFT_IORING_SUPPORTED false
93+
typedef struct __SWIFT_IORING_SQE_FALLBACK_STRUCT swift_io_uring_sqe;
94+
#endif
95+
96+
// We can define more specific availability later
97+
98+
#ifdef IORING_FEAT_RW_CUR_POS
99+
// Kernel version >= 5.6, io_uring_sqe has open_flags
100+
#endif
101+
102+
#ifdef IORING_FEAT_NODROP
103+
// Kernel version >= 5.5, io_uring_sqe has cancel_flags
104+
#endif
105+
8106
#else
9107
// Minimal fallback definitions when linux/io_uring.h is not available (e.g. static SDK)
10108
#include <stdint.h>
11109

110+
#define __SWIFT_IORING_SUPPORTED false
111+
12112
#define IORING_OFF_SQ_RING 0ULL
13113
#define IORING_OFF_CQ_RING 0x8000000ULL
14114
#define IORING_OFF_SQES 0x10000000ULL
@@ -44,77 +144,7 @@ typedef int32_t __s32;
44144
typedef int __kernel_rwf_t;
45145
#endif
46146

47-
struct io_uring_sqe {
48-
__u8 opcode;
49-
__u8 flags;
50-
__u16 ioprio;
51-
__s32 fd;
52-
union {
53-
__u64 off;
54-
__u64 addr2;
55-
struct {
56-
__u32 cmd_op;
57-
__u32 __pad1;
58-
};
59-
};
60-
union {
61-
__u64 addr;
62-
__u64 splice_off_in;
63-
struct {
64-
__u32 level;
65-
__u32 optname;
66-
};
67-
};
68-
__u32 len;
69-
union {
70-
__kernel_rwf_t rw_flags;
71-
__u32 fsync_flags;
72-
__u16 poll_events;
73-
__u32 poll32_events;
74-
__u32 sync_range_flags;
75-
__u32 msg_flags;
76-
__u32 timeout_flags;
77-
__u32 accept_flags;
78-
__u32 cancel_flags;
79-
__u32 open_flags;
80-
__u32 statx_flags;
81-
__u32 fadvise_advice;
82-
__u32 splice_flags;
83-
__u32 rename_flags;
84-
__u32 unlink_flags;
85-
__u32 hardlink_flags;
86-
__u32 xattr_flags;
87-
__u32 msg_ring_flags;
88-
__u32 uring_cmd_flags;
89-
__u32 waitid_flags;
90-
__u32 futex_flags;
91-
__u32 install_fd_flags;
92-
__u32 nop_flags;
93-
};
94-
__u64 user_data;
95-
union {
96-
__u16 buf_index;
97-
__u16 buf_group;
98-
} __attribute__((packed));
99-
__u16 personality;
100-
union {
101-
__s32 splice_fd_in;
102-
__u32 file_index;
103-
__u32 optlen;
104-
struct {
105-
__u16 addr_len;
106-
__u16 __pad3[1];
107-
};
108-
};
109-
union {
110-
struct {
111-
__u64 addr3;
112-
__u64 __pad2[1];
113-
};
114-
__u64 optval;
115-
__u8 cmd[0];
116-
};
117-
};
147+
typedef struct __SWIFT_IORING_SQE_FALLBACK_STRUCT swift_io_uring_sqe;
118148

119149
struct io_uring_cqe {
120150
__u64 user_data;

Sources/System/IORing/IORing.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ extension UnsafeMutableRawBufferPointer {
7272
@inline(__always) @inlinable
7373
internal func _tryWriteRequest(
7474
_ request: __owned RawIORequest, ring: inout SQRing,
75-
submissionQueueEntries: UnsafeMutableBufferPointer<io_uring_sqe>
75+
submissionQueueEntries: UnsafeMutableBufferPointer<swift_io_uring_sqe>
7676
)
7777
-> Bool
7878
{
@@ -151,9 +151,9 @@ internal func _flushQueue(ring: borrowing SQRing) -> UInt32 {
151151

152152
@inlinable
153153
internal func _getSubmissionEntry(
154-
ring: inout SQRing, submissionQueueEntries: UnsafeMutableBufferPointer<io_uring_sqe>
154+
ring: inout SQRing, submissionQueueEntries: UnsafeMutableBufferPointer<swift_io_uring_sqe>
155155
) -> UnsafeMutablePointer<
156-
io_uring_sqe
156+
swift_io_uring_sqe
157157
>? {
158158
let next = ring.userTail &+ 1 //this is expected to wrap
159159

@@ -196,7 +196,7 @@ private func setUpRing(
196196
throw err
197197
}
198198

199-
if params.features & IORING_FEAT_NODROP == 0
199+
if params.features & IORing.Features.nonDroppingCompletions.rawValue == 0
200200
{
201201
close(ringDescriptor)
202202
throw Errno.invalidArgument
@@ -266,7 +266,7 @@ private func setUpRing(
266266
// map the submission queue
267267
let sqes = mmap(
268268
/* addr: */ nil,
269-
/* len: */ Int(params.sq_entries) * MemoryLayout<io_uring_sqe>.size,
269+
/* len: */ Int(params.sq_entries) * MemoryLayout<swift_io_uring_sqe>.size,
270270
/* prot: */ PROT_READ | PROT_WRITE,
271271
/* flags: */ MAP_SHARED | MAP_POPULATE,
272272
/* fd: */ ringDescriptor,
@@ -307,7 +307,7 @@ public struct IORing: ~Copyable {
307307

308308
@usableFromInline let completionRing: CQRing
309309

310-
@usableFromInline let submissionQueueEntries: UnsafeMutableBufferPointer<io_uring_sqe>
310+
@usableFromInline let submissionQueueEntries: UnsafeMutableBufferPointer<swift_io_uring_sqe>
311311

312312
// kept around for unmap / cleanup. TODO: we can save a few words of memory by figuring out how to handle cleanup for non-IORING_FEAT_SINGLE_MMAP better
313313
let ringSize: Int
@@ -366,6 +366,10 @@ public struct IORing: ~Copyable {
366366

367367
/// Initializes an IORing with enough space for `queueDepth` prepared requests and completed operations
368368
public init(queueDepth: UInt32, flags: SetupFlags = []) throws(Errno) {
369+
guard __SWIFT_IORING_SUPPORTED != 0 else {
370+
throw Errno.notSupported
371+
}
372+
369373
let (params, tmpRingDescriptor, tmpRingPtr, tmpRingSize, tmpSQPtr, tmpSQSize, tmpCQPtr, tmpCQSize, sqes) = try setUpRing(queueDepth: queueDepth, flags: flags)
370374
// All throws need to be before initializing ivars here to avoid
371375
// "error: conditional initialization or destruction of noncopyable types is not supported;
@@ -421,7 +425,7 @@ public struct IORing: ~Copyable {
421425
)
422426

423427
let submissionQueueEntries = UnsafeMutableBufferPointer(
424-
start: sqes.assumingMemoryBound(to: io_uring_sqe.self),
428+
start: sqes.assumingMemoryBound(to: swift_io_uring_sqe.self),
425429
count: Int(params.sq_entries)
426430
)
427431

@@ -868,7 +872,7 @@ public struct IORing: ~Copyable {
868872
}
869873
munmap(
870874
UnsafeMutableRawPointer(submissionQueueEntries.baseAddress!),
871-
submissionQueueEntries.count * MemoryLayout<io_uring_sqe>.size
875+
submissionQueueEntries.count * MemoryLayout<swift_io_uring_sqe>.size
872876
)
873877
close(ringDescriptor)
874878
}

Sources/System/IORing/RawIORequest.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import CSystem
55

66
@usableFromInline
77
internal struct RawIORequest: ~Copyable {
8-
@usableFromInline var rawValue: io_uring_sqe
8+
// swift_io_uring_sqe is a typedef of io_uring_sqe on platforms where
9+
// IORing is supported (currently requires kernel version >= 5.15).
10+
@usableFromInline var rawValue: swift_io_uring_sqe
911
@usableFromInline var path: FilePath? //buffer owner for the path pointer that the sqe may have
1012

1113
@inlinable public init() {
12-
self.rawValue = io_uring_sqe()
14+
self.rawValue = swift_io_uring_sqe()
1315
}
1416
}
1517

@@ -176,8 +178,8 @@ extension RawIORequest {
176178

177179
@inlinable
178180
static func withTimeoutRequest<R>(
179-
linkedTo opEntry: UnsafeMutablePointer<io_uring_sqe>,
180-
in timeoutEntry: UnsafeMutablePointer<io_uring_sqe>,
181+
linkedTo opEntry: UnsafeMutablePointer<swift_io_uring_sqe>,
182+
in timeoutEntry: UnsafeMutablePointer<swift_io_uring_sqe>,
181183
duration: Duration,
182184
flags: TimeOutFlags,
183185
work: () throws -> R) rethrows -> R {

0 commit comments

Comments
 (0)