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
@@ -32,7 +32,7 @@ static rlim_t mlock_limit;
32
32
  static int devnull;
33
33
 
34
34
  static int expect_fail(int fd, unsigned int opcode, void *arg,
35
- unsigned int nr_args, int error)
35
+ unsigned int nr_args, int error, int error2)
36
36
  {
37
37
  int ret;
38
38
 
@@ -55,8 +55,8 @@ static int expect_fail(int fd, unsigned int opcode, void *arg,
55
55
  return 1;
56
56
  }
57
57
 
58
- if (ret != error) {
59
- fprintf(stderr, "expected %d, got %d\n", error, ret);
58
+ if (ret != error && (error2 && ret != error2)) {
59
+ fprintf(stderr, "expected %d/%d, got %d\n", error, error2, ret);
60
60
  return 1;
61
61
  }
62
62
  return 0;
@@ -195,8 +195,7 @@ static int test_max_fds(int uring_fd)
195
195
  status = 0;
196
196
  ret = io_uring_register(uring_fd, IORING_UNREGISTER_FILES, 0, 0);
197
197
  if (ret < 0) {
198
- ret = errno;
199
- errno = ret;
198
+ errno = -ret;
200
199
  perror("io_uring_register UNREGISTER_FILES");
201
200
  exit(1);
202
201
  }
@@ -230,22 +229,20 @@ static int test_memlock_exceeded(int fd)
230
229
 
231
230
  while (iov.iov_len) {
232
231
  ret = io_uring_register(fd, IORING_REGISTER_BUFFERS, &iov, 1);
233
- if (ret < 0) {
234
- if (errno == ENOMEM) {
235
- iov.iov_len /= 2;
236
- continue;
237
- }
238
- if (errno == EFAULT) {
239
- free(buf);
240
- return 0;
241
- }
242
- fprintf(stderr, "expected success or EFAULT, got %d\n", errno);
232
+ if (ret == -ENOMEM) {
233
+ iov.iov_len /= 2;
234
+ continue;
235
+ } else if (ret == -EFAULT) {
236
+ free(buf);
237
+ return 0;
238
+ } else if (ret) {
239
+ fprintf(stderr, "expected success or EFAULT, got %d\n", ret);
243
240
  free(buf);
244
241
  return 1;
245
242
  }
246
243
  ret = io_uring_register(fd, IORING_UNREGISTER_BUFFERS, NULL, 0);
247
244
  if (ret != 0) {
248
- fprintf(stderr, "error: unregister failed with %d\n", errno);
245
+ fprintf(stderr, "error: unregister failed with %d\n", ret);
249
246
  free(buf);
250
247
  return 1;
251
248
  }
@@ -277,15 +274,15 @@ static int test_iovec_nr(int fd)
277
274
  iovs[i].iov_len = pagesize;
278
275
  }
279
276
 
280
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, iovs, nr, -EINVAL);
277
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, iovs, nr, -EINVAL, 0);
281
278
 
282
279
  /* reduce to UIO_MAXIOV */
283
280
  nr = UIO_MAXIOV;
284
281
  ret = io_uring_register(fd, IORING_REGISTER_BUFFERS, iovs, nr);
285
- if (ret && (errno == ENOMEM || errno == EPERM) && geteuid()) {
282
+ if ((ret == -ENOMEM || ret == -EPERM) && geteuid()) {
286
283
  fprintf(stderr, "can't register large iovec for regular users, skip\n");
287
284
  } else if (ret != 0) {
288
- fprintf(stderr, "expected success, got %d\n", errno);
285
+ fprintf(stderr, "expected success, got %d\n", ret);
289
286
  status = 1;
290
287
  } else {
291
288
  io_uring_register(fd, IORING_UNREGISTER_BUFFERS, 0, 0);
@@ -308,12 +305,12 @@ static int test_iovec_size(int fd)
308
305
  /* NULL pointer for base */
309
306
  iov.iov_base = 0;
310
307
  iov.iov_len = 4096;
311
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
308
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
312
309
 
313
310
  /* valid base, 0 length */
314
311
  iov.iov_base = &buf;
315
312
  iov.iov_len = 0;
316
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
313
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
317
314
 
318
315
  /* valid base, length exceeds size */
319
316
  /* this requires an unampped page directly after buf */
@@ -324,7 +321,7 @@ static int test_iovec_size(int fd)
324
321
  assert(ret == 0);
325
322
  iov.iov_base = buf;
326
323
  iov.iov_len = 2 * pagesize;
327
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
324
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
328
325
  munmap(buf, pagesize);
329
326
 
330
327
  /* huge page */
@@ -372,7 +369,7 @@ static int test_iovec_size(int fd)
372
369
  status = 1;
373
370
  iov.iov_base = buf;
374
371
  iov.iov_len = 2*1024*1024;
375
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EOPNOTSUPP);
372
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, -EOPNOTSUPP);
376
373
  munmap(buf, 2*1024*1024);
377
374
 
378
375
  /* bump up against the soft limit and make sure we get EFAULT
@@ -410,7 +407,7 @@ static int ioring_poll(struct io_uring *ring, int fd, int fixed)
410
407
  return 1;
411
408
  }
412
409
  ret = 0;
413
- if (cqe->res != POLLOUT) {
410
+ if (!(cqe->res & POLLOUT)) {
414
411
  fprintf(stderr, "io_uring_wait_cqe: expected 0x%.8x, got 0x%.8x\n",
415
412
  POLLOUT, cqe->res);
416
413
  ret = 1;
@@ -442,7 +439,7 @@ static int test_poll_ringfd(void)
442
439
  * fail, because the kernel does not allow registering of the
443
440
  * ring_fd.
444
441
  */
445
- status |= expect_fail(fd, IORING_REGISTER_FILES, &fd, 1, -EBADF);
442
+ status |= expect_fail(fd, IORING_REGISTER_FILES, &fd, 1, -EBADF, 0);
446
443
 
447
444
  /* tear down queue */
448
445
  io_uring_queue_exit(&ring);
@@ -475,14 +472,14 @@ int main(int argc, char **argv)
475
472
  }
