polyphony 1.5 → 1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +14 -0
  4. data/TODO.md +0 -4
  5. data/ext/polyphony/backend_io_uring.c +34 -1
  6. data/ext/polyphony/backend_io_uring_context.c +24 -18
  7. data/ext/polyphony/backend_io_uring_context.h +4 -2
  8. data/ext/polyphony/backend_libev.c +4 -7
  9. data/ext/polyphony/event.c +21 -0
  10. data/ext/polyphony/extconf.rb +20 -18
  11. data/ext/polyphony/fiber.c +0 -2
  12. data/ext/polyphony/polyphony.c +2 -0
  13. data/ext/polyphony/polyphony.h +5 -0
  14. data/ext/polyphony/ring_buffer.c +1 -0
  15. data/ext/polyphony/runqueue_ring_buffer.c +1 -0
  16. data/ext/polyphony/thread.c +63 -0
  17. data/lib/polyphony/adapters/open3.rb +190 -0
  18. data/lib/polyphony/core/sync.rb +83 -13
  19. data/lib/polyphony/core/timer.rb +7 -25
  20. data/lib/polyphony/extensions/exception.rb +15 -0
  21. data/lib/polyphony/extensions/fiber.rb +14 -13
  22. data/lib/polyphony/extensions/io.rb +56 -14
  23. data/lib/polyphony/extensions/kernel.rb +1 -1
  24. data/lib/polyphony/extensions/object.rb +1 -13
  25. data/lib/polyphony/extensions/process.rb +76 -1
  26. data/lib/polyphony/extensions/thread.rb +19 -27
  27. data/lib/polyphony/version.rb +1 -1
  28. data/lib/polyphony.rb +11 -5
  29. data/test/helper.rb +46 -4
  30. data/test/open3/envutil.rb +380 -0
  31. data/test/open3/find_executable.rb +24 -0
  32. data/test/stress.rb +11 -7
  33. data/test/test_backend.rb +7 -2
  34. data/test/test_event.rb +10 -3
  35. data/test/test_ext.rb +2 -1
  36. data/test/test_fiber.rb +16 -4
  37. data/test/test_global_api.rb +13 -12
  38. data/test/test_io.rb +39 -0
  39. data/test/test_kernel.rb +2 -2
  40. data/test/test_monitor.rb +356 -0
  41. data/test/test_open3.rb +338 -0
  42. data/test/test_signal.rb +5 -1
  43. data/test/test_socket.rb +6 -3
  44. data/test/test_sync.rb +46 -0
  45. data/test/test_thread.rb +10 -1
  46. data/test/test_thread_pool.rb +5 -0
  47. data/test/test_throttler.rb +1 -1
  48. data/test/test_timer.rb +8 -2
  49. data/test/test_trace.rb +2 -0
  50. data/vendor/liburing/.github/workflows/build.yml +8 -0
  51. data/vendor/liburing/.gitignore +1 -0
  52. data/vendor/liburing/CHANGELOG +8 -0
  53. data/vendor/liburing/configure +17 -25
  54. data/vendor/liburing/debian/liburing-dev.manpages +2 -0
  55. data/vendor/liburing/debian/rules +2 -1
  56. data/vendor/liburing/examples/Makefile +2 -1
  57. data/vendor/liburing/examples/io_uring-udp.c +11 -3
  58. data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
  59. data/vendor/liburing/liburing.spec +1 -1
  60. data/vendor/liburing/make-debs.sh +4 -2
  61. data/vendor/liburing/src/Makefile +5 -5
  62. data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
  63. data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
  64. data/vendor/liburing/src/include/liburing.h +86 -11
  65. data/vendor/liburing/src/int_flags.h +1 -0
  66. data/vendor/liburing/src/liburing-ffi.map +12 -0
  67. data/vendor/liburing/src/liburing.map +8 -0
  68. data/vendor/liburing/src/register.c +7 -2
  69. data/vendor/liburing/src/setup.c +373 -81
  70. data/vendor/liburing/test/232c93d07b74.c +3 -3
  71. data/vendor/liburing/test/Makefile +10 -3
  72. data/vendor/liburing/test/accept.c +2 -1
  73. data/vendor/liburing/test/buf-ring.c +35 -75
  74. data/vendor/liburing/test/connect-rep.c +204 -0
  75. data/vendor/liburing/test/coredump.c +59 -0
  76. data/vendor/liburing/test/fallocate.c +9 -0
  77. data/vendor/liburing/test/fd-pass.c +34 -3
  78. data/vendor/liburing/test/file-verify.c +27 -6
  79. data/vendor/liburing/test/helpers.c +3 -1
  80. data/vendor/liburing/test/io_uring_register.c +25 -28
  81. data/vendor/liburing/test/io_uring_setup.c +1 -1
  82. data/vendor/liburing/test/poll-cancel-all.c +29 -5
  83. data/vendor/liburing/test/poll-race-mshot.c +6 -22
  84. data/vendor/liburing/test/read-write.c +53 -0
  85. data/vendor/liburing/test/recv-msgall.c +21 -23
  86. data/vendor/liburing/test/reg-fd-only.c +55 -0
  87. data/vendor/liburing/test/reg-hint.c +56 -0
  88. data/vendor/liburing/test/regbuf-merge.c +91 -0
  89. data/vendor/liburing/test/ringbuf-read.c +2 -10
  90. data/vendor/liburing/test/send_recvmsg.c +5 -16
  91. data/vendor/liburing/test/shutdown.c +2 -1
  92. data/vendor/liburing/test/socket-io-cmd.c +215 -0
  93. data/vendor/liburing/test/socket-rw-eagain.c +2 -1
  94. data/vendor/liburing/test/socket-rw-offset.c +2 -1
  95. data/vendor/liburing/test/socket-rw.c +2 -1
  96. data/vendor/liburing/test/timeout.c +276 -0
  97. data/vendor/liburing/test/xattr.c +38 -25
  98. metadata +14 -3
  99. data/vendor/liburing/test/timeout-overflow.c +0 -204
