uringmachine 0.19 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/TODO.md +40 -0
- data/examples/bm_fileno.rb +33 -0
- data/examples/bm_mutex.rb +85 -0
- data/examples/bm_mutex_single.rb +33 -0
- data/examples/bm_queue.rb +27 -28
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/fiber_scheduler_demo.rb +15 -51
- data/examples/fiber_scheduler_fork.rb +24 -0
- data/examples/nc_ssl.rb +71 -0
- data/ext/um/extconf.rb +5 -15
- data/ext/um/um.c +73 -42
- data/ext/um/um.h +21 -11
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +94 -23
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_queue_class.c +1 -1
- data/ext/um/um_stream.c +5 -5
- data/ext/um/um_stream_class.c +3 -0
- data/ext/um/um_sync.c +22 -27
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +229 -0
- data/grant-2025/tasks.md +66 -0
- data/lib/uringmachine/fiber_scheduler.rb +180 -48
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +138 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +451 -33
- data/vendor/liburing/.github/workflows/ci.yml +94 -1
- data/vendor/liburing/.github/workflows/test_build.c +9 -0
- data/vendor/liburing/configure +27 -0
- data/vendor/liburing/examples/Makefile +6 -0
- data/vendor/liburing/examples/helpers.c +8 -0
- data/vendor/liburing/examples/helpers.h +5 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +9 -3
- data/vendor/liburing/src/include/liburing/barrier.h +11 -5
- data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
- data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +445 -121
- data/vendor/liburing/src/liburing-ffi.map +15 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/sanitize.c +4 -1
- data/vendor/liburing/src/setup.c +7 -4
- data/vendor/liburing/test/232c93d07b74.c +4 -16
- data/vendor/liburing/test/Makefile +15 -1
- data/vendor/liburing/test/accept.c +2 -13
- data/vendor/liburing/test/conn-unreach.c +132 -0
- data/vendor/liburing/test/fd-pass.c +32 -7
- data/vendor/liburing/test/fdinfo.c +39 -12
- data/vendor/liburing/test/fifo-futex-poll.c +114 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
- data/vendor/liburing/test/futex.c +1 -1
- data/vendor/liburing/test/helpers.c +99 -2
- data/vendor/liburing/test/helpers.h +9 -0
- data/vendor/liburing/test/io_uring_passthrough.c +6 -12
- data/vendor/liburing/test/mock_file.c +379 -0
- data/vendor/liburing/test/mock_file.h +47 -0
- data/vendor/liburing/test/nop.c +2 -2
- data/vendor/liburing/test/nop32-overflow.c +150 -0
- data/vendor/liburing/test/nop32.c +126 -0
- data/vendor/liburing/test/pipe.c +166 -0
- data/vendor/liburing/test/poll-race-mshot.c +13 -1
- data/vendor/liburing/test/recv-mshot-fair.c +81 -34
- data/vendor/liburing/test/recvsend_bundle.c +1 -1
- data/vendor/liburing/test/resize-rings.c +2 -0
- data/vendor/liburing/test/ring-query.c +322 -0
- data/vendor/liburing/test/ringbuf-loop.c +87 -0
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +102 -32
- data/vendor/liburing/test/shutdown.c +2 -12
- data/vendor/liburing/test/socket-nb.c +3 -14
- data/vendor/liburing/test/socket-rw-eagain.c +2 -12
- data/vendor/liburing/test/socket-rw-offset.c +2 -12
- data/vendor/liburing/test/socket-rw.c +2 -12
- data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
- data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
- data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
- data/vendor/liburing/test/timestamp.c +56 -19
- data/vendor/liburing/test/vec-regbuf.c +2 -4
- data/vendor/liburing/test/wq-aff.c +7 -0
- metadata +24 -2
|
@@ -244,3 +244,18 @@ LIBURING_2.11 {
|
|
|
244
244
|
io_uring_memory_size_params;
|
|
245
245
|
io_uring_register_sync_msg;
|
|
246
246
|
} LIBURING_2.10;
|
|
247
|
+
|
|
248
|
+
LIBURING_2.12 {
|
|
249
|
+
global:
|
|
250
|
+
io_uring_prep_pipe;
|
|
251
|
+
io_uring_prep_pipe_direct;
|
|
252
|
+
io_uring_cqe_nr;
|
|
253
|
+
} LIBURING_2.11;
|
|
254
|
+
|
|
255
|
+
LIBURING_2.13 {
|
|
256
|
+
global:
|
|
257
|
+
io_uring_prep_nop128;
|
|
258
|
+
io_uring_prep_uring_cmd;
|
|
259
|
+
io_uring_prep_uring_cmd128;
|
|
260
|
+
io_uring_get_sqe128;
|
|
261
|
+
} LIBURING_2.12;
|
|
@@ -119,7 +119,10 @@ static inline void initialize_sanitize_handlers()
|
|
|
119
119
|
sanitize_handlers[IORING_OP_EPOLL_WAIT] = sanitize_sqe_addr;
|
|
120
120
|
sanitize_handlers[IORING_OP_READV_FIXED] = sanitize_sqe_addr;
|
|
121
121
|
sanitize_handlers[IORING_OP_WRITEV_FIXED] = sanitize_sqe_addr;
|
|
122
|
-
|
|
122
|
+
sanitize_handlers[IORING_OP_PIPE] = sanitize_sqe_addr;
|
|
123
|
+
sanitize_handlers[IORING_OP_NOP128] = sanitize_sqe_nop;
|
|
124
|
+
sanitize_handlers[IORING_OP_URING_CMD128] = sanitize_sqe_optval;
|
|
125
|
+
_Static_assert(IORING_OP_URING_CMD128 + 1 == IORING_OP_LAST, "Need an implementation for all IORING_OP_* codes");
|
|
123
126
|
sanitize_handlers_initialized = true;
|
|
124
127
|
}
|
|
125
128
|
|
data/vendor/liburing/src/setup.c
CHANGED
|
@@ -218,7 +218,7 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p,
|
|
|
218
218
|
{
|
|
219
219
|
unsigned long page_size = get_page_size();
|
|
220
220
|
unsigned sq_entries, cq_entries;
|
|
221
|
-
size_t ring_mem, sqes_mem;
|
|
221
|
+
size_t sqes_size = 0, ring_mem, sqes_mem;
|
|
222
222
|
unsigned long mem_used = 0;
|
|
223
223
|
void *ptr;
|
|
224
224
|
int ret;
|
|
@@ -260,7 +260,8 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p,
|
|
|
260
260
|
buf_size = huge_page_size;
|
|
261
261
|
map_hugetlb = MAP_HUGETLB;
|
|
262
262
|
}
|
|
263
|
-
|
|
263
|
+
sqes_size = buf_size;
|
|
264
|
+
ptr = __sys_mmap(NULL, sqes_size, PROT_READ|PROT_WRITE,
|
|
264
265
|
MAP_SHARED|MAP_ANONYMOUS|map_hugetlb,
|
|
265
266
|
-1, 0);
|
|
266
267
|
if (IS_ERR(ptr))
|
|
@@ -285,7 +286,8 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p,
|
|
|
285
286
|
MAP_SHARED|MAP_ANONYMOUS|map_hugetlb,
|
|
286
287
|
-1, 0);
|
|
287
288
|
if (IS_ERR(ptr)) {
|
|
288
|
-
|
|
289
|
+
if (sqes_size)
|
|
290
|
+
__sys_munmap(sq->sqes, sqes_size);
|
|
289
291
|
return PTR_ERR(ptr);
|
|
290
292
|
}
|
|
291
293
|
sq->ring_ptr = ptr;
|
|
@@ -330,7 +332,7 @@ int __io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
|
|
|
330
332
|
if (fd < 0) {
|
|
331
333
|
if ((p->flags & IORING_SETUP_NO_MMAP) &&
|
|
332
334
|
!(ring->int_flags & INT_FLAG_APP_MEM)) {
|
|
333
|
-
__sys_munmap(ring->sq.sqes,
|
|
335
|
+
__sys_munmap(ring->sq.sqes, ret);
|
|
334
336
|
io_uring_unmap_rings(&ring->sq, &ring->cq);
|
|
335
337
|
}
|
|
336
338
|
return fd;
|
|
@@ -630,6 +632,7 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring,
|
|
|
630
632
|
MAP_SHARED | MAP_POPULATE, ring->ring_fd, off);
|
|
631
633
|
if (IS_ERR(br)) {
|
|
632
634
|
*err = PTR_ERR(br);
|
|
635
|
+
io_uring_unregister_buf_ring(ring, bgid);
|
|
633
636
|
return NULL;
|
|
634
637
|
}
|
|
635
638
|
|
|
@@ -100,14 +100,8 @@ static void *rcv(void *arg)
|
|
|
100
100
|
int s1 = accept(s0, NULL, NULL);
|
|
101
101
|
assert(s1 != -1);
|
|
102
102
|
|
|
103
|
-
if (p->non_blocking)
|
|
104
|
-
|
|
105
|
-
assert(flags != -1);
|
|
106
|
-
|
|
107
|
-
flags |= O_NONBLOCK;
|
|
108
|
-
res = fcntl(s1, F_SETFL, flags);
|
|
109
|
-
assert(res != -1);
|
|
110
|
-
}
|
|
103
|
+
if (p->non_blocking)
|
|
104
|
+
t_set_nonblock(s1);
|
|
111
105
|
|
|
112
106
|
struct io_uring m_io_uring;
|
|
113
107
|
void *ret = NULL;
|
|
@@ -208,14 +202,8 @@ static void *snd(void *arg)
|
|
|
208
202
|
assert(ret != -1);
|
|
209
203
|
}
|
|
210
204
|
|
|
211
|
-
if (p->non_blocking)
|
|
212
|
-
|
|
213
|
-
assert(flags != -1);
|
|
214
|
-
|
|
215
|
-
flags |= O_NONBLOCK;
|
|
216
|
-
ret = fcntl(s0, F_SETFL, flags);
|
|
217
|
-
assert(ret != -1);
|
|
218
|
-
}
|
|
205
|
+
if (p->non_blocking)
|
|
206
|
+
t_set_nonblock(s0);
|
|
219
207
|
|
|
220
208
|
struct io_uring m_io_uring;
|
|
221
209
|
|
|
@@ -31,6 +31,10 @@ ifeq ($(CONFIG_USE_SANITIZER),y)
|
|
|
31
31
|
XCFLAGS += -fsanitize=address,undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
|
32
32
|
endif
|
|
33
33
|
|
|
34
|
+
ifeq ($(CONFIG_USE_TSAN),y)
|
|
35
|
+
XCFLAGS += -fsanitize=thread -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
|
36
|
+
endif
|
|
37
|
+
|
|
34
38
|
CXXFLAGS ?= $(CFLAGS)
|
|
35
39
|
override CFLAGS += $(XCFLAGS) -DLIBURING_BUILD_TEST
|
|
36
40
|
override CXXFLAGS += $(XCFLAGS) -std=c++11 -DLIBURING_BUILD_TEST
|
|
@@ -62,6 +66,7 @@ test_srcs := \
|
|
|
62
66
|
buf-ring-put.c \
|
|
63
67
|
ce593a6c480a.c \
|
|
64
68
|
close-opath.c \
|
|
69
|
+
conn-unreach.c \
|
|
65
70
|
connect.c \
|
|
66
71
|
connect-rep.c \
|
|
67
72
|
coredump.c \
|
|
@@ -98,6 +103,7 @@ test_srcs := \
|
|
|
98
103
|
fdinfo.c \
|
|
99
104
|
fdinfo-sqpoll.c \
|
|
100
105
|
fifo-nonblock-read.c \
|
|
106
|
+
fifo-futex-poll.c \
|
|
101
107
|
file-exit-unreg.c \
|
|
102
108
|
file-register.c \
|
|
103
109
|
files-exit-hang-poll.c \
|
|
@@ -147,12 +153,15 @@ test_srcs := \
|
|
|
147
153
|
no-mmap-inval.c \
|
|
148
154
|
nop-all-sizes.c \
|
|
149
155
|
nop.c \
|
|
156
|
+
nop32.c \
|
|
157
|
+
nop32-overflow.c \
|
|
150
158
|
ooo-file-unreg.c \
|
|
151
159
|
openat2.c \
|
|
152
160
|
open-close.c \
|
|
153
161
|
open-direct-link.c \
|
|
154
162
|
open-direct-pick.c \
|
|
155
163
|
personality.c \
|
|
164
|
+
pipe.c \
|
|
156
165
|
pipe-bug.c \
|
|
157
166
|
pipe-eof.c \
|
|
158
167
|
pipe-reuse.c \
|
|
@@ -191,6 +200,7 @@ test_srcs := \
|
|
|
191
200
|
register-restrictions.c \
|
|
192
201
|
rename.c \
|
|
193
202
|
resize-rings.c \
|
|
203
|
+
ringbuf-loop.c \
|
|
194
204
|
ringbuf-read.c \
|
|
195
205
|
ringbuf-status.c \
|
|
196
206
|
ring-leak2.c \
|
|
@@ -219,7 +229,6 @@ test_srcs := \
|
|
|
219
229
|
socket-rw-offset.c \
|
|
220
230
|
splice.c \
|
|
221
231
|
sq-full.c \
|
|
222
|
-
sq-full-cpp.cc \
|
|
223
232
|
sqpoll-disable-exit.c \
|
|
224
233
|
sqpoll-exec.c \
|
|
225
234
|
sq-poll-dup.c \
|
|
@@ -228,6 +237,9 @@ test_srcs := \
|
|
|
228
237
|
sq-poll-share.c \
|
|
229
238
|
sqpoll-sleep.c \
|
|
230
239
|
sq-space_left.c \
|
|
240
|
+
sqe-mixed-nop.c \
|
|
241
|
+
sqe-mixed-bad-wrap.c \
|
|
242
|
+
sqe-mixed-uring_cmd.c \
|
|
231
243
|
sqwait.c \
|
|
232
244
|
stdout.c \
|
|
233
245
|
submit-and-wait.c \
|
|
@@ -253,6 +265,8 @@ test_srcs := \
|
|
|
253
265
|
zcrx.c \
|
|
254
266
|
vec-regbuf.c \
|
|
255
267
|
timestamp.c \
|
|
268
|
+
ring-query.c \
|
|
269
|
+
mock_file.c \
|
|
256
270
|
# EOL
|
|
257
271
|
|
|
258
272
|
# Please keep this list sorted alphabetically.
|
|
@@ -218,23 +218,12 @@ static int set_client_fd(struct sockaddr_in *addr)
|
|
|
218
218
|
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
|
219
219
|
assert(ret != -1);
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
assert(flags != -1);
|
|
223
|
-
|
|
224
|
-
flags |= O_NONBLOCK;
|
|
225
|
-
ret = fcntl(fd, F_SETFL, flags);
|
|
226
|
-
assert(ret != -1);
|
|
221
|
+
t_set_nonblock(fd);
|
|
227
222
|
|
|
228
223
|
ret = connect(fd, (struct sockaddr *)addr, sizeof(*addr));
|
|
229
224
|
assert(ret == -1);
|
|
230
225
|
|
|
231
|
-
|
|
232
|
-
assert(flags != -1);
|
|
233
|
-
|
|
234
|
-
flags &= ~O_NONBLOCK;
|
|
235
|
-
ret = fcntl(fd, F_SETFL, flags);
|
|
236
|
-
assert(ret != -1);
|
|
237
|
-
|
|
226
|
+
t_clear_nonblock(fd);
|
|
238
227
|
return fd;
|
|
239
228
|
}
|
|
240
229
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
|
2
|
+
/*
|
|
3
|
+
* Check that IORING_OP_CONNECT properly returns -ECONNRESET when
|
|
4
|
+
* attempting to connect to an unreachable address. See:
|
|
5
|
+
*
|
|
6
|
+
* https://github.com/axboe/liburing/discussions/1335
|
|
7
|
+
*/
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
#include <assert.h>
|
|
13
|
+
|
|
14
|
+
#include <errno.h>
|
|
15
|
+
#include <fcntl.h>
|
|
16
|
+
#include <unistd.h>
|
|
17
|
+
#include <sys/socket.h>
|
|
18
|
+
#include <sys/un.h>
|
|
19
|
+
#include <netinet/tcp.h>
|
|
20
|
+
#include <netinet/in.h>
|
|
21
|
+
#include <arpa/inet.h>
|
|
22
|
+
|
|
23
|
+
#include "liburing.h"
|
|
24
|
+
#include "helpers.h"
|
|
25
|
+
|
|
26
|
+
static int check_cqe(struct io_uring *ring, struct io_uring_cqe *cqe)
|
|
27
|
+
{
|
|
28
|
+
if (cqe->res == -EINVAL)
|
|
29
|
+
return T_EXIT_SKIP;
|
|
30
|
+
|
|
31
|
+
switch (cqe->user_data) {
|
|
32
|
+
case 1:
|
|
33
|
+
if (cqe->res != -ECONNRESET) {
|
|
34
|
+
fprintf(stderr, "Unexpected connect: %d\n", cqe->res);
|
|
35
|
+
return T_EXIT_FAIL;
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case 2:
|
|
39
|
+
if (cqe->res) {
|
|
40
|
+
fprintf(stderr, "Unexpected shutdown: %d\n", cqe->res);
|
|
41
|
+
return T_EXIT_FAIL;
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
io_uring_cqe_seen(ring, cqe);
|
|
46
|
+
return T_EXIT_PASS;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static int test(struct io_uring *ring, struct sockaddr_in *saddr, int p_fd)
|
|
50
|
+
{
|
|
51
|
+
struct io_uring_cqe *cqe;
|
|
52
|
+
struct io_uring_sqe *sqe1, *sqe2;
|
|
53
|
+
socklen_t val_len;
|
|
54
|
+
int ret, val;
|
|
55
|
+
|
|
56
|
+
sqe1 = io_uring_get_sqe(ring);
|
|
57
|
+
io_uring_prep_connect(sqe1, p_fd, (struct sockaddr *)saddr, sizeof(*saddr));
|
|
58
|
+
sqe1->user_data = 1;
|
|
59
|
+
|
|
60
|
+
ret = io_uring_submit(ring);
|
|
61
|
+
assert(ret != -1);
|
|
62
|
+
|
|
63
|
+
usleep(200000); // 200ms
|
|
64
|
+
sqe2 = io_uring_get_sqe(ring);
|
|
65
|
+
io_uring_prep_shutdown(sqe2, p_fd, SHUT_RDWR);
|
|
66
|
+
sqe2->user_data = 2;
|
|
67
|
+
|
|
68
|
+
ret = io_uring_submit(ring);
|
|
69
|
+
assert(ret != -1);
|
|
70
|
+
|
|
71
|
+
ret = io_uring_wait_cqe(ring, &cqe);
|
|
72
|
+
if (ret < 0) {
|
|
73
|
+
fprintf(stderr, "wait: %s\n", strerror(-ret));
|
|
74
|
+
return T_EXIT_FAIL;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ret = check_cqe(ring, cqe);
|
|
78
|
+
if (ret != T_EXIT_PASS)
|
|
79
|
+
return ret;
|
|
80
|
+
|
|
81
|
+
val = 0;
|
|
82
|
+
val_len = sizeof(val);
|
|
83
|
+
ret = getsockopt(p_fd, SOL_SOCKET, SO_ERROR, &val, &val_len);
|
|
84
|
+
assert(ret != -1);
|
|
85
|
+
|
|
86
|
+
ret = io_uring_wait_cqe(ring, &cqe);
|
|
87
|
+
if (ret < 0) {
|
|
88
|
+
fprintf(stderr, "wait: %s\n", strerror(-ret));
|
|
89
|
+
return T_EXIT_FAIL;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return check_cqe(ring, cqe);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
int main(int argc, char *argv[])
|
|
96
|
+
{
|
|
97
|
+
struct sockaddr_in addr = { };
|
|
98
|
+
struct io_uring ring;
|
|
99
|
+
int val, p_fd, ret;
|
|
100
|
+
|
|
101
|
+
if (argc > 1)
|
|
102
|
+
return T_EXIT_SKIP;
|
|
103
|
+
|
|
104
|
+
p_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
|
105
|
+
|
|
106
|
+
val = 1;
|
|
107
|
+
ret = setsockopt(p_fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
|
108
|
+
assert(ret != -1);
|
|
109
|
+
|
|
110
|
+
// NB. these are to make things faster
|
|
111
|
+
val = 2;
|
|
112
|
+
ret = setsockopt(p_fd, IPPROTO_TCP, TCP_SYNCNT, &val, sizeof(val));
|
|
113
|
+
assert(ret != -1);
|
|
114
|
+
|
|
115
|
+
val = 500; // 500ms
|
|
116
|
+
ret = setsockopt(p_fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof(val));
|
|
117
|
+
assert(ret != -1);
|
|
118
|
+
|
|
119
|
+
t_set_nonblock(p_fd);
|
|
120
|
+
|
|
121
|
+
addr.sin_family = AF_INET;
|
|
122
|
+
/* any unreachable address */
|
|
123
|
+
addr.sin_addr.s_addr = inet_addr("172.31.5.5");
|
|
124
|
+
addr.sin_port = htons(12345);
|
|
125
|
+
|
|
126
|
+
ret = io_uring_queue_init(2, &ring, 0);
|
|
127
|
+
assert(ret >= 0);
|
|
128
|
+
|
|
129
|
+
ret = test(&ring, &addr, p_fd);
|
|
130
|
+
io_uring_queue_exit(&ring);
|
|
131
|
+
return ret;
|
|
132
|
+
}
|
|
@@ -50,14 +50,15 @@ static int verify_fixed_read(struct io_uring *ring, int fixed_fd, int fail)
|
|
|
50
50
|
return 0;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
static int test(const char *filename, int source_fd, int target_fd
|
|
53
|
+
static int test(const char *filename, int source_fd, int target_fd,
|
|
54
|
+
unsigned int ring_flags)
|
|
54
55
|
{
|
|
55
56
|
struct io_uring sring, dring;
|
|
56
57
|
struct io_uring_sqe *sqe;
|
|
57
58
|
struct io_uring_cqe *cqe;
|
|
58
59
|
int ret;
|
|
59
60
|
|
|
60
|
-
ret = io_uring_queue_init(8, &sring,
|
|
61
|
+
ret = io_uring_queue_init(8, &sring, ring_flags);
|
|
61
62
|
if (ret) {
|
|
62
63
|
fprintf(stderr, "ring setup failed: %d\n", ret);
|
|
63
64
|
return T_EXIT_FAIL;
|
|
@@ -202,36 +203,60 @@ int main(int argc, char *argv[])
|
|
|
202
203
|
sprintf(fname, ".fd-pass.%d", getpid());
|
|
203
204
|
t_create_file_pattern(fname, FSIZE, PAT);
|
|
204
205
|
|
|
205
|
-
ret = test(fname, 0, 1);
|
|
206
|
+
ret = test(fname, 0, 1, 0);
|
|
206
207
|
if (ret == T_EXIT_FAIL) {
|
|
207
208
|
fprintf(stderr, "test failed 0 1\n");
|
|
208
209
|
ret = T_EXIT_FAIL;
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
ret = test(fname, 0, 2);
|
|
212
|
+
ret = test(fname, 0, 2, 0);
|
|
212
213
|
if (ret == T_EXIT_FAIL) {
|
|
213
214
|
fprintf(stderr, "test failed 0 2\n");
|
|
214
215
|
ret = T_EXIT_FAIL;
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
ret = test(fname, 1, 1);
|
|
218
|
+
ret = test(fname, 1, 1, 0);
|
|
218
219
|
if (ret == T_EXIT_FAIL) {
|
|
219
220
|
fprintf(stderr, "test failed 1 1\n");
|
|
220
221
|
ret = T_EXIT_FAIL;
|
|
221
222
|
}
|
|
222
223
|
|
|
223
|
-
ret = test(fname, 1, 0);
|
|
224
|
+
ret = test(fname, 1, 0, 0);
|
|
224
225
|
if (ret == T_EXIT_FAIL) {
|
|
225
226
|
fprintf(stderr, "test failed 1 0\n");
|
|
226
227
|
ret = T_EXIT_FAIL;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
ret = test(fname, 1, IORING_FILE_INDEX_ALLOC);
|
|
230
|
+
ret = test(fname, 1, IORING_FILE_INDEX_ALLOC, 0);
|
|
230
231
|
if (ret == T_EXIT_FAIL) {
|
|
231
232
|
fprintf(stderr, "test failed 1 ALLOC\n");
|
|
232
233
|
ret = T_EXIT_FAIL;
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
ret = test(fname, 0, 2, IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER);
|
|
237
|
+
if (ret == T_EXIT_FAIL) {
|
|
238
|
+
fprintf(stderr, "test failed 0 2 defer\n");
|
|
239
|
+
ret = T_EXIT_FAIL;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
ret = test(fname, 1, 1, IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER);
|
|
243
|
+
if (ret == T_EXIT_FAIL) {
|
|
244
|
+
fprintf(stderr, "test failed 1 1 defer\n");
|
|
245
|
+
ret = T_EXIT_FAIL;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
ret = test(fname, 1, 0, IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER);
|
|
249
|
+
if (ret == T_EXIT_FAIL) {
|
|
250
|
+
fprintf(stderr, "test failed 1 0 defer\n");
|
|
251
|
+
ret = T_EXIT_FAIL;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
ret = test(fname, 1, IORING_FILE_INDEX_ALLOC, IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER);
|
|
255
|
+
if (ret == T_EXIT_FAIL) {
|
|
256
|
+
fprintf(stderr, "test failed 1 ALLOC defer\n");
|
|
257
|
+
ret = T_EXIT_FAIL;
|
|
258
|
+
}
|
|
259
|
+
|
|
235
260
|
unlink(fname);
|
|
236
261
|
return ret;
|
|
237
262
|
}
|
|
@@ -57,7 +57,7 @@ static void fdinfo_read(struct io_uring *ring)
|
|
|
57
57
|
|
|
58
58
|
static int __test_io(const char *file, struct io_uring *ring, int write,
|
|
59
59
|
int buffered, int sqthread, int fixed, int nonvec,
|
|
60
|
-
int buf_select, int seq, int exp_len)
|
|
60
|
+
int buf_select, int seq, int exp_len, int mixed)
|
|
61
61
|
{
|
|
62
62
|
struct io_uring_sqe *sqe;
|
|
63
63
|
struct io_uring_cqe *cqe;
|
|
@@ -66,9 +66,9 @@ static int __test_io(const char *file, struct io_uring *ring, int write,
|
|
|
66
66
|
off_t offset;
|
|
67
67
|
|
|
68
68
|
#ifdef VERBOSE
|
|
69
|
-
fprintf(stdout, "%s: start %d/%d/%d/%d/%d: ", __FUNCTION__, write,
|
|
69
|
+
fprintf(stdout, "%s: start %d/%d/%d/%d/%d/%d: ", __FUNCTION__, write,
|
|
70
70
|
buffered, sqthread,
|
|
71
|
-
fixed, nonvec);
|
|
71
|
+
fixed, nonvec, mixed);
|
|
72
72
|
#endif
|
|
73
73
|
if (write)
|
|
74
74
|
open_flags = O_WRONLY;
|
|
@@ -107,6 +107,17 @@ static int __test_io(const char *file, struct io_uring *ring, int write,
|
|
|
107
107
|
|
|
108
108
|
offset = 0;
|
|
109
109
|
for (i = 0; i < BUFFERS; i++) {
|
|
110
|
+
if (mixed && i & 1) {
|
|
111
|
+
sqe = io_uring_get_sqe128(ring);
|
|
112
|
+
if (!sqe) {
|
|
113
|
+
fprintf(stderr, "sqe get failed\n");
|
|
114
|
+
goto err;
|
|
115
|
+
}
|
|
116
|
+
io_uring_prep_nop128(sqe);
|
|
117
|
+
sqe->user_data = i;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
110
121
|
sqe = io_uring_get_sqe(ring);
|
|
111
122
|
if (!sqe) {
|
|
112
123
|
fprintf(stderr, "sqe get failed\n");
|
|
@@ -167,12 +178,17 @@ static int __test_io(const char *file, struct io_uring *ring, int write,
|
|
|
167
178
|
offset += BS;
|
|
168
179
|
}
|
|
169
180
|
|
|
181
|
+
__io_uring_flush_sq(ring);
|
|
170
182
|
fdinfo_read(ring);
|
|
171
183
|
|
|
172
184
|
ret = io_uring_submit(ring);
|
|
173
|
-
if (ret != BUFFERS) {
|
|
185
|
+
if (!mixed && ret != BUFFERS) {
|
|
174
186
|
fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
|
|
175
187
|
goto err;
|
|
188
|
+
} else if (mixed && ret != BUFFERS + (BUFFERS >> 1)) {
|
|
189
|
+
fprintf(stderr, "submit got %d, wanted %d\n", ret,
|
|
190
|
+
BUFFERS + (BUFFERS >> 1));
|
|
191
|
+
goto err;
|
|
176
192
|
}
|
|
177
193
|
|
|
178
194
|
for (i = 0; i < 10; i++) {
|
|
@@ -186,7 +202,13 @@ static int __test_io(const char *file, struct io_uring *ring, int write,
|
|
|
186
202
|
fprintf(stderr, "wait_cqe=%d\n", ret);
|
|
187
203
|
goto err;
|
|
188
204
|
}
|
|
189
|
-
if (cqe->
|
|
205
|
+
if (mixed && cqe->user_data & 1) {
|
|
206
|
+
if (cqe->user_data > 32) {
|
|
207
|
+
fprintf(stderr, "cqe user data %lld, max expected %d\n",
|
|
208
|
+
cqe->user_data, BUFFERS - 1);
|
|
209
|
+
goto err;
|
|
210
|
+
}
|
|
211
|
+
} else if (cqe->res == -EINVAL && nonvec) {
|
|
190
212
|
if (!warned) {
|
|
191
213
|
fprintf(stdout, "Non-vectored IO not "
|
|
192
214
|
"supported, skipping\n");
|
|
@@ -252,15 +274,19 @@ err:
|
|
|
252
274
|
return 1;
|
|
253
275
|
}
|
|
254
276
|
static int test_io(const char *file, int write, int buffered, int sqthread,
|
|
255
|
-
int fixed, int nonvec, int exp_len)
|
|
277
|
+
int fixed, int nonvec, int exp_len, int mixed)
|
|
256
278
|
{
|
|
257
279
|
struct io_uring ring;
|
|
258
|
-
int ret, ring_flags = 0;
|
|
280
|
+
int ret, ring_flags = 0, entries = 64;
|
|
259
281
|
|
|
260
282
|
if (sqthread)
|
|
261
283
|
ring_flags = IORING_SETUP_SQPOLL;
|
|
284
|
+
if (mixed) {
|
|
285
|
+
ring_flags |= IORING_SETUP_SQE_MIXED;
|
|
286
|
+
entries = 128;
|
|
287
|
+
}
|
|
262
288
|
|
|
263
|
-
ret = t_create_ring(
|
|
289
|
+
ret = t_create_ring(entries, &ring, ring_flags);
|
|
264
290
|
if (ret == T_SETUP_SKIP)
|
|
265
291
|
return 0;
|
|
266
292
|
if (ret != T_SETUP_OK) {
|
|
@@ -269,7 +295,7 @@ static int test_io(const char *file, int write, int buffered, int sqthread,
|
|
|
269
295
|
}
|
|
270
296
|
|
|
271
297
|
ret = __test_io(file, &ring, write, buffered, sqthread, fixed, nonvec,
|
|
272
|
-
0, 0, exp_len);
|
|
298
|
+
0, 0, exp_len, mixed);
|
|
273
299
|
io_uring_queue_exit(&ring);
|
|
274
300
|
return ret;
|
|
275
301
|
}
|
|
@@ -379,17 +405,18 @@ int main(int argc, char *argv[])
|
|
|
379
405
|
vecs = t_create_buffers(BUFFERS, BS);
|
|
380
406
|
|
|
381
407
|
/* if we don't have nonvec read, skip testing that */
|
|
382
|
-
nr = has_nonvec_read() ?
|
|
408
|
+
nr = has_nonvec_read() ? 64 : 32;
|
|
383
409
|
|
|
384
410
|
for (i = 0; i < nr; i++) {
|
|
385
411
|
int write = (i & 1) != 0;
|
|
386
412
|
int buffered = (i & 2) != 0;
|
|
387
413
|
int sqthread = (i & 4) != 0;
|
|
388
414
|
int fixed = (i & 8) != 0;
|
|
389
|
-
int
|
|
415
|
+
int mixed = (i & 16) != 0;
|
|
416
|
+
int nonvec = (i & 32) != 0;
|
|
390
417
|
|
|
391
418
|
ret = test_io(fname, write, buffered, sqthread, fixed, nonvec,
|
|
392
|
-
BS);
|
|
419
|
+
BS, mixed);
|
|
393
420
|
if (ret == T_EXIT_SKIP)
|
|
394
421
|
continue;
|
|
395
422
|
if (ret) {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
|
2
|
+
/*
|
|
3
|
+
* Description: Run a failing futex wait command followed up a POLL_ADD
|
|
4
|
+
* on a fifo.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <linux/futex.h>
|
|
10
|
+
#include <linux/poll.h>
|
|
11
|
+
#include <unistd.h>
|
|
12
|
+
|
|
13
|
+
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
15
|
+
|
|
16
|
+
#ifndef FUTEX2_SIZE_U32
|
|
17
|
+
#define FUTEX2_SIZE_U32 0x02
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
int main(int argc, char *argv[])
|
|
21
|
+
{
|
|
22
|
+
struct io_uring_sqe *sqe;
|
|
23
|
+
struct io_uring_cqe *cqe;
|
|
24
|
+
struct io_uring ring;
|
|
25
|
+
int ret, pipe;
|
|
26
|
+
|
|
27
|
+
if (argc > 1)
|
|
28
|
+
return T_EXIT_SKIP;
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* Setup a FIFO for polling. FIFOs are interesting because they end
|
|
32
|
+
* up using two wait queue entries for poll, hitting double poll
|
|
33
|
+
* in io_uring.
|
|
34
|
+
*/
|
|
35
|
+
ret = mkfifo("fifo", 0644);
|
|
36
|
+
if (ret < 0) {
|
|
37
|
+
perror("mkfifo");
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
pipe = open("fifo", O_RDWR);
|
|
41
|
+
if (pipe < 0) {
|
|
42
|
+
perror("open fifo");
|
|
43
|
+
ret = T_EXIT_FAIL;
|
|
44
|
+
goto err;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
ret = io_uring_queue_init(64, &ring, 0);
|
|
48
|
+
if (ret) {
|
|
49
|
+
ret = T_EXIT_FAIL;
|
|
50
|
+
goto err;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Submit invalid futex wait, will error inline.
|
|
55
|
+
*/
|
|
56
|
+
sqe = io_uring_get_sqe(&ring);
|
|
57
|
+
io_uring_prep_futex_wait(sqe, NULL, 0, FUTEX_BITSET_MATCH_ANY, FUTEX2_SIZE_U32, 0);
|
|
58
|
+
sqe->user_data = 1;
|
|
59
|
+
io_uring_submit(&ring);
|
|
60
|
+
|
|
61
|
+
ret = io_uring_wait_cqe(&ring, &cqe);
|
|
62
|
+
if (ret) {
|
|
63
|
+
fprintf(stderr, "wait %d \n", ret);
|
|
64
|
+
ret = T_EXIT_FAIL;
|
|
65
|
+
goto err_ring;
|
|
66
|
+
}
|
|
67
|
+
if (cqe->res != -EFAULT) {
|
|
68
|
+
if (cqe->res == -EINVAL) {
|
|
69
|
+
ret = T_EXIT_SKIP;
|
|
70
|
+
goto err_ring;
|
|
71
|
+
}
|
|
72
|
+
fprintf(stderr, "Unexpected futex return: %d\n", cqe->res);
|
|
73
|
+
ret = T_EXIT_FAIL;
|
|
74
|
+
goto err_ring;
|
|
75
|
+
}
|
|
76
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
77
|
+
|
|
78
|
+
ret = io_uring_register_files(&ring, &pipe, 1);
|
|
79
|
+
if (ret < 0) {
|
|
80
|
+
fprintf(stderr, "io_uring register files failed \n");
|
|
81
|
+
ret = T_EXIT_FAIL;
|
|
82
|
+
goto err_ring;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
* Submit poll request for POLLIN on the fifo
|
|
87
|
+
*/
|
|
88
|
+
sqe = io_uring_get_sqe(&ring);
|
|
89
|
+
io_uring_prep_poll_add(sqe, 0, POLLIN);
|
|
90
|
+
sqe->flags |= IOSQE_FIXED_FILE;
|
|
91
|
+
sqe->user_data = 2;
|
|
92
|
+
io_uring_submit(&ring);
|
|
93
|
+
|
|
94
|
+
/*
|
|
95
|
+
* Trigger the poll request
|
|
96
|
+
*/
|
|
97
|
+
ret = write(pipe, "FIFO test\n", 10);
|
|
98
|
+
if (ret < 0)
|
|
99
|
+
perror("fifo write");
|
|
100
|
+
|
|
101
|
+
ret = io_uring_wait_cqe(&ring, &cqe);
|
|
102
|
+
if (ret) {
|
|
103
|
+
fprintf(stderr, "wait %d \n", ret);
|
|
104
|
+
ret = T_EXIT_FAIL;
|
|
105
|
+
}
|
|
106
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
107
|
+
err_ring:
|
|
108
|
+
io_uring_queue_exit(&ring);
|
|
109
|
+
err:
|
|
110
|
+
if (pipe != -1)
|
|
111
|
+
close(pipe);
|
|
112
|
+
unlink("fifo");
|
|
113
|
+
return ret;
|
|
114
|
+
}
|