uringmachine 0.19.1 → 0.21.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/.github/workflows/test.yml +3 -4
- data/CHANGELOG.md +32 -1
- data/TODO.md +0 -39
- 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 +29 -29
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/bm_write.rb +4 -1
- 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 +310 -74
- data/ext/um/um.h +66 -29
- data/ext/um/um_async_op.c +1 -1
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +178 -31
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_op.c +37 -0
- 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 +28 -39
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +353 -0
- data/grant-2025/tasks.md +135 -0
- data/lib/uringmachine/fiber_scheduler.rb +316 -57
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +640 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +722 -54
- data/uringmachine.gemspec +5 -5
- 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 +51 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +458 -121
- data/vendor/liburing/src/liburing-ffi.map +16 -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/bind-listen.c +175 -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/read-write.c +4 -4
- 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/ringbuf-read.c +4 -4
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +103 -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 +37 -15
|
@@ -244,3 +244,19 @@ 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
|
+
io_uring_prep_cmd_getsockname;
|
|
262
|
+
} 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
|
|
|
@@ -22,7 +22,7 @@ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
static const char *magic = "Hello World!";
|
|
25
|
-
static
|
|
25
|
+
static bool no_getsockname = false;
|
|
26
26
|
|
|
27
27
|
enum {
|
|
28
28
|
SRV_INDEX = 0,
|
|
@@ -74,18 +74,82 @@ static int connect_client(struct io_uring *ring, unsigned short peer_port)
|
|
|
74
74
|
return T_SETUP_OK;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
/*
|
|
78
|
+
* getsockname was added to the kernel a few releases after bind/listen.
|
|
79
|
+
* In order to provide a backward-compatible test, fallback to
|
|
80
|
+
* non-io-uring if we are on an older kernel, allowing the test to
|
|
81
|
+
* continue.
|
|
82
|
+
*/
|
|
83
|
+
static int do_getsockname(struct io_uring *ring, int direct_socket,
|
|
84
|
+
int peer, struct sockaddr *saddr,
|
|
85
|
+
socklen_t *saddr_len)
|
|
86
|
+
{
|
|
87
|
+
struct io_uring_sqe *sqe;
|
|
88
|
+
struct io_uring_cqe *cqe;
|
|
89
|
+
int res = 0, fd;
|
|
90
|
+
|
|
91
|
+
if (!no_getsockname) {
|
|
92
|
+
/* attempt io_uring. Command might not exist */
|
|
93
|
+
sqe = io_uring_get_sqe(ring);
|
|
94
|
+
io_uring_prep_cmd_getsockname(sqe, direct_socket,
|
|
95
|
+
saddr, saddr_len, peer);
|
|
96
|
+
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
|
|
97
|
+
io_uring_submit(ring);
|
|
98
|
+
io_uring_wait_cqe(ring, &cqe);
|
|
99
|
+
res = cqe->res;
|
|
100
|
+
io_uring_cqe_seen(ring, cqe);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (no_getsockname || res == -ENOTSUP) {
|
|
104
|
+
/*
|
|
105
|
+
* Older kernel. install the fd and use the getsockname
|
|
106
|
+
* syscall.
|
|
107
|
+
*/
|
|
108
|
+
no_getsockname = true;
|
|
109
|
+
|
|
110
|
+
sqe = io_uring_get_sqe(ring);
|
|
111
|
+
io_uring_prep_fixed_fd_install(sqe, direct_socket, 0);
|
|
112
|
+
io_uring_submit(ring);
|
|
113
|
+
io_uring_wait_cqe(ring, &cqe);
|
|
114
|
+
fd = cqe->res;
|
|
115
|
+
io_uring_cqe_seen(ring, cqe);
|
|
116
|
+
|
|
117
|
+
if (fd < 0) {
|
|
118
|
+
fprintf(stderr, "installing direct fd failed. %d\n",
|
|
119
|
+
cqe->res);
|
|
120
|
+
return T_EXIT_FAIL;
|
|
121
|
+
}
|
|
122
|
+
if (peer)
|
|
123
|
+
res = getpeername(fd, saddr, saddr_len);
|
|
124
|
+
else
|
|
125
|
+
res = getsockname(fd, saddr, saddr_len);
|
|
126
|
+
|
|
127
|
+
if (res) {
|
|
128
|
+
fprintf(stderr, "get%sname syscall failed. %d\n",
|
|
129
|
+
peer? "peer":"sock", errno);
|
|
130
|
+
return T_EXIT_FAIL;
|
|
131
|
+
}
|
|
132
|
+
close(fd);
|
|
133
|
+
} else if (res < 0) {
|
|
134
|
+
fprintf(stderr, "getsockname server failed. %d\n", cqe->res);
|
|
135
|
+
return T_EXIT_FAIL;
|
|
136
|
+
}
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static int setup_srv(struct io_uring *ring)
|
|
78
141
|
{
|
|
142
|
+
struct sockaddr_in server_addr;
|
|
79
143
|
struct io_uring_sqe *sqe;
|
|
80
144
|
struct io_uring_cqe *cqe;
|
|
81
145
|
struct __kernel_timespec ts;
|
|
82
146
|
int ret, val, submitted;
|
|
83
147
|
unsigned head;
|
|
84
148
|
|
|
85
|
-
memset(server_addr, 0, sizeof(struct sockaddr_in));
|
|
86
|
-
server_addr
|
|
87
|
-
server_addr
|
|
88
|
-
server_addr
|
|
149
|
+
memset(&server_addr, 0, sizeof(struct sockaddr_in));
|
|
150
|
+
server_addr.sin_family = AF_INET;
|
|
151
|
+
server_addr.sin_port = htons(0);
|
|
152
|
+
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
|
|
89
153
|
|
|
90
154
|
sqe = io_uring_get_sqe(ring);
|
|
91
155
|
io_uring_prep_socket_direct(sqe, AF_INET, SOCK_STREAM, 0, SRV_INDEX, 0);
|
|
@@ -98,7 +162,7 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
|
|
|
98
162
|
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
|
|
99
163
|
|
|
100
164
|
sqe = io_uring_get_sqe(ring);
|
|
101
|
-
io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) server_addr,
|
|
165
|
+
io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) &server_addr,
|
|
102
166
|
sizeof(struct sockaddr_in));
|
|
103
167
|
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
|
|
104
168
|
|
|
@@ -132,12 +196,13 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
|
|
|
132
196
|
|
|
133
197
|
static int test_good_server(unsigned int ring_flags)
|
|
134
198
|
{
|
|
135
|
-
struct sockaddr_in
|
|
199
|
+
struct sockaddr_in saddr = {};
|
|
200
|
+
socklen_t saddr_len = sizeof(saddr);
|
|
136
201
|
struct __kernel_timespec ts;
|
|
137
202
|
struct io_uring_sqe *sqe;
|
|
138
203
|
struct io_uring_cqe *cqe;
|
|
139
204
|
struct io_uring ring;
|
|
140
|
-
int ret;
|
|
205
|
+
int ret, port;
|
|
141
206
|
int fds[3];
|
|
142
207
|
char buf[1024];
|
|
143
208
|
|
|
@@ -155,18 +220,22 @@ static int test_good_server(unsigned int ring_flags)
|
|
|
155
220
|
return T_SETUP_SKIP;
|
|
156
221
|
}
|
|
157
222
|
|
|
158
|
-
ret = setup_srv(&ring
|
|
223
|
+
ret = setup_srv(&ring);
|
|
159
224
|
if (ret != T_SETUP_OK) {
|
|
160
225
|
fprintf(stderr, "srv startup failed.\n");
|
|
161
226
|
return T_EXIT_FAIL;
|
|
162
227
|
}
|
|
163
228
|
|
|
164
|
-
if (
|
|
229
|
+
if (do_getsockname(&ring, SRV_INDEX, 0, (struct sockaddr*) &saddr,
|
|
230
|
+
&saddr_len))
|
|
231
|
+
return T_EXIT_FAIL;
|
|
232
|
+
|
|
233
|
+
if (connect_client(&ring, saddr.sin_port) != T_SETUP_OK) {
|
|
165
234
|
fprintf(stderr, "cli startup failed.\n");
|
|
166
235
|
return T_SETUP_SKIP;
|
|
167
236
|
}
|
|
168
237
|
|
|
169
|
-
/* Wait for a
|
|
238
|
+
/* Wait for a connection */
|
|
170
239
|
sqe = io_uring_get_sqe(&ring);
|
|
171
240
|
io_uring_prep_accept_direct(sqe, SRV_INDEX, NULL, NULL, 0, CONN_INDEX);
|
|
172
241
|
sqe->flags |= IOSQE_FIXED_FILE;
|
|
@@ -179,6 +248,22 @@ static int test_good_server(unsigned int ring_flags)
|
|
|
179
248
|
}
|
|
180
249
|
io_uring_cqe_seen(&ring, cqe);
|
|
181
250
|
|
|
251
|
+
/* Test that getsockname on the peer (getpeername) yields a
|
|
252
|
+
* sane result.
|
|
253
|
+
*/
|
|
254
|
+
port = saddr.sin_port;
|
|
255
|
+
saddr.sin_port = 0;
|
|
256
|
+
if (do_getsockname(&ring, CLI_INDEX, 1,
|
|
257
|
+
(struct sockaddr*)&saddr, &saddr_len))
|
|
258
|
+
return T_EXIT_FAIL;
|
|
259
|
+
|
|
260
|
+
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) ||
|
|
261
|
+
saddr.sin_port != port) {
|
|
262
|
+
fprintf(stderr, "getsockname peer got wrong address: %s:%d\n",
|
|
263
|
+
inet_ntoa(saddr.sin_addr), saddr.sin_port);
|
|
264
|
+
return T_EXIT_FAIL;
|
|
265
|
+
}
|
|
266
|
+
|
|
182
267
|
sqe = io_uring_get_sqe(&ring);
|
|
183
268
|
io_uring_prep_recv(sqe, CONN_INDEX, buf, sizeof(buf), 0);
|
|
184
269
|
sqe->flags |= IOSQE_FIXED_FILE;
|
|
@@ -355,6 +440,77 @@ fail:
|
|
|
355
440
|
return ret;
|
|
356
441
|
}
|
|
357
442
|
|
|
443
|
+
static int test_bad_sockname(void)
|
|
444
|
+
{
|
|
445
|
+
struct sockaddr_in saddr;
|
|
446
|
+
socklen_t saddr_len;
|
|
447
|
+
struct io_uring_sqe *sqe;
|
|
448
|
+
struct io_uring_cqe *cqe;
|
|
449
|
+
struct io_uring ring;
|
|
450
|
+
int sock = -1, err;
|
|
451
|
+
int ret = T_EXIT_FAIL;
|
|
452
|
+
|
|
453
|
+
memset(&saddr, 0, sizeof(struct sockaddr_in));
|
|
454
|
+
saddr.sin_family = AF_INET;
|
|
455
|
+
saddr.sin_port = htons(8001);
|
|
456
|
+
saddr.sin_addr.s_addr = htons(INADDR_ANY);
|
|
457
|
+
|
|
458
|
+
err = t_create_ring(1, &ring, 0);
|
|
459
|
+
if (err < 0) {
|
|
460
|
+
fprintf(stderr, "queue_init: %d\n", err);
|
|
461
|
+
return T_SETUP_SKIP;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
465
|
+
if (sock < 0) {
|
|
466
|
+
perror("socket");
|
|
467
|
+
goto fail;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
err = t_bind_ephemeral_port(sock, &saddr);
|
|
471
|
+
if (err) {
|
|
472
|
+
fprintf(stderr, "bind: %s\n", strerror(-err));
|
|
473
|
+
goto fail;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* getsockname on a !socket fd. with getsockname(2), this would
|
|
477
|
+
* return -ENOTSOCK, but we can't do it in an io_uring_cmd.
|
|
478
|
+
*/
|
|
479
|
+
sqe = io_uring_get_sqe(&ring);
|
|
480
|
+
saddr_len = sizeof(saddr);
|
|
481
|
+
io_uring_prep_cmd_getsockname(sqe, 1, (struct sockaddr*)&saddr, &saddr_len, 0);
|
|
482
|
+
err = io_uring_submit(&ring);
|
|
483
|
+
if (err < 0)
|
|
484
|
+
goto fail;
|
|
485
|
+
err = io_uring_wait_cqe(&ring, &cqe);
|
|
486
|
+
if (err)
|
|
487
|
+
goto fail;
|
|
488
|
+
if (cqe->res != -ENOTSUP)
|
|
489
|
+
goto fail;
|
|
490
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
491
|
+
|
|
492
|
+
/* getsockname with weird parameters */
|
|
493
|
+
sqe = io_uring_get_sqe(&ring);
|
|
494
|
+
io_uring_prep_cmd_getsockname(sqe, sock, (struct sockaddr*)&saddr,
|
|
495
|
+
&saddr_len, 3);
|
|
496
|
+
err = io_uring_submit(&ring);
|
|
497
|
+
if (err < 0)
|
|
498
|
+
goto fail;
|
|
499
|
+
err = io_uring_wait_cqe(&ring, &cqe);
|
|
500
|
+
if (err)
|
|
501
|
+
goto fail;
|
|
502
|
+
if (cqe->res != -EINVAL)
|
|
503
|
+
goto fail;
|
|
504
|
+
io_uring_cqe_seen(&ring, cqe);
|
|
505
|
+
|
|
506
|
+
ret = T_EXIT_PASS;
|
|
507
|
+
fail:
|
|
508
|
+
io_uring_queue_exit(&ring);
|
|
509
|
+
if (sock != -1)
|
|
510
|
+
close(sock);
|
|
511
|
+
return ret;
|
|
512
|
+
}
|
|
513
|
+
|
|
358
514
|
int main(int argc, char *argv[])
|
|
359
515
|
{
|
|
360
516
|
struct io_uring_probe *probe;
|
|
@@ -403,6 +559,12 @@ int main(int argc, char *argv[])
|
|
|
403
559
|
fprintf(stderr, "bad listen failed\n");
|
|
404
560
|
return T_EXIT_FAIL;
|
|
405
561
|
}
|
|
406
|
-
|
|
562
|
+
if (!no_getsockname) {
|
|
563
|
+
ret = test_bad_sockname();
|
|
564
|
+
if (ret) {
|
|
565
|
+
fprintf(stderr, "bad sockname failed\n");
|
|
566
|
+
return T_EXIT_FAIL;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
407
569
|
return T_EXIT_PASS;
|
|
408
570
|
}
|
|
@@ -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
|
}
|