polyphony 1.4 → 1.6

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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +22 -0
  4. data/TODO.md +5 -14
  5. data/examples/pipes/http_server.rb +42 -12
  6. data/examples/pipes/http_server2.rb +45 -0
  7. data/ext/polyphony/backend_common.h +5 -0
  8. data/ext/polyphony/backend_io_uring.c +174 -121
  9. data/ext/polyphony/backend_io_uring_context.c +24 -18
  10. data/ext/polyphony/backend_io_uring_context.h +4 -2
  11. data/ext/polyphony/backend_libev.c +46 -22
  12. data/ext/polyphony/event.c +21 -0
  13. data/ext/polyphony/extconf.rb +25 -19
  14. data/ext/polyphony/fiber.c +0 -2
  15. data/ext/polyphony/pipe.c +1 -1
  16. data/ext/polyphony/polyphony.c +2 -20
  17. data/ext/polyphony/polyphony.h +5 -5
  18. data/ext/polyphony/ring_buffer.c +1 -0
  19. data/ext/polyphony/runqueue_ring_buffer.c +1 -0
  20. data/ext/polyphony/thread.c +63 -0
  21. data/ext/polyphony/win_uio.h +18 -0
  22. data/lib/polyphony/adapters/open3.rb +190 -0
  23. data/lib/polyphony/core/sync.rb +83 -13
  24. data/lib/polyphony/core/timer.rb +7 -25
  25. data/lib/polyphony/extensions/exception.rb +15 -0
  26. data/lib/polyphony/extensions/fiber.rb +14 -13
  27. data/lib/polyphony/extensions/io.rb +56 -14
  28. data/lib/polyphony/extensions/kernel.rb +1 -1
  29. data/lib/polyphony/extensions/object.rb +1 -13
  30. data/lib/polyphony/extensions/process.rb +76 -1
  31. data/lib/polyphony/extensions/socket.rb +0 -14
  32. data/lib/polyphony/extensions/thread.rb +19 -27
  33. data/lib/polyphony/extensions/timeout.rb +5 -1
  34. data/lib/polyphony/version.rb +1 -1
  35. data/lib/polyphony.rb +11 -5
  36. data/test/helper.rb +46 -4
  37. data/test/open3/envutil.rb +380 -0
  38. data/test/open3/find_executable.rb +24 -0
  39. data/test/stress.rb +11 -7
  40. data/test/test_backend.rb +11 -4
  41. data/test/test_event.rb +10 -3
  42. data/test/test_ext.rb +16 -1
  43. data/test/test_fiber.rb +16 -4
  44. data/test/test_global_api.rb +17 -16
  45. data/test/test_io.rb +39 -0
  46. data/test/test_kernel.rb +2 -2
  47. data/test/test_monitor.rb +356 -0
  48. data/test/test_open3.rb +338 -0
  49. data/test/test_signal.rb +5 -1
  50. data/test/test_socket.rb +6 -98
  51. data/test/test_sync.rb +46 -0
  52. data/test/test_thread.rb +10 -1
  53. data/test/test_thread_pool.rb +5 -0
  54. data/test/test_throttler.rb +1 -1
  55. data/test/test_timer.rb +8 -2
  56. data/test/test_trace.rb +2 -0
  57. data/vendor/liburing/.github/workflows/build.yml +8 -0
  58. data/vendor/liburing/.gitignore +1 -0
  59. data/vendor/liburing/CHANGELOG +8 -0
  60. data/vendor/liburing/configure +17 -25
  61. data/vendor/liburing/debian/liburing-dev.manpages +2 -0
  62. data/vendor/liburing/debian/rules +2 -1
  63. data/vendor/liburing/examples/Makefile +2 -1
  64. data/vendor/liburing/examples/io_uring-udp.c +11 -3
  65. data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
  66. data/vendor/liburing/liburing.spec +1 -1
  67. data/vendor/liburing/make-debs.sh +4 -2
  68. data/vendor/liburing/src/Makefile +5 -5
  69. data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
  70. data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
  71. data/vendor/liburing/src/include/liburing.h +86 -11
  72. data/vendor/liburing/src/int_flags.h +1 -0
  73. data/vendor/liburing/src/liburing-ffi.map +12 -0
  74. data/vendor/liburing/src/liburing.map +8 -0
  75. data/vendor/liburing/src/register.c +7 -2
  76. data/vendor/liburing/src/setup.c +373 -81
  77. data/vendor/liburing/test/232c93d07b74.c +3 -3
  78. data/vendor/liburing/test/Makefile +10 -3
  79. data/vendor/liburing/test/accept.c +2 -1
  80. data/vendor/liburing/test/buf-ring.c +35 -75
  81. data/vendor/liburing/test/connect-rep.c +204 -0
  82. data/vendor/liburing/test/coredump.c +59 -0
  83. data/vendor/liburing/test/fallocate.c +9 -0
  84. data/vendor/liburing/test/fd-pass.c +34 -3
  85. data/vendor/liburing/test/file-verify.c +27 -6
  86. data/vendor/liburing/test/helpers.c +3 -1
  87. data/vendor/liburing/test/io_uring_register.c +25 -28
  88. data/vendor/liburing/test/io_uring_setup.c +1 -1
  89. data/vendor/liburing/test/poll-cancel-all.c +29 -5
  90. data/vendor/liburing/test/poll-race-mshot.c +6 -22
  91. data/vendor/liburing/test/read-write.c +53 -0
  92. data/vendor/liburing/test/recv-msgall.c +21 -23
  93. data/vendor/liburing/test/reg-fd-only.c +55 -0
  94. data/vendor/liburing/test/reg-hint.c +56 -0
  95. data/vendor/liburing/test/regbuf-merge.c +91 -0
  96. data/vendor/liburing/test/ringbuf-read.c +2 -10
  97. data/vendor/liburing/test/send_recvmsg.c +5 -16
  98. data/vendor/liburing/test/shutdown.c +2 -1
  99. data/vendor/liburing/test/socket-io-cmd.c +215 -0
  100. data/vendor/liburing/test/socket-rw-eagain.c +2 -1
  101. data/vendor/liburing/test/socket-rw-offset.c +2 -1
  102. data/vendor/liburing/test/socket-rw.c +2 -1
  103. data/vendor/liburing/test/timeout.c +276 -0
  104. data/vendor/liburing/test/xattr.c +38 -25
  105. metadata +20 -7
  106. 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");