Skip to content

Commit d89ca1d

Browse files
authored
Merge pull request #247 from jrflat/ioring-for-older-kernels
Fix IORing build for older Linux kernels
2 parents 960067d + d32abd8 commit d89ca1d

File tree

4 files changed

+127
-84
lines changed

4 files changed

+127
-84
lines changed

.github/workflows/pull_request.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ jobs:
99
name: Test
1010
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
1111
with:
12-
linux_exclude_swift_versions: '[{"swift_version": "5.8"}]'
12+
linux_os_versions: '["jammy", "focal"]'
13+
enable_macos_checks: false
14+
macos_xcode_versions: '["16.3"]'
15+
1316
soundness:
1417
name: Soundness
1518
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main

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: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import Musl
1010
#endif
1111
import Synchronization
1212

13+
private var ioringSupported: Bool {
14+
__SWIFT_IORING_SUPPORTED != 0
15+
}
16+
1317
//This was #defines in older headers, so we redeclare it to get a consistent import
1418
internal enum RegistrationOps: UInt32 {
1519
case registerBuffers = 0
@@ -72,7 +76,7 @@ extension UnsafeMutableRawBufferPointer {
7276
@inline(__always) @inlinable
7377
internal func _tryWriteRequest(
7478
_ request: __owned RawIORequest, ring: inout SQRing,
75-
submissionQueueEntries: UnsafeMutableBufferPointer<io_uring_sqe>
79+
submissionQueueEntries: UnsafeMutableBufferPointer<swift_io_uring_sqe>
7680
)
7781
-> Bool
7882
{
@@ -151,9 +155,9 @@ internal func _flushQueue(ring: borrowing SQRing) -> UInt32 {
151155

152156
@inlinable
153157
internal func _getSubmissionEntry(
154-
ring: inout SQRing, submissionQueueEntries: UnsafeMutableBufferPointer<io_uring_sqe>
158+
ring: inout SQRing, submissionQueueEntries: UnsafeMutableBufferPointer<swift_io_uring_sqe>
155159
) -> UnsafeMutablePointer<
156-
io_uring_sqe
160+
swift_io_uring_sqe
157161
>? {
158162
let next = ring.userTail &+ 1 //this is expected to wrap
159163

@@ -196,7 +200,7 @@ private func setUpRing(
196200
throw err
197201
}
198202

199-
if params.features & IORING_FEAT_NODROP == 0
203+
if params.features & IORing.Features.nonDroppingCompletions.rawValue == 0
200204
{
201205
close(ringDescriptor)
202206
throw Errno.invalidArgument
@@ -266,7 +270,7 @@ private func setUpRing(
266270
// map the submission queue
267271
let sqes = mmap(
268272
/* addr: */ nil,
269-
/* len: */ Int(params.sq_entries) * MemoryLayout<io_uring_sqe>.size,
273+
/* len: */ Int(params.sq_entries) * MemoryLayout<swift_io_uring_sqe>.size,
270274
/* prot: */ PROT_READ | PROT_WRITE,
271275
/* flags: */ MAP_SHARED | MAP_POPULATE,
272276
/* fd: */ ringDescriptor,
@@ -307,7 +311,7 @@ public struct IORing: ~Copyable {
307311

308312
@usableFromInline let completionRing: CQRing
309313

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

312316
// 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
313317
let ringSize: Int
@@ -366,6 +370,10 @@ public struct IORing: ~Copyable {
366370

367371
/// Initializes an IORing with enough space for `queueDepth` prepared requests and completed operations
368372
public init(queueDepth: UInt32, flags: SetupFlags = []) throws(Errno) {
373+
guard ioringSupported else {
374+
throw Errno.notSupported
375+
}
376+
369377
let (params, tmpRingDescriptor, tmpRingPtr, tmpRingSize, tmpSQPtr, tmpSQSize, tmpCQPtr, tmpCQSize, sqes) = try setUpRing(queueDepth: queueDepth, flags: flags)
370378
// All throws need to be before initializing ivars here to avoid
371379
// "error: conditional initialization or destruction of noncopyable types is not supported;
@@ -421,7 +429,7 @@ public struct IORing: ~Copyable {
421429
)
422430

423431
let submissionQueueEntries = UnsafeMutableBufferPointer(
424-
start: sqes.assumingMemoryBound(to: io_uring_sqe.self),
432+
start: sqes.assumingMemoryBound(to: swift_io_uring_sqe.self),
425433
count: Int(params.sq_entries)
426434
)
427435

@@ -868,7 +876,7 @@ public struct IORing: ~Copyable {
868876
}
869877
munmap(
870878
UnsafeMutableRawPointer(submissionQueueEntries.baseAddress!),
871-
submissionQueueEntries.count * MemoryLayout<io_uring_sqe>.size
879+
submissionQueueEntries.count * MemoryLayout<swift_io_uring_sqe>.size
872880
)
873881
close(ringDescriptor)
874882
}

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)