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
@@ -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 io_uring_buf_reg reg = { };
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 *ptr, *bufs;
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
- if (posix_memalign(&ptr, 4096, 32 * sizeof(struct io_uring_buf)))
37
- return 1;
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, &reg, 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 io_uring_buf_reg reg = { };
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 *ptr, *bufs;
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
- if (posix_memalign(&ptr, 4096, 32 * sizeof(struct io_uring_buf)))
102
- return 1;
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, &reg, 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
- if (posix_memalign(&ptr, 4096, 32 * sizeof(struct io_uring_buf)))
132
- return 1;
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, &reg, 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) ptr;
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 = io_uring_unregister_buf_ring(&ring, bgid);
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 io_uring_buf_reg reg = { };
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
- if (posix_memalign(&ptr, 4096, 32 * sizeof(struct io_uring_buf)))
185
- return 1;
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, &reg, 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 = io_uring_unregister_buf_ring(&ring, bgid);
173
+ ret = io_uring_free_buf_ring(&ring, br, 32, bgid);
202
174
  if (ret) {
203
- fprintf(stderr, "Buffer ring register failed %d\n", ret);
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 1;
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
- struct io_uring_buf_reg reg = { };
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
- if (posix_memalign(&ptr, 4096, ring_size))
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, &reg, 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, &params);
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
- io_uring_prep_msg_ring_fd(sqe, dring.ring_fd, source_fd, target_fd,
106
- USER_DATA, 0);
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 = io_uring_register_buffers(ring, v, READ_BATCH);
384
+ ret = t_register_buffers(ring, v, READ_BATCH);
368
385
  if (ret) {
369
- fprintf(stderr, "Error buffer reg %d\n", ret);
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
- assert(!getsockname(fd, (struct sockaddr *)addr, &addrlen));
46
+ ret = getsockname(fd, (struct sockaddr *)addr, &addrlen);
47
+ assert(!ret);
46
48
  assert(addr->sin_port != 0);
47
49
  return 0;
48
50
  }