polyphony 1.5 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/TODO.md +0 -4
- data/ext/polyphony/backend_io_uring.c +34 -1
- data/ext/polyphony/backend_io_uring_context.c +24 -18
- data/ext/polyphony/backend_io_uring_context.h +4 -2
- data/ext/polyphony/backend_libev.c +4 -7
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +20 -18
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -0
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +1 -0
- data/ext/polyphony/thread.c +63 -0
- data/lib/polyphony/adapters/open3.rb +190 -0
- data/lib/polyphony/core/sync.rb +83 -13
- data/lib/polyphony/core/timer.rb +7 -25
- data/lib/polyphony/extensions/exception.rb +15 -0
- data/lib/polyphony/extensions/fiber.rb +14 -13
- data/lib/polyphony/extensions/io.rb +56 -14
- data/lib/polyphony/extensions/kernel.rb +1 -1
- data/lib/polyphony/extensions/object.rb +1 -13
- data/lib/polyphony/extensions/process.rb +76 -1
- data/lib/polyphony/extensions/thread.rb +19 -27
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +11 -5
- data/test/helper.rb +46 -4
- data/test/open3/envutil.rb +380 -0
- data/test/open3/find_executable.rb +24 -0
- data/test/stress.rb +11 -7
- data/test/test_backend.rb +7 -2
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +2 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +13 -12
- data/test/test_io.rb +39 -0
- data/test/test_kernel.rb +2 -2
- data/test/test_monitor.rb +356 -0
- data/test/test_open3.rb +338 -0
- data/test/test_signal.rb +5 -1
- data/test/test_socket.rb +6 -3
- data/test/test_sync.rb +46 -0
- data/test/test_thread.rb +10 -1
- data/test/test_thread_pool.rb +5 -0
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +8 -2
- data/test/test_trace.rb +2 -0
- data/vendor/liburing/.github/workflows/build.yml +8 -0
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +8 -0
- data/vendor/liburing/configure +17 -25
- data/vendor/liburing/debian/liburing-dev.manpages +2 -0
- data/vendor/liburing/debian/rules +2 -1
- data/vendor/liburing/examples/Makefile +2 -1
- data/vendor/liburing/examples/io_uring-udp.c +11 -3
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/make-debs.sh +4 -2
- data/vendor/liburing/src/Makefile +5 -5
- data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
- data/vendor/liburing/src/include/liburing.h +86 -11
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/liburing-ffi.map +12 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/register.c +7 -2
- data/vendor/liburing/src/setup.c +373 -81
- data/vendor/liburing/test/232c93d07b74.c +3 -3
- data/vendor/liburing/test/Makefile +10 -3
- data/vendor/liburing/test/accept.c +2 -1
- data/vendor/liburing/test/buf-ring.c +35 -75
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/coredump.c +59 -0
- data/vendor/liburing/test/fallocate.c +9 -0
- data/vendor/liburing/test/fd-pass.c +34 -3
- data/vendor/liburing/test/file-verify.c +27 -6
- data/vendor/liburing/test/helpers.c +3 -1
- data/vendor/liburing/test/io_uring_register.c +25 -28
- data/vendor/liburing/test/io_uring_setup.c +1 -1
- data/vendor/liburing/test/poll-cancel-all.c +29 -5
- data/vendor/liburing/test/poll-race-mshot.c +6 -22
- data/vendor/liburing/test/read-write.c +53 -0
- data/vendor/liburing/test/recv-msgall.c +21 -23
- data/vendor/liburing/test/reg-fd-only.c +55 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/ringbuf-read.c +2 -10
- data/vendor/liburing/test/send_recvmsg.c +5 -16
- data/vendor/liburing/test/shutdown.c +2 -1
- data/vendor/liburing/test/socket-io-cmd.c +215 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -1
- data/vendor/liburing/test/socket-rw-offset.c +2 -1
- data/vendor/liburing/test/socket-rw.c +2 -1
- data/vendor/liburing/test/timeout.c +276 -0
- data/vendor/liburing/test/xattr.c +38 -25
- metadata +14 -3
- data/vendor/liburing/test/timeout-overflow.c +0 -204
@@ -20,11 +20,11 @@ static int pagesize;
|
|
20
20
|
/* test trying to register classic group when ring group exists */
|
21
21
|
static int test_mixed_reg2(int bgid)
|
22
22
|
{
|
23
|
-
struct
|
23
|
+
struct io_uring_buf_ring *br;
|
24
24
|
struct io_uring_sqe *sqe;
|
25
25
|
struct io_uring_cqe *cqe;
|
26
26
|
struct io_uring ring;
|
27
|
-
void *
|
27
|
+
void *bufs;
|
28
28
|
int ret;
|
29
29
|
|
30
30
|
ret = t_create_ring(1, &ring, 0);
|
@@ -33,15 +33,8 @@ static int test_mixed_reg2(int bgid)
|
|
33
33
|
else if (ret != T_SETUP_OK)
|
34
34
|
return 1;
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
reg.ring_addr = (unsigned long) ptr;
|
40
|
-
reg.ring_entries = 32;
|
41
|
-
reg.bgid = bgid;
|
42
|
-
|
43
|
-
ret = io_uring_register_buf_ring(&ring, ®, 0);
|
44
|
-
if (ret) {
|
36
|
+
br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
|
37
|
+
if (!br) {
|
45
38
|
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
46
39
|
return 1;
|
47
40
|
}
|
@@ -62,6 +55,7 @@ static int test_mixed_reg2(int bgid)
|
|
62
55
|
}
|
63
56
|
io_uring_cqe_seen(&ring, cqe);
|
64
57
|
|
58
|
+
io_uring_free_buf_ring(&ring, br, 32, bgid);
|
65
59
|
io_uring_queue_exit(&ring);
|
66
60
|
return 0;
|
67
61
|
}
|
@@ -69,11 +63,11 @@ static int test_mixed_reg2(int bgid)
|
|
69
63
|
/* test trying to register ring group when classic group exists */
|
70
64
|
static int test_mixed_reg(int bgid)
|
71
65
|
{
|
72
|
-
struct
|
66
|
+
struct io_uring_buf_ring *br;
|
73
67
|
struct io_uring_sqe *sqe;
|
74
68
|
struct io_uring_cqe *cqe;
|
75
69
|
struct io_uring ring;
|
76
|
-
void *
|
70
|
+
void *bufs;
|
77
71
|
int ret;
|
78
72
|
|
79
73
|
ret = t_create_ring(1, &ring, 0);
|
@@ -98,16 +92,9 @@ static int test_mixed_reg(int bgid)
|
|
98
92
|
}
|
99
93
|
io_uring_cqe_seen(&ring, cqe);
|
100
94
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
reg.ring_addr = (unsigned long) ptr;
|
105
|
-
reg.ring_entries = 32;
|
106
|
-
reg.bgid = bgid;
|
107
|
-
|
108
|
-
ret = io_uring_register_buf_ring(&ring, ®, 0);
|
109
|
-
if (ret != -EEXIST) {
|
110
|
-
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
95
|
+
br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
|
96
|
+
if (br) {
|
97
|
+
fprintf(stderr, "Buffer ring setup succeeded unexpectedly %d\n", ret);
|
111
98
|
return 1;
|
112
99
|
}
|
113
100
|
|
@@ -118,8 +105,8 @@ static int test_mixed_reg(int bgid)
|
|
118
105
|
static int test_double_reg_unreg(int bgid)
|
119
106
|
{
|
120
107
|
struct io_uring_buf_reg reg = { };
|
108
|
+
struct io_uring_buf_ring *br;
|
121
109
|
struct io_uring ring;
|
122
|
-
void *ptr;
|
123
110
|
int ret;
|
124
111
|
|
125
112
|
ret = t_create_ring(1, &ring, 0);
|
@@ -128,21 +115,14 @@ static int test_double_reg_unreg(int bgid)
|
|
128
115
|
else if (ret != T_SETUP_OK)
|
129
116
|
return 1;
|
130
117
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
reg.ring_addr = (unsigned long) ptr;
|
135
|
-
reg.ring_entries = 32;
|
136
|
-
reg.bgid = bgid;
|
137
|
-
|
138
|
-
ret = io_uring_register_buf_ring(&ring, ®, 0);
|
139
|
-
if (ret) {
|
118
|
+
br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
|
119
|
+
if (!br) {
|
140
120
|
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
141
121
|
return 1;
|
142
122
|
}
|
143
123
|
|
144
124
|
/* check that 2nd register with same bgid fails */
|
145
|
-
reg.ring_addr = (unsigned long)
|
125
|
+
reg.ring_addr = (unsigned long) br;
|
146
126
|
reg.ring_entries = 32;
|
147
127
|
reg.bgid = bgid;
|
148
128
|
|
@@ -152,7 +132,7 @@ static int test_double_reg_unreg(int bgid)
|
|
152
132
|
return 1;
|
153
133
|
}
|
154
134
|
|
155
|
-
ret =
|
135
|
+
ret = io_uring_free_buf_ring(&ring, br, 32, bgid);
|
156
136
|
if (ret) {
|
157
137
|
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
158
138
|
return 1;
|
@@ -170,9 +150,8 @@ static int test_double_reg_unreg(int bgid)
|
|
170
150
|
|
171
151
|
static int test_reg_unreg(int bgid)
|
172
152
|
{
|
173
|
-
struct
|
153
|
+
struct io_uring_buf_ring *br;
|
174
154
|
struct io_uring ring;
|
175
|
-
void *ptr;
|
176
155
|
int ret;
|
177
156
|
|
178
157
|
ret = t_create_ring(1, &ring, 0);
|
@@ -181,15 +160,8 @@ static int test_reg_unreg(int bgid)
|
|
181
160
|
else if (ret != T_SETUP_OK)
|
182
161
|
return 1;
|
183
162
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
reg.ring_addr = (unsigned long) ptr;
|
188
|
-
reg.ring_entries = 32;
|
189
|
-
reg.bgid = bgid;
|
190
|
-
|
191
|
-
ret = io_uring_register_buf_ring(&ring, ®, 0);
|
192
|
-
if (ret) {
|
163
|
+
br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
|
164
|
+
if (!br) {
|
193
165
|
if (ret == -EINVAL) {
|
194
166
|
no_buf_ring = 1;
|
195
167
|
return 0;
|
@@ -198,9 +170,9 @@ static int test_reg_unreg(int bgid)
|
|
198
170
|
return 1;
|
199
171
|
}
|
200
172
|
|
201
|
-
ret =
|
173
|
+
ret = io_uring_free_buf_ring(&ring, br, 32, bgid);
|
202
174
|
if (ret) {
|
203
|
-
fprintf(stderr, "Buffer ring
|
175
|
+
fprintf(stderr, "Buffer ring unregister failed %d\n", ret);
|
204
176
|
return 1;
|
205
177
|
}
|
206
178
|
|
@@ -234,6 +206,9 @@ static int test_bad_reg(int bgid)
|
|
234
206
|
|
235
207
|
static int test_full_page_reg(int bgid)
|
236
208
|
{
|
209
|
+
#if defined(__hppa__)
|
210
|
+
return T_EXIT_SKIP;
|
211
|
+
#else
|
237
212
|
struct io_uring ring;
|
238
213
|
int ret;
|
239
214
|
void *ptr;
|
@@ -243,7 +218,7 @@ static int test_full_page_reg(int bgid)
|
|
243
218
|
ret = io_uring_queue_init(1, &ring, 0);
|
244
219
|
if (ret) {
|
245
220
|
fprintf(stderr, "queue init failed %d\n", ret);
|
246
|
-
return
|
221
|
+
return T_EXIT_FAIL;
|
247
222
|
}
|
248
223
|
|
249
224
|
ret = posix_memalign(&ptr, pagesize, pagesize * 2);
|
@@ -273,7 +248,8 @@ err1:
|
|
273
248
|
free(ptr);
|
274
249
|
err:
|
275
250
|
io_uring_queue_exit(&ring);
|
276
|
-
return ret;
|
251
|
+
return ret ? T_EXIT_FAIL : T_EXIT_PASS;
|
252
|
+
#endif
|
277
253
|
}
|
278
254
|
|
279
255
|
static int test_one_read(int fd, int bgid, struct io_uring *ring)
|
@@ -318,18 +294,12 @@ static int test_one_read(int fd, int bgid, struct io_uring *ring)
|
|
318
294
|
|
319
295
|
static int test_running(int bgid, int entries, int loops)
|
320
296
|
{
|
321
|
-
|
297
|
+
int ring_mask = io_uring_buf_ring_mask(entries);
|
298
|
+
struct io_uring_buf_ring *br;
|
299
|
+
int ret, loop, idx, read_fd;
|
322
300
|
struct io_uring ring;
|
323
|
-
void *ptr;
|
324
301
|
char buffer[8];
|
325
|
-
int ret;
|
326
|
-
int ring_size = (entries * sizeof(struct io_uring_buf) + 4095) & (~4095);
|
327
|
-
int ring_mask = io_uring_buf_ring_mask(entries);
|
328
|
-
|
329
|
-
int loop, idx;
|
330
302
|
bool *buffers;
|
331
|
-
struct io_uring_buf_ring *br;
|
332
|
-
int read_fd;
|
333
303
|
|
334
304
|
ret = t_create_ring(1, &ring, 0);
|
335
305
|
if (ret == T_SETUP_SKIP)
|
@@ -337,11 +307,12 @@ static int test_running(int bgid, int entries, int loops)
|
|
337
307
|
else if (ret != T_SETUP_OK)
|
338
308
|
return 1;
|
339
309
|
|
340
|
-
|
310
|
+
br = io_uring_setup_buf_ring(&ring, entries, bgid, 0, &ret);
|
311
|
+
if (!br) {
|
312
|
+
/* by now should have checked if this is supported or not */
|
313
|
+
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
341
314
|
return 1;
|
342
|
-
|
343
|
-
br = (struct io_uring_buf_ring *)ptr;
|
344
|
-
io_uring_buf_ring_init(br);
|
315
|
+
}
|
345
316
|
|
346
317
|
buffers = malloc(sizeof(bool) * entries);
|
347
318
|
if (!buffers)
|
@@ -351,17 +322,6 @@ static int test_running(int bgid, int entries, int loops)
|
|
351
322
|
if (read_fd < 0)
|
352
323
|
return 1;
|
353
324
|
|
354
|
-
reg.ring_addr = (unsigned long) ptr;
|
355
|
-
reg.ring_entries = entries;
|
356
|
-
reg.bgid = bgid;
|
357
|
-
|
358
|
-
ret = io_uring_register_buf_ring(&ring, ®, 0);
|
359
|
-
if (ret) {
|
360
|
-
/* by now should have checked if this is supported or not */
|
361
|
-
fprintf(stderr, "Buffer ring register failed %d\n", ret);
|
362
|
-
return 1;
|
363
|
-
}
|
364
|
-
|
365
325
|
for (loop = 0; loop < loops; loop++) {
|
366
326
|
memset(buffers, 0, sizeof(bool) * entries);
|
367
327
|
for (idx = 0; idx < entries; idx++)
|
@@ -456,7 +416,7 @@ int main(int argc, char *argv[])
|
|
456
416
|
}
|
457
417
|
|
458
418
|
ret = test_full_page_reg(bgids[i]);
|
459
|
-
if (ret) {
|
419
|
+
if (ret == T_EXIT_FAIL) {
|
460
420
|
fprintf(stderr, "test_full_page_reg failed\n");
|
461
421
|
return T_EXIT_FAIL;
|
462
422
|
}
|
@@ -0,0 +1,204 @@
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
2
|
+
/*
|
3
|
+
* Check that repeated IORING_OP_CONNECT to a socket without a listener keeps
|
4
|
+
* yielding -ECONNREFUSED rather than -ECONNABORTED. Based on a reproducer
|
5
|
+
* from:
|
6
|
+
*
|
7
|
+
* https://github.com/axboe/liburing/issues/828
|
8
|
+
*
|
9
|
+
* and adopted to our usual test cases. Other changes made like looping,
|
10
|
+
* using different ring types, adding a memset() for reuse, etc.
|
11
|
+
*
|
12
|
+
*/
|
13
|
+
#include <stdio.h>
|
14
|
+
#include <netinet/in.h>
|
15
|
+
#include <string.h>
|
16
|
+
#include <unistd.h>
|
17
|
+
#include <stdlib.h>
|
18
|
+
#include <arpa/inet.h>
|
19
|
+
|
20
|
+
#include "liburing.h"
|
21
|
+
#include "helpers.h"
|
22
|
+
|
23
|
+
static unsigned long ud;
|
24
|
+
|
25
|
+
static int init_test_server(struct sockaddr_in *serv_addr)
|
26
|
+
{
|
27
|
+
socklen_t servaddr_len = sizeof(struct sockaddr_in);
|
28
|
+
int fd;
|
29
|
+
|
30
|
+
/* Init server socket. Bind but don't listen */
|
31
|
+
fd = socket(AF_INET, SOCK_STREAM, 0);
|
32
|
+
if (fd < 0) {
|
33
|
+
perror("socket");
|
34
|
+
return -1;
|
35
|
+
}
|
36
|
+
|
37
|
+
serv_addr->sin_family = AF_INET;
|
38
|
+
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1");
|
39
|
+
|
40
|
+
if (bind(fd, (struct sockaddr *) serv_addr, servaddr_len) < 0) {
|
41
|
+
perror("bind");
|
42
|
+
return -1;
|
43
|
+
}
|
44
|
+
|
45
|
+
/*
|
46
|
+
* Get the addresses the socket is bound to because the port is chosen
|
47
|
+
* by the network stack.
|
48
|
+
*/
|
49
|
+
if (getsockname(fd, (struct sockaddr *)serv_addr, &servaddr_len) < 0) {
|
50
|
+
perror("getsockname");
|
51
|
+
return -1;
|
52
|
+
}
|
53
|
+
|
54
|
+
return fd;
|
55
|
+
}
|
56
|
+
|
57
|
+
static int init_test_client(void)
|
58
|
+
{
|
59
|
+
socklen_t addr_len = sizeof(struct sockaddr_in);
|
60
|
+
struct sockaddr_in client_addr = {};
|
61
|
+
int clientfd;
|
62
|
+
|
63
|
+
clientfd = socket(AF_INET, SOCK_STREAM, 0);
|
64
|
+
if (clientfd < 0) {
|
65
|
+
perror("socket");
|
66
|
+
return -1;
|
67
|
+
}
|
68
|
+
|
69
|
+
client_addr.sin_family = AF_INET;
|
70
|
+
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
71
|
+
|
72
|
+
if (bind(clientfd, (struct sockaddr *)&client_addr, addr_len) < 0) {
|
73
|
+
perror("bind");
|
74
|
+
close(clientfd);
|
75
|
+
return -1;
|
76
|
+
}
|
77
|
+
|
78
|
+
/*
|
79
|
+
* Get the addresses the socket is bound to because the port is chosen
|
80
|
+
* by the network stack.
|
81
|
+
*/
|
82
|
+
if (getsockname(clientfd, (struct sockaddr *)&client_addr, &addr_len) < 0) {
|
83
|
+
perror("getsockname");
|
84
|
+
close(clientfd);
|
85
|
+
return -1;
|
86
|
+
}
|
87
|
+
|
88
|
+
return clientfd;
|
89
|
+
}
|
90
|
+
|
91
|
+
static int get_completion_and_print(struct io_uring *ring)
|
92
|
+
{
|
93
|
+
struct io_uring_cqe *cqe;
|
94
|
+
int ret, res;
|
95
|
+
|
96
|
+
ret = io_uring_wait_cqe(ring, &cqe);
|
97
|
+
if (ret < 0) {
|
98
|
+
fprintf(stderr, "wait_cqe=%d\n", ret);
|
99
|
+
return -1;
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Mark this completion as seen */
|
103
|
+
res = cqe->res;
|
104
|
+
io_uring_cqe_seen(ring, cqe);
|
105
|
+
return res;
|
106
|
+
}
|
107
|
+
|
108
|
+
static int test_connect(struct io_uring *ring,
|
109
|
+
int clientfd, struct sockaddr_in *serv_addr)
|
110
|
+
{
|
111
|
+
struct sockaddr_in local_sa;
|
112
|
+
struct io_uring_sqe *sqe;
|
113
|
+
int ret;
|
114
|
+
|
115
|
+
sqe = io_uring_get_sqe(ring);
|
116
|
+
io_uring_prep_connect(sqe, clientfd, (const struct sockaddr *)serv_addr,
|
117
|
+
sizeof(struct sockaddr_in));
|
118
|
+
sqe->user_data = ++ud;
|
119
|
+
|
120
|
+
memcpy(&local_sa, serv_addr, sizeof(local_sa));
|
121
|
+
|
122
|
+
ret = io_uring_submit_and_wait(ring, 1);
|
123
|
+
if (ret != 1) {
|
124
|
+
fprintf(stderr, "submit=%d\n", ret);
|
125
|
+
return T_EXIT_FAIL;
|
126
|
+
}
|
127
|
+
|
128
|
+
/* check for reuse at the same time */
|
129
|
+
memset(&local_sa, 0xff, sizeof(local_sa));
|
130
|
+
|
131
|
+
ret = get_completion_and_print(ring);
|
132
|
+
if (ret != -ECONNREFUSED) {
|
133
|
+
fprintf(stderr, "Connect got %d\n", ret);
|
134
|
+
return T_EXIT_FAIL;
|
135
|
+
}
|
136
|
+
return T_EXIT_PASS;
|
137
|
+
}
|
138
|
+
|
139
|
+
static int test(int flags)
|
140
|
+
{
|
141
|
+
struct io_uring_params params = { .flags = flags, };
|
142
|
+
struct sockaddr_in serv_addr = {};
|
143
|
+
struct io_uring ring;
|
144
|
+
int ret, clientfd, s_fd, i;
|
145
|
+
|
146
|
+
if (flags & IORING_SETUP_SQPOLL)
|
147
|
+
params.sq_thread_idle = 50;
|
148
|
+
|
149
|
+
ret = io_uring_queue_init_params(8, &ring, ¶ms);
|
150
|
+
if (ret < 0) {
|
151
|
+
fprintf(stderr, "Queue init: %d\n", ret);
|
152
|
+
return T_EXIT_FAIL;
|
153
|
+
}
|
154
|
+
|
155
|
+
s_fd = init_test_server(&serv_addr);
|
156
|
+
if (s_fd < 0)
|
157
|
+
return T_EXIT_FAIL;
|
158
|
+
|
159
|
+
clientfd = init_test_client();
|
160
|
+
if (clientfd < 0) {
|
161
|
+
close(s_fd);
|
162
|
+
return T_EXIT_FAIL;
|
163
|
+
}
|
164
|
+
|
165
|
+
/* make sure SQPOLL thread is sleeping */
|
166
|
+
if (flags & IORING_SETUP_SQPOLL)
|
167
|
+
usleep(100000);
|
168
|
+
|
169
|
+
for (i = 0; i < 32; i++) {
|
170
|
+
ret = test_connect(&ring, clientfd, &serv_addr);
|
171
|
+
if (ret == T_EXIT_SKIP)
|
172
|
+
return T_EXIT_SKIP;
|
173
|
+
else if (ret == T_EXIT_PASS)
|
174
|
+
continue;
|
175
|
+
|
176
|
+
return T_EXIT_FAIL;
|
177
|
+
}
|
178
|
+
|
179
|
+
close(s_fd);
|
180
|
+
close(clientfd);
|
181
|
+
return T_EXIT_PASS;
|
182
|
+
}
|
183
|
+
|
184
|
+
int main(int argc, char *argv[])
|
185
|
+
{
|
186
|
+
int ret;
|
187
|
+
|
188
|
+
if (argc > 1)
|
189
|
+
return T_EXIT_SKIP;
|
190
|
+
|
191
|
+
ret = test(0);
|
192
|
+
if (ret == T_EXIT_FAIL) {
|
193
|
+
fprintf(stderr, "test(0) failed\n");
|
194
|
+
return T_EXIT_FAIL;
|
195
|
+
}
|
196
|
+
|
197
|
+
ret = test(IORING_SETUP_SQPOLL);
|
198
|
+
if (ret == T_EXIT_FAIL) {
|
199
|
+
fprintf(stderr, "test(SQPOLL) failed\n");
|
200
|
+
return T_EXIT_FAIL;
|
201
|
+
}
|
202
|
+
|
203
|
+
return 0;
|
204
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/* SPDX-License-Identifier: MIT */
|
2
|
+
/*
|
3
|
+
* Description: trigger segfault. A recent 6.4-rc kernel introduced a bug
|
4
|
+
* via vhost where segfaults for applications using io_uring
|
5
|
+
* would hang in D state forever upon trying to generate the
|
6
|
+
* core file. Perform a trivial test where a child process
|
7
|
+
* generates a NULL pointer dereference and ensure that we don't
|
8
|
+
* hang.
|
9
|
+
*
|
10
|
+
*/
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
#include <unistd.h>
|
14
|
+
#include <sys/wait.h>
|
15
|
+
|
16
|
+
#include "liburing.h"
|
17
|
+
#include "helpers.h"
|
18
|
+
|
19
|
+
static void test(void)
|
20
|
+
{
|
21
|
+
struct io_uring_sqe *sqe;
|
22
|
+
struct io_uring ring;
|
23
|
+
int *ptr = NULL;
|
24
|
+
int fds[2];
|
25
|
+
char r1;
|
26
|
+
|
27
|
+
if (pipe(fds) < 0) {
|
28
|
+
perror("pipe");
|
29
|
+
exit(0);
|
30
|
+
}
|
31
|
+
|
32
|
+
io_uring_queue_init(8, &ring, 0);
|
33
|
+
|
34
|
+
sqe = io_uring_get_sqe(&ring);
|
35
|
+
io_uring_prep_read(sqe, fds[0], &r1, sizeof(r1), 0);
|
36
|
+
sqe->flags = IOSQE_ASYNC;
|
37
|
+
sqe->user_data = 1;
|
38
|
+
|
39
|
+
io_uring_submit(&ring);
|
40
|
+
*ptr = 0;
|
41
|
+
exit(0);
|
42
|
+
}
|
43
|
+
|
44
|
+
int main(int argc, char *argv[])
|
45
|
+
{
|
46
|
+
pid_t pid;
|
47
|
+
int wstat;
|
48
|
+
|
49
|
+
pid = fork();
|
50
|
+
if (pid < 0) {
|
51
|
+
perror("fork");
|
52
|
+
return T_EXIT_SKIP;
|
53
|
+
} else if (!pid) {
|
54
|
+
test();
|
55
|
+
}
|
56
|
+
|
57
|
+
wait(&wstat);
|
58
|
+
return T_EXIT_PASS;
|
59
|
+
}
|
@@ -12,6 +12,7 @@
|
|
12
12
|
#include <stdlib.h>
|
13
13
|
#include <string.h>
|
14
14
|
#include <fcntl.h>
|
15
|
+
#include <signal.h>
|
15
16
|
|
16
17
|
#include "liburing.h"
|
17
18
|
#include "helpers.h"
|
@@ -216,14 +217,22 @@ err:
|
|
216
217
|
return 1;
|
217
218
|
}
|
218
219
|
|
220
|
+
static void sig_xfsz(int sig)
|
221
|
+
{
|
222
|
+
}
|
223
|
+
|
219
224
|
int main(int argc, char *argv[])
|
220
225
|
{
|
226
|
+
struct sigaction act = { };
|
221
227
|
struct io_uring ring;
|
222
228
|
int ret;
|
223
229
|
|
224
230
|
if (argc > 1)
|
225
231
|
return T_EXIT_SKIP;
|
226
232
|
|
233
|
+
act.sa_handler = sig_xfsz;
|
234
|
+
sigaction(SIGXFSZ, &act, NULL);
|
235
|
+
|
227
236
|
ret = io_uring_queue_init(8, &ring, 0);
|
228
237
|
if (ret) {
|
229
238
|
fprintf(stderr, "ring setup failed\n");
|
@@ -80,6 +80,14 @@ static int test(const char *filename, int source_fd, int target_fd)
|
|
80
80
|
fprintf(stderr, "register files failed %d\n", ret);
|
81
81
|
return T_EXIT_FAIL;
|
82
82
|
}
|
83
|
+
if (target_fd == IORING_FILE_INDEX_ALLOC) {
|
84
|
+
/* we want to test installing into a non-zero slot */
|
85
|
+
ret = io_uring_register_file_alloc_range(&dring, 1, 1);
|
86
|
+
if (ret) {
|
87
|
+
fprintf(stderr, "io_uring_register_file_alloc_range %d\n", ret);
|
88
|
+
return T_EXIT_FAIL;
|
89
|
+
}
|
90
|
+
}
|
83
91
|
|
84
92
|
/* open direct descriptor */
|
85
93
|
sqe = io_uring_get_sqe(&sring);
|
@@ -102,8 +110,14 @@ static int test(const char *filename, int source_fd, int target_fd)
|
|
102
110
|
|
103
111
|
/* send direct descriptor to destination ring */
|
104
112
|
sqe = io_uring_get_sqe(&sring);
|
105
|
-
|
106
|
-
|
113
|
+
if (target_fd == IORING_FILE_INDEX_ALLOC) {
|
114
|
+
io_uring_prep_msg_ring_fd_alloc(sqe, dring.ring_fd, source_fd,
|
115
|
+
USER_DATA, 0);
|
116
|
+
} else {
|
117
|
+
|
118
|
+
io_uring_prep_msg_ring_fd(sqe, dring.ring_fd, source_fd,
|
119
|
+
target_fd, USER_DATA, 0);
|
120
|
+
}
|
107
121
|
io_uring_submit(&sring);
|
108
122
|
|
109
123
|
ret = io_uring_wait_cqe(&sring, &cqe);
|
@@ -111,7 +125,7 @@ static int test(const char *filename, int source_fd, int target_fd)
|
|
111
125
|
fprintf(stderr, "wait cqe failed %d\n", ret);
|
112
126
|
return T_EXIT_FAIL;
|
113
127
|
}
|
114
|
-
if (cqe->res) {
|
128
|
+
if (cqe->res < 0) {
|
115
129
|
if (cqe->res == -EINVAL && !no_fd_pass) {
|
116
130
|
no_fd_pass = 1;
|
117
131
|
return T_EXIT_SKIP;
|
@@ -131,6 +145,17 @@ static int test(const char *filename, int source_fd, int target_fd)
|
|
131
145
|
fprintf(stderr, "bad user_data %ld\n", (long) cqe->res);
|
132
146
|
return T_EXIT_FAIL;
|
133
147
|
}
|
148
|
+
if (cqe->res < 0) {
|
149
|
+
fprintf(stderr, "bad result %i\n", cqe->res);
|
150
|
+
return T_EXIT_FAIL;
|
151
|
+
}
|
152
|
+
if (target_fd == IORING_FILE_INDEX_ALLOC) {
|
153
|
+
if (cqe->res != 1) {
|
154
|
+
fprintf(stderr, "invalid allocated index %i\n", cqe->res);
|
155
|
+
return T_EXIT_FAIL;
|
156
|
+
}
|
157
|
+
target_fd = cqe->res;
|
158
|
+
}
|
134
159
|
io_uring_cqe_seen(&dring, cqe);
|
135
160
|
|
136
161
|
/* now verify we can read the sane data from the destination ring */
|
@@ -201,6 +226,12 @@ int main(int argc, char *argv[])
|
|
201
226
|
ret = T_EXIT_FAIL;
|
202
227
|
}
|
203
228
|
|
229
|
+
ret = test(fname, 1, IORING_FILE_INDEX_ALLOC);
|
230
|
+
if (ret == T_EXIT_FAIL) {
|
231
|
+
fprintf(stderr, "test failed 1 ALLOC\n");
|
232
|
+
ret = T_EXIT_FAIL;
|
233
|
+
}
|
234
|
+
|
204
235
|
unlink(fname);
|
205
236
|
return ret;
|
206
237
|
}
|
@@ -32,15 +32,32 @@
|
|
32
32
|
*/
|
33
33
|
#define READ_BATCH 16
|
34
34
|
|
35
|
+
static void verify_buf_sync(void *buf, size_t size, bool registered)
|
36
|
+
{
|
37
|
+
#if defined(__hppa__)
|
38
|
+
if (registered) {
|
39
|
+
unsigned long off = (unsigned long) buf & 4095;
|
40
|
+
unsigned long p = (unsigned long) buf & ~4095;
|
41
|
+
int i;
|
42
|
+
|
43
|
+
size += off;
|
44
|
+
for (i = 0; i < size; i += 32)
|
45
|
+
asm volatile("fdc 0(%0)" : : "r" (p + i));
|
46
|
+
}
|
47
|
+
#endif
|
48
|
+
}
|
49
|
+
|
35
50
|
/*
|
36
51
|
* Each offset in the file has the offset / sizeof(int) stored for every
|
37
52
|
* sizeof(int) address.
|
38
53
|
*/
|
39
|
-
static int verify_buf(void *buf, size_t size, off_t off)
|
54
|
+
static int verify_buf(void *buf, size_t size, off_t off, bool registered)
|
40
55
|
{
|
41
56
|
int i, u_in_buf = size / sizeof(unsigned int);
|
42
57
|
unsigned int *ptr;
|
43
58
|
|
59
|
+
verify_buf_sync(buf, size, registered);
|
60
|
+
|
44
61
|
off /= sizeof(unsigned int);
|
45
62
|
ptr = buf;
|
46
63
|
for (i = 0; i < u_in_buf; i++) {
|
@@ -197,7 +214,7 @@ again:
|
|
197
214
|
goto err;
|
198
215
|
}
|
199
216
|
|
200
|
-
if (verify_buf(buf, CHUNK_SIZE / 2, 0))
|
217
|
+
if (verify_buf(buf, CHUNK_SIZE / 2, 0, false))
|
201
218
|
goto err;
|
202
219
|
|
203
220
|
/*
|
@@ -364,9 +381,12 @@ static int test(struct io_uring *ring, const char *fname, int buffered,
|
|
364
381
|
v[i].iov_base = buf[i];
|
365
382
|
v[i].iov_len = CHUNK_SIZE;
|
366
383
|
}
|
367
|
-
ret =
|
384
|
+
ret = t_register_buffers(ring, v, READ_BATCH);
|
368
385
|
if (ret) {
|
369
|
-
|
386
|
+
if (ret == T_SETUP_SKIP) {
|
387
|
+
ret = 0;
|
388
|
+
goto free_bufs;
|
389
|
+
}
|
370
390
|
goto err;
|
371
391
|
}
|
372
392
|
}
|
@@ -445,12 +465,12 @@ static int test(struct io_uring *ring, const char *fname, int buffered,
|
|
445
465
|
void *buf = vecs[index][j].iov_base;
|
446
466
|
size_t len = vecs[index][j].iov_len;
|
447
467
|
|
448
|
-
if (verify_buf(buf, len, voff))
|
468
|
+
if (verify_buf(buf, len, voff, registered))
|
449
469
|
goto err;
|
450
470
|
voff += len;
|
451
471
|
}
|
452
472
|
} else {
|
453
|
-
if (verify_buf(buf[index], CHUNK_SIZE, voff))
|
473
|
+
if (verify_buf(buf[index], CHUNK_SIZE, voff, registered))
|
454
474
|
goto err;
|
455
475
|
}
|
456
476
|
}
|
@@ -460,6 +480,7 @@ static int test(struct io_uring *ring, const char *fname, int buffered,
|
|
460
480
|
done:
|
461
481
|
if (registered)
|
462
482
|
io_uring_unregister_buffers(ring);
|
483
|
+
free_bufs:
|
463
484
|
if (vectored) {
|
464
485
|
for (j = 0; j < READ_BATCH; j++)
|
465
486
|
for (i = 0; i < nr_vecs; i++)
|
@@ -36,13 +36,15 @@ void *t_malloc(size_t size)
|
|
36
36
|
int t_bind_ephemeral_port(int fd, struct sockaddr_in *addr)
|
37
37
|
{
|
38
38
|
socklen_t addrlen;
|
39
|
+
int ret;
|
39
40
|
|
40
41
|
addr->sin_port = 0;
|
41
42
|
if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)))
|
42
43
|
return -errno;
|
43
44
|
|
44
45
|
addrlen = sizeof(*addr);
|
45
|
-
|
46
|
+
ret = getsockname(fd, (struct sockaddr *)addr, &addrlen);
|
47
|
+
assert(!ret);
|
46
48
|
assert(addr->sin_port != 0);
|
47
49
|
return 0;
|
48
50
|
}
|