476
473
 
477
474
  /* invalid fd */
478
- status |= expect_fail(-1, 0, NULL, 0, -EBADF);
475
+ status |= expect_fail(-1, 0, NULL, 0, -EBADF, 0);
479
476
  /* valid fd that is not an io_uring fd */
480
- status |= expect_fail(devnull, 0, NULL, 0, -EOPNOTSUPP);
477
+ status |= expect_fail(devnull, 0, NULL, 0, -EOPNOTSUPP, 0);
481
478
 
482
479
  /* invalid opcode */
483
480
  memset(&p, 0, sizeof(p));
484
481
  fd = new_io_uring(1, &p);
485
- ret = expect_fail(fd, ~0U, NULL, 0, -EINVAL);
482
+ ret = expect_fail(fd, ~0U, NULL, 0, -EINVAL, 0);
486
483
  if (ret) {
487
484
  /* if this succeeds, tear down the io_uring instance
488
485
  * and start clean for the next test. */
@@ -17,7 +17,7 @@
17
17
  #include "liburing.h"
18
18
  #include "helpers.h"
19
19
 
20
- #include "../syscall.h"
20
+ #include "../src/syscall.h"
21
21
 
22
22
  /* bogus: setup returns a valid fd on success... expect can't predict the
23
23
  fd we'll get, so this really only takes 1 parameter: error */
@@ -14,11 +14,22 @@
14
14
 
15
15
  static int no_cancel_flags;
16
16
 
17
- static int test1(struct io_uring *ring, int *fd)
17
+ static int test1(struct io_uring *ring, int *fd, int fixed)
18
18
  {
19
19
  struct io_uring_sqe *sqe;
20
20
  struct io_uring_cqe *cqe;
21
- int ret, i;
21
+ int ret, i, __fd = fd[0];
22
+
23
+ if (fixed)
24
+ __fd = 0;
25
+
26
+ if (fixed) {
27
+ ret = io_uring_register_files(ring, fd, 1);
28
+ if (ret) {
29
+ fprintf(stderr, "failed file register %d\n", ret);
30
+ return 1;
31
+ }
32
+ }
22
33
 
23
34
  for (i = 0; i < 8; i++) {
24
35
  sqe = io_uring_get_sqe(ring);
@@ -27,8 +38,10 @@ static int test1(struct io_uring *ring, int *fd)
27
38
  return 1;
28
39
  }
29
40
 
30
- io_uring_prep_poll_add(sqe, fd[0], POLLIN);
41
+ io_uring_prep_poll_add(sqe, __fd, POLLIN);
31
42
  sqe->user_data = i + 1;
43
+ if (fixed)
44
+ sqe->flags |= IOSQE_FIXED_FILE;
32
45
  }
33
46
 
34
47
  ret = io_uring_submit(ring);
@@ -51,7 +64,9 @@ static int test1(struct io_uring *ring, int *fd)
51
64
  */
52
65
  io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
53
66
  sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
54
- sqe->fd = fd[0];
67
+ if (fixed)
68
+ sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD_FIXED;
69
+ sqe->fd = __fd;
55
70
  sqe->user_data = 100;
56
71
 
57
72
  ret = io_uring_submit(ring);
@@ -93,6 +108,9 @@ static int test1(struct io_uring *ring, int *fd)
93
108
  io_uring_cqe_seen(ring, cqe);
94
109
  }