@@ -37,7 +37,6 @@ static int verify_buffer(char *buf, char val)
37
37
 
38
38
  static int test(const char *filename, int dio, int async)
39
39
  {
40
- struct io_uring_buf_reg reg = { };
41
40
  struct io_uring_sqe *sqe;
42
41
  struct io_uring_cqe *cqe;
43
42
  struct io_uring ring;
@@ -68,16 +67,9 @@ static int test(const char *filename, int dio, int async)
68
67
 
69
68
  if (posix_memalign((void **) &buf, 4096, FSIZE))
70
69
  return 1;
71
- if (posix_memalign((void **) &br, 4096, NR_BUFS * sizeof(struct io_uring_buf)))
72
- return 1;
73
-
74
- io_uring_buf_ring_init(br);
75
- reg.ring_addr = (unsigned long) br;
76
- reg.ring_entries = NR_BUFS;
77
- reg.bgid = 1;
78
70
 
79
- ret = io_uring_register_buf_ring(&ring, &reg, 0);
80
- if (ret) {
71
+ br = io_uring_setup_buf_ring(&ring, NR_BUFS, 1, 0, &ret);
72
+ if (!br) {
81
73
  if (ret == -EINVAL) {
82
74
  no_buf_ring = 1;
83
75
  return 0;
@@ -184,22 +184,11 @@ static void *recv_fn(void *data)
184
184
 
185
185
  if ((rd->buf_ring || rd->buf_select) && !rd->no_buf_add) {
186
186
  if (rd->buf_ring) {
187
- struct io_uring_buf_reg reg = { };
188
- void *ptr;
189
-
190
- if (posix_memalign(&ptr, 4096, 4096))
191
- goto err;
192
-
193
- reg.ring_addr = (unsigned long) ptr;
194
- reg.ring_entries = 1;
195
- reg.bgid = BUF_BGID;
196
- if (io_uring_register_buf_ring(&ring, &reg, 0)) {
187
+ br = io_uring_setup_buf_ring(&ring, 1, BUF_BGID, 0, &ret);
188
+ if (!br) {
197
189
  no_pbuf_ring = 1;
198
190
  goto out;
199
191
  }
200
-
201
- br = ptr;
202
- io_uring_buf_ring_init(br);
203
192
  io_uring_buf_ring_add(br, buf, sizeof(buf), BUF_BID,
204
193
  io_uring_buf_ring_mask(1), 0);
205
194
  io_uring_buf_ring_advance(br, 1);
@@ -246,9 +235,9 @@ static void *recv_fn(void *data)
246
235
  ret = do_recvmsg(&ring, buf, rd);
247
236
  close(sockfd);
248
237
 
249
- io_uring_queue_exit(&ring);
250
238
  if (br)
251
- free(br);
239
+ io_uring_free_buf_ring(&ring, br, 1, BUF_BGID);
240
+ io_uring_queue_exit(&ring);
252
241
  err:
253
242
  return (void *)(intptr_t)ret;
254
243
  out:
@@ -256,7 +245,7 @@ out:
256
245
  out_no_ring:
257
246
  pthread_mutex_unlock(mutex);
258
247
  if (br)
259
- free(br);
248
+ io_uring_free_buf_ring(&ring, br, 1, BUF_BGID);
260
249
  return NULL;
261
250
  }
262
251
 
@@ -47,7 +47,8 @@ int main(int argc, char *argv[])
47
47
  addr.sin_family = AF_INET;
48
48
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
49
49
 
50
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
50
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
51
+ assert(!ret);
51
52
  ret = listen(recv_s0, 128);
52
53
  assert(ret != -1);
53
54
 
@@ -0,0 +1,215 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Check that CMD operations on sockets are consistent.
4
+ */
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <stdint.h>
8
+ #include <assert.h>
9
+ #include <string.h>
10
+ #include <unistd.h>
11
+ #include <linux/sockios.h>
12
+ #include <sys/ioctl.h>
13
+
14
+ #include "liburing.h"
15
+ #include "helpers.h"
16
+
17
+ #define USERDATA 0x1234
18
+ #define MSG "foobarbaz"
19
+
20
+ struct fds {
21
+ int tx;
22
+ int rx;
23
+ };
24
+
25
+ /* Create 2 sockets (tx, rx) given the socket type */
26
+ static struct fds create_sockets(bool stream)
27
+ {
28
+ struct fds retval;
29
+ int fd[2];
30
+
31
+ t_create_socket_pair(fd, stream);
32
+
33
+ retval.tx = fd[0];
34
+ retval.rx = fd[1];
35
+
36
+ return retval;
37
+ }
38
+
39
+ static int create_sqe_and_submit(struct io_uring *ring, int32_t fd, int op)
40
+ {
41
+ struct io_uring_sqe *sqe;
42
+ int ret;
43
+
44
+ assert(fd > 0);
45
+ sqe = io_uring_get_sqe(ring);
46
+ assert(sqe != NULL);
47
+
48
+ io_uring_prep_cmd_sock(sqe, op, fd, 0, 0, NULL, 0);
49
+ sqe->user_data = USERDATA;
50
+
51
+ /* Submitting SQE */
52
+ ret = io_uring_submit_and_wait(ring, 1);
53
+ if (ret <= 0)
54
+ return ret;
55
+
56
+ return 0;
57
+ }
58
+
59
+ static int receive_cqe(struct io_uring *ring)
60
+ {
61
+ struct io_uring_cqe *cqe;
62
+ int err;
63
+
64
+ err = io_uring_wait_cqe(ring, &cqe);
65
+ assert(err == 0);
66
+ assert(cqe->user_data == USERDATA);
67
+ io_uring_cqe_seen(ring, cqe);
68
+
69
+ /* Return the result of the operation */
70
+ return cqe->res;
71
+ }
72
+
73
+ static ssize_t send_data(struct fds *s, char *str)
74
+ {
75
+ size_t written_bytes;
76
+
77
+ written_bytes = write(s->tx, str, strlen(str));
78
+ assert(written_bytes == strlen(MSG));
79
+
80
+ return written_bytes;
81
+ }
82
+
83
+ static int run_test(bool stream)
84
+ {
85
+ struct fds sockfds;
86
+ size_t bytes_in, bytes_out;
87
+ struct io_uring ring;
88
+ size_t written_bytes;
89
+ int error;
90
+
91
+ /* Create three sockets */
92
+ sockfds = create_sockets(stream);
93
+ assert(sockfds.tx > 0);
94
+ assert(sockfds.rx > 0);
95
+ /* Send data sing the sockfds->send */
96
+ written_bytes = send_data(&sockfds, MSG);
97
+
98
+ /* Simply io_uring ring creation */
99
+ error = t_create_ring(1, &ring, 0);
100
+ if (error == T_SETUP_SKIP)
101
+ return error;
102
+ else if (error != T_SETUP_OK)
103
+ return T_EXIT_FAIL;
104
+
105
+ error = create_sqe_and_submit(&ring, sockfds.rx,
106
+ SOCKET_URING_OP_SIOCINQ);
107
+ bytes_in = receive_cqe(&ring);
108
+ if (error)
109
+ return T_EXIT_FAIL;
110
+
111
+ error = create_sqe_and_submit(&ring, sockfds.tx,
112
+ SOCKET_URING_OP_SIOCOUTQ);
113
+ if (error)
114
+ return T_EXIT_FAIL;
115
+
116
+ bytes_out = receive_cqe(&ring);
117
+ if (bytes_in == -ENOTSUP || bytes_out == -ENOTSUP) {
118
+ fprintf(stderr, "Skipping tests. -ENOTSUP returned\n");
119
+ return T_EXIT_SKIP;
120
+ }
121
+
122
+ /*
123
+ * Assert the number of written bytes are either in the socket buffer
124
+ * or on the receive side
125
+ */
126
+ if (bytes_in + bytes_out != written_bytes) {
127
+ fprintf(stderr, "values does not match: %zu+%zu != %zu\n",
128
+ bytes_in, bytes_out, written_bytes);
129
+ return T_EXIT_FAIL;
130
+ }
131
+
132
+ io_uring_queue_exit(&ring);
133
+
134
+ return T_EXIT_PASS;
135
+ }
136
+
137
+ /*
138
+ * Make sure that siocoutq and siocinq returns the same value
139
+ * using ioctl(2) and uring commands for raw sockets
140
+ */
141
+ static int run_test_raw(void)
142
+ {
143
+ int ioctl_siocoutq, ioctl_siocinq;
144
+ int uring_siocoutq, uring_siocinq;
145
+ struct io_uring ring;
146
+ int sock, error;
147
+
148
+ sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
149
+ if (sock == -1) {
150
+ /* You need root to create raw socket */
151
+ perror("Not able to create a raw socket");
152
+ return T_EXIT_SKIP;
153
+ }
154
+
155
+ /* Simple SIOCOUTQ using ioctl */
156
+ error = ioctl(sock, SIOCOUTQ, &ioctl_siocoutq);
157
+ if (error < 0) {
158
+ fprintf(stderr, "Failed to run ioctl(SIOCOUTQ): %d\n", error);
159
+ return T_EXIT_FAIL;
160
+ }
161
+
162
+ error = ioctl(sock, SIOCINQ, &ioctl_siocinq);
163
+ if (error < 0) {
164
+ fprintf(stderr, "Failed to run ioctl(SIOCINQ): %d\n", error);
165
+ return T_EXIT_FAIL;
166
+ }
167
+
168
+ /* Get the same operation using uring cmd */
169
+ error = t_create_ring(1, &ring, 0);
170
+ if (error == T_SETUP_SKIP)
171
+ return error;
172
+ else if (error != T_SETUP_OK)
173
+ return T_EXIT_FAIL;
174
+
175
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCOUTQ);
176
+ uring_siocoutq = receive_cqe(&ring);
177
+
178
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCINQ);
179
+ uring_siocinq = receive_cqe(&ring);
180
+
181
+ /* Compare that both values (ioctl and uring CMD) should be similar */
182
+ if (uring_siocoutq != ioctl_siocoutq) {
183
+ fprintf(stderr, "values does not match: %d != %d\n",
184
+ uring_siocoutq, ioctl_siocoutq);
185
+ return T_EXIT_FAIL;
186
+ }
187
+ if (uring_siocinq != ioctl_siocinq) {
188
+ fprintf(stderr, "values does not match: %d != %d\n",
189
+ uring_siocinq, ioctl_siocinq);
190
+ return T_EXIT_FAIL;
191
+ }
192
+
193
+ return T_EXIT_PASS;
194
+ }
195
+
196
+ int main(int argc, char *argv[])
197
+ {
198
+ int err;
199
+
200
+ if (argc > 1)
201
+ return 0;
202
+
203
+ /* Test SOCK_STREAM */
204
+ err = run_test(true);
205
+ if (err)
206
+ return err;
207
+
208
+ /* Test SOCK_DGRAM */
209
+ err = run_test(false);
210
+ if (err)
211
+ return err;
212
+
213
+ /* Test raw sockets */
214
+ return run_test_raw();
215
+ }
@@ -42,7 +42,8 @@ int main(int argc, char *argv[])
42
42
 
43
43
  addr.sin_family = AF_INET;
44
44
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
45
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
45
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
46
+ assert(!ret);
46
47
  ret = listen(recv_s0, 128);
47
48
  assert(ret != -1);
48
49
 
@@ -44,7 +44,8 @@ int main(int argc, char *argv[])
44
44
 
45
45
  addr.sin_family = AF_INET;
46
46
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
47
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
47
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
48
+ assert(!ret);
48
49
  ret = listen(recv_s0, 128);
49
50
  assert(ret != -1);
50
51
 
@@ -44,7 +44,8 @@ int main(int argc, char *argv[])
44
44
 
45
45
  addr.sin_family = AF_INET;
46
46
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
47
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
47
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
48
+ assert(!ret);
48
49
  ret = listen(recv_s0, 128);
49
50
  assert(ret != -1);
50
51
 
@@ -14,12 +14,14 @@
14
14
  #include <sys/types.h>
15
15
  #include <sys/stat.h>
16
16
 
17
+ #include "helpers.h"
17
18
  #include "liburing.h"
18
19
  #include "../src/syscall.h"
19
20
 
20
21
  #define TIMEOUT_MSEC 200
21
22
  static int not_supported;
22
23
  static int no_modify;
24
+ static int no_multishot;
23
25
 
24
26
  static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
25
27
  {
@@ -1327,6 +1329,246 @@ done:
1327
1329
  }
1328
1330
 
1329
1331
 
1332
+ static int test_timeout_multishot(struct io_uring *ring)
1333
+ {
1334
+ struct io_uring_cqe *cqe;
1335
+ struct io_uring_sqe *sqe;
1336
+ struct __kernel_timespec ts;
1337
+ int ret;
1338
+
1339
+ sqe = io_uring_get_sqe(ring);
1340
+ if (!sqe) {
1341
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1342
+ goto err;
1343
+ }
1344
+
1345
+ msec_to_ts(&ts, TIMEOUT_MSEC);
1346
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT);
1347
+ io_uring_sqe_set_data(sqe, (void *) 1);
1348
+
1349
+ ret = io_uring_submit(ring);
1350
+ if (ret <= 0) {
1351
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1352
+ goto err;
1353
+ }
1354
+
1355
+ for (int i = 0; i < 2; i++) {
1356
+ ret = io_uring_wait_cqe(ring, &cqe);
1357
+ if (ret < 0) {
1358
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1359
+ goto err;
1360
+ }
1361
+
1362
+ ret = cqe->res;
1363
+ if (ret == -EINVAL) {
1364
+ no_multishot = 1;
1365
+ return T_EXIT_SKIP;
1366
+ }
1367
+
1368
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
1369
+ fprintf(stderr, "%s: flag not set in cqe\n", __FUNCTION__);
1370
+ goto err;
1371
+ }
1372
+
1373
+ if (ret != -ETIME) {
1374
+ fprintf(stderr, "%s: Timeout: %s\n", __FUNCTION__, strerror(-ret));
1375
+ goto err;
1376
+ }
1377
+
1378
+ io_uring_cqe_seen(ring, cqe);
1379
+ }
1380
+
1381
+ sqe = io_uring_get_sqe(ring);
1382
+ if (!sqe) {
1383
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1384
+ goto err;
1385
+ }
1386
+
1387
+ io_uring_prep_timeout_remove(sqe, 1, 0);
1388
+ io_uring_sqe_set_data(sqe, (void *) 2);
1389
+
1390
+ ret = io_uring_submit(ring);
1391
+ if (ret <= 0) {
1392
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1393
+ goto err;
1394
+ }
1395
+
1396
+ ret = io_uring_wait_cqe(ring, &cqe);
1397
+ if (ret < 0) {
1398
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1399
+ goto err;
1400
+ }
1401
+
1402
+ ret = cqe->res;
1403
+ if (ret < 0) {
1404
+ fprintf(stderr, "%s: remove failed: %s\n", __FUNCTION__, strerror(-ret));
1405
+ goto err;
1406
+ }
1407
+
1408
+ io_uring_cqe_seen(ring, cqe);
1409
+
1410
+ ret = io_uring_wait_cqe(ring, &cqe);
1411
+ if (ret < 0) {
1412
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1413
+ goto err;
1414
+ }
1415
+
1416
+ ret = cqe->res;
1417
+ if (ret != -ECANCELED) {
1418
+ fprintf(stderr, "%s: timeout canceled: %s %llu\n", __FUNCTION__, strerror(-ret), cqe->user_data);
1419
+ goto err;
1420
+ }
1421
+
1422
+ io_uring_cqe_seen(ring, cqe);
1423
+ return 0;
1424
+ err:
1425
+ return 1;
1426
+ }
1427
+
1428
+
1429
+ static int test_timeout_multishot_nr(struct io_uring *ring)
1430
+ {
1431
+ struct io_uring_cqe *cqe;
1432
+ struct io_uring_sqe *sqe;
1433
+ struct __kernel_timespec ts;
1434
+ int ret;
1435
+
1436
+ if (no_multishot)
1437
+ return T_EXIT_SKIP;
1438
+
1439
+ sqe = io_uring_get_sqe(ring);
1440
+ if (!sqe) {
1441
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1442
+ goto err;
1443
+ }
1444
+
1445
+ msec_to_ts(&ts, TIMEOUT_MSEC);
1446
+ io_uring_prep_timeout(sqe, &ts, 3, IORING_TIMEOUT_MULTISHOT);
1447
+ io_uring_sqe_set_data(sqe, (void *) 1);
1448
+
1449
+ ret = io_uring_submit(ring);
1450
+ if (ret <= 0) {
1451
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1452
+ goto err;
1453
+ }
1454
+
1455
+ for (int i = 0; i < 3; i++) {
1456
+ ret = io_uring_wait_cqe(ring, &cqe);
1457
+ if (ret < 0) {
1458
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1459
+ goto err;
1460
+ }
1461
+
1462
+ if (i < 2 && !(cqe->flags & IORING_CQE_F_MORE)) {
1463
+ fprintf(stderr, "%s: flag not set in cqe\n", __FUNCTION__);
1464
+ goto err;
1465
+ }
1466
+ if (i == 3 && (cqe->flags & IORING_CQE_F_MORE)) {
1467
+ fprintf(stderr, "%s: flag set in cqe\n", __FUNCTION__);
1468
+ goto err;
1469
+ }
1470
+
1471
+ ret = cqe->res;
1472
+ if (ret != -ETIME) {
1473
+ fprintf(stderr, "%s: Timeout: %s\n", __FUNCTION__, strerror(-ret));
1474
+ goto err;
1475
+ }
1476
+
1477
+ io_uring_cqe_seen(ring, cqe);
1478
+ }
1479
+
1480
+ msec_to_ts(&ts, 2 * TIMEOUT_MSEC);
1481
+ ret = io_uring_wait_cqe_timeout(ring, &cqe, &ts);
1482
+ if (ret != -ETIME) {
1483
+ fprintf(stderr, "%s: wait completion timeout %s\n", __FUNCTION__, strerror(-ret));
1484
+ goto err;
1485
+ }
1486
+
1487
+ return 0;
1488
+ err:
1489
+ return 1;
1490
+ }
1491
+
1492
+
1493
+ static int test_timeout_multishot_overflow(struct io_uring *ring)
1494
+ {
1495
+ struct io_uring_cqe *cqe;
1496
+ struct io_uring_sqe *sqe;
1497
+ struct __kernel_timespec ts;
1498
+ int ret;
1499
+
1500
+ if (no_multishot)
1501
+ return T_EXIT_SKIP;
1502
+
1503
+ sqe = io_uring_get_sqe(ring);
1504
+ if (!sqe) {
1505
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1506
+ goto err;
1507
+ }
1508
+
1509
+ msec_to_ts(&ts, 10);
1510
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT);
1511
+ io_uring_sqe_set_data(sqe, (void *) 1);
1512
+
1513
+ ret = io_uring_submit(ring);
1514
+ if (ret <= 0) {
1515
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1516
+ goto err;
1517
+ }
1518
+
1519
+ ret = io_uring_wait_cqe(ring, &cqe);
1520
+ if (ret < 0) {
1521
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1522
+ goto err;
1523
+ }
1524
+
1525
+ ret = cqe->res;
1526
+ if (ret != -ETIME) {
1527
+ fprintf(stderr, "%s: Timeout: %s\n", __FUNCTION__, strerror(-ret));
1528
+ goto err;
1529
+ }
1530
+
1531
+ io_uring_cqe_seen(ring, cqe);
1532
+ sleep(1);
1533
+
1534
+ if (!((*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW)) {
1535
+ goto err;
1536
+ }
1537
+
1538
+ /* multishot timer should be gone */
1539
+ sqe = io_uring_get_sqe(ring);
1540
+ if (!sqe) {
1541
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1542
+ goto err;
1543
+ }
1544
+
1545
+ io_uring_prep_timeout_remove(sqe, 1, 0);
1546
+
1547
+ ret = io_uring_submit(ring);
1548
+ if (ret <= 0) {
1549
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1550
+ goto err;
1551
+ }
1552
+
1553
+ ret = io_uring_wait_cqe(ring, &cqe);
1554
+ if (ret < 0) {
1555
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1556
+ goto err;
1557
+ }
1558
+
1559
+ ret = cqe->res;
1560
+ io_uring_cqe_seen(ring, cqe);
1561
+ if (ret != -ETIME) {
1562
+ fprintf(stderr, "%s: remove failed: %d %s\n", __FUNCTION__, ret, strerror(-ret));
1563
+ goto err;
1564
+ }
1565
+
1566
+ return 0;
1567
+ err:
1568
+ return 1;
1569
+ }
1570
+
1571
+
1330
1572
  int main(int argc, char *argv[])
1331
1573
  {
1332
1574
  struct io_uring ring, sqpoll_ring;
@@ -1419,6 +1661,40 @@ int main(int argc, char *argv[])
1419
1661
  return ret;
1420
1662
  }
1421
1663
 
1664
+ ret = test_timeout_multishot(&ring);
1665
+ if (ret && ret != T_EXIT_SKIP) {
1666
+ fprintf(stderr, "test_timeout_multishot failed\n");
1667
+ return ret;
1668
+ }
1669
+
1670
+ ret = test_timeout_multishot_nr(&ring);
1671
+ if (ret && ret != T_EXIT_SKIP) {
1672
+ fprintf(stderr, "test_timeout_multishot_nr failed\n");
1673
+ return ret;
1674
+ }
1675
+
1676
+ /* io_uring_wait_cqe_timeout() may have left a timeout, reinit ring */
1677
+ io_uring_queue_exit(&ring);
1678
+ ret = io_uring_queue_init(8, &ring, 0);
1679
+ if (ret) {
1680
+ fprintf(stderr, "ring setup failed\n");
1681
+ return 1;
1682
+ }
1683
+
1684
+ ret = test_timeout_multishot_overflow(&ring);
1685
+ if (ret && ret != T_EXIT_SKIP) {
1686
+ fprintf(stderr, "test_timeout_multishot_overflow failed\n");
1687
+ return ret;
1688
+ }
1689
+
1690
+ /* io_uring_wait_cqe_timeout() may have left a timeout, reinit ring */
1691
+ io_uring_queue_exit(&ring);
1692
+ ret = io_uring_queue_init(8, &ring, 0);
1693
+ if (ret) {
1694
+ fprintf(stderr, "ring setup failed\n");
1695
+ return 1;
1696
+ }
1697
+
1422
1698
  ret = test_single_timeout_wait(&ring, &p);
1423
1699
  if (ret) {
1424
1700
  fprintf(stderr, "test_single_timeout_wait failed\n");