95
110
 
111
+ if (fixed)
112
+ io_uring_unregister_files(ring);
113
+
96
114
  return 0;
97
115
  }
98
116
 
@@ -442,7 +460,7 @@ int main(int argc, char *argv[])
442
460
  return 1;
443
461
  }
444
462
 
445
- ret = test1(&ring, fd);
463
+ ret = test1(&ring, fd, 0);
446
464
  if (ret) {
447
465
  fprintf(stderr, "test1 failed\n");
448
466
  return ret;
@@ -450,6 +468,12 @@ int main(int argc, char *argv[])
450
468
  if (no_cancel_flags)
451
469
  return 0;
452
470
 
471
+ ret = test1(&ring, fd, 1);
472
+ if (ret) {
473
+ fprintf(stderr, "test1 fixed failed\n");
474
+ return ret;
475
+ }
476
+
453
477
  ret = test2(&ring, fd);
454
478
  if (ret) {
455
479
  fprintf(stderr, "test2 failed\n");
@@ -49,7 +49,6 @@ static void *thread(void *data)
49
49
 
50
50
  static int test(struct io_uring *ring, struct data *d)
51
51
  {
52
- struct io_uring_buf_reg reg = { };
53
52
  struct io_uring_buf_ring *br;
54
53
  struct io_uring_sqe *sqe;
55
54
  struct io_uring_cqe *cqe;
@@ -67,16 +66,9 @@ static int test(struct io_uring *ring, struct data *d)
67
66
 
68
67
  if (posix_memalign((void **) &buf, 16384, BUF_SIZE * NREQS))
69
68
  return T_EXIT_FAIL;
70
- if (posix_memalign((void **) &br, 16384, sizeof(struct io_uring_buf) * NREQS))
71
- return T_EXIT_FAIL;
72
-
73
- io_uring_buf_ring_init(br);
74
- reg.ring_addr = (unsigned long) br;
75
- reg.ring_entries = NREQS;
76
- reg.bgid = 1;
77
69
 
78
- ret = io_uring_register_buf_ring(ring, &reg, 0);
79
- if (ret) {
70
+ br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
71
+ if (!br) {
80
72
  if (ret == -EINVAL) {
81
73
  no_buf_ring = 1;
82
74
  return T_EXIT_SKIP;
@@ -143,7 +135,7 @@ static int test(struct io_uring *ring, struct data *d)
143
135
 
144
136
  pthread_join(t, &ret2);
145
137
  free(buf);
146
- free(br);
138
+ io_uring_free_buf_ring(ring, br, NREQS, 1);
147
139
  close(fd[0]);
148
140
  close(fd[1]);
149
141
  return T_EXIT_PASS;
@@ -151,7 +143,6 @@ static int test(struct io_uring *ring, struct data *d)
151
143
 
152
144
  static int test_mshot(struct io_uring *ring, struct data *d)
153
145
  {
154
- struct io_uring_buf_reg reg = { };
155
146
  struct io_uring_buf_ring *br;
156
147
  struct io_uring_sqe *sqe;
157
148
  struct io_uring_cqe *cqe;
@@ -169,16 +160,9 @@ static int test_mshot(struct io_uring *ring, struct data *d)
169
160
 
170
161
  if (posix_memalign((void *) &buf, 16384, BUF_SIZE * NREQS))
171
162
  return T_EXIT_FAIL;
172
- if (posix_memalign((void *) &br, 16384, sizeof(struct io_uring_buf) * NREQS))
173
- return T_EXIT_FAIL;
174
-
175
- io_uring_buf_ring_init(br);
176
- reg.ring_addr = (unsigned long) br;
177
- reg.ring_entries = NREQS;
178
- reg.bgid = 1;
179
163
 
180
- ret = io_uring_register_buf_ring(ring, &reg, 0);
181
- if (ret) {
164
+ br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
165
+ if (!br) {
182
166
  fprintf(stderr, "buf ring reg %d\n", ret);
183
167
  return T_EXIT_FAIL;
184
168
  }
@@ -245,8 +229,8 @@ static int test_mshot(struct io_uring *ring, struct data *d)
245
229
  }
246
230
 
247
231
  pthread_join(t, &ret2);
232
+ io_uring_free_buf_ring(ring, br, NREQS, 1);
248
233
  free(buf);
249
- free(br);
250
234
  close(fd[0]);
251
235
  close(fd[1]);
252
236
  return T_EXIT_PASS;
@@ -637,6 +637,53 @@ static int test_rem_buf(int batch, int sqe_flags)
637
637
  return ret;
638
638
  }
639
639
 
640
+ static int test_rem_buf_single(int to_rem)
641
+ {
642
+ struct io_uring_sqe *sqe;
643
+ struct io_uring_cqe *cqe;
644
+ struct io_uring ring;
645
+ int ret, expected;
646
+ int bgid = 1;
647
+
648
+ if (no_buf_select)
649
+ return 0;
650
+
651
+ ret = io_uring_queue_init(64, &ring, 0);
652
+ if (ret) {
653
+ fprintf(stderr, "ring create failed: %d\n", ret);
654
+ return 1;
655
+ }
656
+
657
+ ret = provide_buffers_iovec(&ring, bgid);
658
+ if (ret)
659
+ return ret;
660
+
661
+ expected = (to_rem > BUFFERS) ? BUFFERS : to_rem;
662
+
663
+ sqe = io_uring_get_sqe(&ring);
664
+ io_uring_prep_remove_buffers(sqe, to_rem, bgid);
665
+
666
+ ret = io_uring_submit(&ring);
667
+ if (ret != 1) {
668
+ fprintf(stderr, "submit: %d\n", ret);
669
+ return -1;
670
+ }
671
+
672
+ ret = io_uring_wait_cqe(&ring, &cqe);
673
+ if (ret) {
674
+ fprintf(stderr, "wait_cqe=%d\n", ret);
675
+ return 1;
676
+ }
677
+ if (cqe->res != expected) {
678
+ fprintf(stderr, "cqe->res=%d, expected=%d\n", cqe->res, expected);
679
+ return 1;
680
+ }
681
+ io_uring_cqe_seen(&ring, cqe);
682
+
683
+ io_uring_queue_exit(&ring);
684
+ return ret;
685
+ }
686
+
640
687
  static int test_io_link(const char *file)
641
688
  {
642
689
  const int nr_links = 100;
@@ -950,6 +997,12 @@ int main(int argc, char *argv[])
950
997
  }
951
998
  }
952
999
 
1000
+ ret = test_rem_buf_single(BUFFERS + 1);
1001
+ if (ret) {
1002
+ fprintf(stderr, "test_rem_buf_single(BUFFERS + 1) failed\n");
1003
+ goto err;
1004
+ }
1005
+
953
1006
  if (fname != argv[1])
954
1007
  unlink(fname);
955
1008
  return 0;
@@ -18,14 +18,18 @@
18
18
  #define MAX_MSG 128
19
19
  #define HOST "127.0.0.1"
20
20
  static __be16 bind_port;
21
+ struct recv_data {
22
+ pthread_barrier_t barrier;
23
+ int use_recvmsg;
24
+ struct msghdr msg;
25
+ };
21
26
 
22
27
  static int recv_prep(struct io_uring *ring, struct iovec *iov, int *sock,
23
- int use_recvmsg)
28
+ struct recv_data *rd)
24
29
  {
25
30
  struct sockaddr_in saddr;
26
31
  struct io_uring_sqe *sqe;
27
32
  int sockfd, ret, val;
28
- struct msghdr msg = { };
29
33
 
30
34
  memset(&saddr, 0, sizeof(saddr));
31
35
  saddr.sin_family = AF_INET;
@@ -47,14 +51,17 @@ static int recv_prep(struct io_uring *ring, struct iovec *iov, int *sock,
47
51
  bind_port = saddr.sin_port;
48
52
 
49
53
  sqe = io_uring_get_sqe(ring);
50
- if (!use_recvmsg) {
54
+ if (!rd->use_recvmsg) {
51
55
  io_uring_prep_recv(sqe, sockfd, iov->iov_base, iov->iov_len,
52
56
  MSG_WAITALL);
53
57
  } else {
54
- msg.msg_namelen = sizeof(struct sockaddr_in);
55
- msg.msg_iov = iov;
56
- msg.msg_iovlen = 1;
57
- io_uring_prep_recvmsg(sqe, sockfd, &msg, MSG_WAITALL);
58
+ struct msghdr *msg = &rd->msg;
59
+
60
+ memset(msg, 0, sizeof(*msg));
61
+ msg->msg_namelen = sizeof(struct sockaddr_in);
62
+ msg->msg_iov = iov;
63
+ msg->msg_iovlen = 1;
64
+ io_uring_prep_recvmsg(sqe, sockfd, msg, MSG_WAITALL);
58
65
  }
59
66
 
60
67
  sqe->user_data = 2;
@@ -101,11 +108,6 @@ err:
101
108
  return 1;
102
109
  }
103
110
 
104
- struct recv_data {
105
- pthread_mutex_t mutex;
106
- int use_recvmsg;
107
- };
108
-
109
111
  static void *recv_fn(void *data)
110
112
  {
111
113
  struct recv_data *rd = data;
@@ -120,20 +122,20 @@ static void *recv_fn(void *data)
120
122
 
121
123
  ret = t_create_ring_params(1, &ring, &p);
122
124
  if (ret == T_SETUP_SKIP) {
123
- pthread_mutex_unlock(&rd->mutex);
125
+ pthread_barrier_wait(&rd->barrier);
124
126
  ret = 0;
125
127
  goto err;
126
128
  } else if (ret < 0) {
127
- pthread_mutex_unlock(&rd->mutex);
129
+ pthread_barrier_wait(&rd->barrier);
128
130
  goto err;
129
131
  }
130
132
 
131
- ret = recv_prep(&ring, &iov, &sock, rd->use_recvmsg);
133
+ ret = recv_prep(&ring, &iov, &sock, rd);
132
134
  if (ret) {
133
135
  fprintf(stderr, "recv_prep failed: %d\n", ret);
134
136
  goto err;
135
137
  }
136
- pthread_mutex_unlock(&rd->mutex);
138
+ pthread_barrier_wait(&rd->barrier);
137
139
  ret = do_recv(&ring);
138
140
  close(sock);
139
141
  io_uring_queue_exit(&ring);
@@ -217,28 +219,24 @@ err:
217
219
 
218
220
  static int test(int use_recvmsg)
219
221
  {
220
- pthread_mutexattr_t attr;
221
222
  pthread_t recv_thread;
222
223
  struct recv_data rd;
223
224
  int ret;
224
225
  void *retval;
225
226
 
226
- pthread_mutexattr_init(&attr);
227
- pthread_mutexattr_setpshared(&attr, 1);
228
- pthread_mutex_init(&rd.mutex, &attr);
229
- pthread_mutex_lock(&rd.mutex);
227
+ pthread_barrier_init(&rd.barrier, NULL, 2);
230
228
  rd.use_recvmsg = use_recvmsg;
231
229
 
232
230
  ret = pthread_create(&recv_thread, NULL, recv_fn, &rd);
233
231
  if (ret) {
234
232
  fprintf(stderr, "Thread create failed: %d\n", ret);
235
- pthread_mutex_unlock(&rd.mutex);
236
233
  return 1;
237
234
  }
238
235
 
239
- pthread_mutex_lock(&rd.mutex);
236
+ pthread_barrier_wait(&rd.barrier);
240
237
  do_send();
241
238
  pthread_join(recv_thread, &retval);
239
+ pthread_barrier_destroy(&rd.barrier);
242
240
  return (intptr_t)retval;
243
241
  }
244
242
 
@@ -0,0 +1,55 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Test io_uring_setup with IORING_SETUP_REGISTERED_FD_ONLY
4
+ *
5
+ */
6
+ #include <stdio.h>
7
+
8
+ #include "helpers.h"
9
+
10
+ int main(int argc, char *argv[])
11
+ {
12
+ struct io_uring ring;
13
+ unsigned values[2];
14
+ int ret;
15
+
16
+ if (argc > 1)
17
+ return T_EXIT_SKIP;
18
+
19
+ ret = io_uring_queue_init(8, &ring, IORING_SETUP_REGISTERED_FD_ONLY | IORING_SETUP_NO_MMAP);
20
+ if (ret == -EINVAL)
21
+ return T_EXIT_SKIP;
22
+ else if (ret) {
23
+ fprintf(stderr, "ring setup failed\n");
24
+ return T_EXIT_FAIL;
25
+ }
26
+
27
+ ret = io_uring_register_ring_fd(&ring);
28
+ if (ret != -EEXIST) {
29
+ fprintf(stderr, "registering already-registered ring fd should fail\n");
30
+ goto err;
31
+ }
32
+
33
+ ret = io_uring_close_ring_fd(&ring);
34
+ if (ret != -EBADF) {
35
+ fprintf(stderr, "closing already-closed ring fd should fail\n");
36
+ goto err;
37
+ }
38
+
39
+ /* Test a simple io_uring_register operation expected to work.
40
+ * io_uring_register_iowq_max_workers is arbitrary.
41
+ */
42
+ values[0] = values[1] = 0;
43
+ ret = io_uring_register_iowq_max_workers(&ring, values);
44
+ if (ret || (values[0] == 0 && values[1] == 0)) {
45
+ fprintf(stderr, "io_uring_register operation failed after closing ring fd\n");
46
+ goto err;
47
+ }
48
+
49
+ io_uring_queue_exit(&ring);
50
+ return T_EXIT_PASS;
51
+
52
+ err:
53
+ io_uring_queue_exit(&ring);
54
+ return T_EXIT_FAIL;
55
+ }
@@ -0,0 +1,56 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Test alloc hint sanity after unregistering the file table
4
+ */
5
+ #include <stdio.h>
6
+ #include <unistd.h>
7
+ #include <sys/socket.h>
8
+
9
+ #include "liburing.h"
10
+ #include "helpers.h"
11
+
12
+ int main(int argc, char *argv[])
13
+ {
14
+ struct io_uring_sqe *sqe;
15
+ struct io_uring_cqe *cqe;
16
+ struct io_uring ring;
17
+ int ret;
18
+
19
+ if (argc > 1)
20
+ return T_EXIT_SKIP;
21
+
22
+ io_uring_queue_init(1, &ring, 0);
23
+
24
+ ret = io_uring_register_files_sparse(&ring, 16);
25
+ if (ret) {
26
+ if (ret == -EINVAL)
27
+ return T_EXIT_SKIP;
28
+
29
+ fprintf(stderr, "Failed to register file table: %d\n", ret);
30
+ return T_EXIT_FAIL;
31
+ }
32
+ io_uring_unregister_files(&ring);
33
+
34
+ sqe = io_uring_get_sqe(&ring);
35
+ io_uring_prep_socket_direct_alloc(sqe, AF_UNIX, SOCK_DGRAM, 0, 0);
36
+
37
+ ret = io_uring_submit(&ring);
38
+ if (ret != 1) {
39
+ fprintf(stderr, "submit %d\n", ret);
40
+ return T_EXIT_FAIL;
41
+ }
42
+
43
+ ret = io_uring_wait_cqe(&ring, &cqe);
44
+ if (ret) {
45
+ fprintf(stderr, "wait cqe: %d\n", ret);
46
+ return T_EXIT_FAIL;
47
+ }
48
+
49
+ if (cqe->res != -ENFILE) {
50
+ fprintf(stderr, "Bad CQE res: %d\n", cqe->res);
51
+ return T_EXIT_FAIL;
52
+ }
53
+
54
+ io_uring_cqe_seen(&ring, cqe);
55
+ return T_EXIT_PASS;
56
+ }
@@ -0,0 +1,91 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ // autogenerated by syzkaller (https://github.com/google/syzkaller)
3
+
4
+ #include <endian.h>
5
+ #include <stdint.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <sys/mman.h>
10
+ #include <sys/syscall.h>
11
+ #include <sys/types.h>
12
+ #include <unistd.h>
13
+
14
+ #include "helpers.h"
15
+
16
+ #ifndef __NR_io_uring_register
17
+ #define __NR_io_uring_register 427
18
+ #endif
19
+ #ifndef __NR_io_uring_setup
20
+ #define __NR_io_uring_setup 425
21
+ #endif
22
+
23
+ #define SIZEOF_IO_URING_SQE 64
24
+ #define SIZEOF_IO_URING_CQE 16
25
+ #define SQ_HEAD_OFFSET 0
26
+ #define SQ_TAIL_OFFSET 64
27
+ #define SQ_RING_MASK_OFFSET 256
28
+ #define SQ_RING_ENTRIES_OFFSET 264
29
+ #define SQ_FLAGS_OFFSET 276
30
+ #define SQ_DROPPED_OFFSET 272
31
+ #define CQ_HEAD_OFFSET 128
32
+ #define CQ_TAIL_OFFSET 192
33
+ #define CQ_RING_MASK_OFFSET 260
34
+ #define CQ_RING_ENTRIES_OFFSET 268
35
+ #define CQ_RING_OVERFLOW_OFFSET 284
36
+ #define CQ_FLAGS_OFFSET 280
37
+ #define CQ_CQES_OFFSET 320
38
+
39
+ static long syz_io_uring_setup(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5)
40
+ {
41
+ uint32_t entries = (uint32_t)a0;
42
+ struct io_uring_params* setup_params = (struct io_uring_params*)a1;
43
+ void* vma1 = (void*)a2;
44
+ void* vma2 = (void*)a3;
45
+ void** ring_ptr_out = (void**)a4;
46
+ void** sqes_ptr_out = (void**)a5;
47
+ uint32_t fd_io_uring = syscall(__NR_io_uring_setup, entries, setup_params);
48
+ uint32_t sq_ring_sz = setup_params->sq_off.array + setup_params->sq_entries * sizeof(uint32_t);
49
+ uint32_t cq_ring_sz = setup_params->cq_off.cqes + setup_params->cq_entries * SIZEOF_IO_URING_CQE;
50
+ uint32_t ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz;
51
+ *ring_ptr_out = mmap(vma1, ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQ_RING);
52
+ uint32_t sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE;
53
+ *sqes_ptr_out = mmap(vma2, sqes_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQES);
54
+ return fd_io_uring;
55
+ }
56
+
57
+ static uint64_t r[1] = {0xffffffffffffffff};
58
+
59
+ int main(int argc, char *argv[])
60
+ {
61
+ intptr_t res = 0;
62
+
63
+ if (argc > 1)
64
+ return T_EXIT_SKIP;
65
+
66
+ mmap((void *) 0x1ffff000ul, 0x1000ul, PROT_NONE,
67
+ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0ul);
68
+ mmap((void *) 0x20000000ul, 0x1000000ul, PROT_READ|PROT_WRITE|PROT_EXEC,
69
+ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0ul);
70
+ mmap((void *) 0x21000000ul, 0x1000ul, PROT_NONE,
71
+ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0ul);
72
+
73
+ *(uint32_t*)0x20000684 = 0;
74
+ *(uint32_t*)0x20000688 = 0;
75
+ *(uint32_t*)0x2000068c = 0;
76
+ *(uint32_t*)0x20000690 = 0;
77
+ *(uint32_t*)0x20000698 = -1;
78
+ memset((void*)0x2000069c, 0, 12);
79
+
80
+ res = syz_io_uring_setup(0x2fd6, 0x20000680, 0x20ffd000, 0x20ffc000,
81
+ 0x20000700, 0x20000740);
82
+ if (res != -1)
83
+ r[0] = res;
84
+
85
+ *(uint64_t*)0x20002840 = 0;
86
+ *(uint64_t*)0x20002848 = 0;
87
+ *(uint64_t*)0x20002850 = 0x20000840;
88
+ *(uint64_t*)0x20002858 = 0x1000;
89
+ syscall(__NR_io_uring_register, r[0], 0ul, 0x20002840ul, 2ul);
90
+ return T_EXIT_PASS;
91
+ }