uringmachine 0.4 → 0.5

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +14 -0
  4. data/README.md +44 -1
  5. data/TODO.md +12 -3
  6. data/examples/bm_snooze.rb +89 -0
  7. data/examples/bm_write.rb +56 -0
  8. data/examples/dns_client.rb +12 -0
  9. data/examples/http_server.rb +42 -43
  10. data/examples/server_client.rb +64 -0
  11. data/examples/snooze.rb +44 -0
  12. data/examples/write_dev_null.rb +16 -0
  13. data/ext/um/extconf.rb +24 -14
  14. data/ext/um/um.c +468 -414
  15. data/ext/um/um.h +129 -39
  16. data/ext/um/um_buffer.c +49 -0
  17. data/ext/um/um_class.c +148 -24
  18. data/ext/um/um_const.c +30 -1
  19. data/ext/um/um_ext.c +4 -0
  20. data/ext/um/um_mutex_class.c +47 -0
  21. data/ext/um/um_op.c +86 -111
  22. data/ext/um/um_queue_class.c +58 -0
  23. data/ext/um/um_sync.c +273 -0
  24. data/ext/um/um_utils.c +1 -1
  25. data/lib/uringmachine/dns_resolver.rb +84 -0
  26. data/lib/uringmachine/version.rb +1 -1
  27. data/lib/uringmachine.rb +19 -3
  28. data/supressions/ruby.supp +71 -0
  29. data/test/test_um.rb +466 -47
  30. data/vendor/liburing/.gitignore +5 -0
  31. data/vendor/liburing/CHANGELOG +1 -0
  32. data/vendor/liburing/configure +32 -0
  33. data/vendor/liburing/examples/Makefile +1 -0
  34. data/vendor/liburing/examples/reg-wait.c +159 -0
  35. data/vendor/liburing/liburing.spec +1 -1
  36. data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
  37. data/vendor/liburing/src/include/liburing.h +28 -2
  38. data/vendor/liburing/src/int_flags.h +10 -3
  39. data/vendor/liburing/src/liburing-ffi.map +13 -2
  40. data/vendor/liburing/src/liburing.map +9 -0
  41. data/vendor/liburing/src/queue.c +25 -16
  42. data/vendor/liburing/src/register.c +73 -4
  43. data/vendor/liburing/src/setup.c +46 -18
  44. data/vendor/liburing/src/setup.h +6 -0
  45. data/vendor/liburing/test/Makefile +7 -0
  46. data/vendor/liburing/test/cmd-discard.c +427 -0
  47. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  48. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  49. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  50. data/vendor/liburing/test/io_uring_register.c +13 -2
  51. data/vendor/liburing/test/napi-test.c +1 -1
  52. data/vendor/liburing/test/no-mmap-inval.c +1 -1
  53. data/vendor/liburing/test/read-mshot-empty.c +2 -0
  54. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  55. data/vendor/liburing/test/read-mshot.c +6 -0
  56. data/vendor/liburing/test/recvsend_bundle.c +2 -2
  57. data/vendor/liburing/test/reg-fd-only.c +1 -1
  58. data/vendor/liburing/test/reg-wait.c +251 -0
  59. data/vendor/liburing/test/regbuf-clone.c +458 -0
  60. data/vendor/liburing/test/resize-rings.c +643 -0
  61. data/vendor/liburing/test/rsrc_tags.c +1 -1
  62. data/vendor/liburing/test/sqpoll-sleep.c +39 -8
  63. data/vendor/liburing/test/sqwait.c +136 -0
  64. data/vendor/liburing/test/sync-cancel.c +8 -1
  65. data/vendor/liburing/test/timeout.c +13 -8
  66. metadata +22 -4
  67. data/examples/http_server_multishot.rb +0 -57
  68. data/examples/http_server_simpler.rb +0 -34
@@ -0,0 +1,136 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: test that the app can always get a new sqe after having
4
+ * called io_uring_sqring_wait().
5
+ *
6
+ */
7
+ #include <stdio.h>
8
+ #include <stdlib.h>
9
+ #include <unistd.h>
10
+
11
+ #include "liburing.h"
12
+ #include "helpers.h"
13
+
14
+ #define NR_IOS 10000
15
+ #define INFLIGHT 256
16
+ #define FILE_SIZE (256 * 1024 * 1024)
17
+
18
+ static int inflight;
19
+
20
+ static int reap(struct io_uring *ring)
21
+ {
22
+ struct io_uring_cqe *cqe;
23
+ int ret;
24
+
25
+ while (inflight >= INFLIGHT / 2) {
26
+ ret = io_uring_wait_cqe(ring, &cqe);
27
+ if (ret < 0) {
28
+ fprintf(stderr, "wait=%d\n", ret);
29
+ return 1;
30
+ }
31
+ if (cqe->res < 0) {
32
+ printf("cqe res %d\n", cqe->res);
33
+ return 1;
34
+ }
35
+ io_uring_cqe_seen(ring, cqe);
36
+ inflight--;
37
+ }
38
+
39
+ return 0;
40
+ }
41
+
42
+ int main(int argc, char *argv[])
43
+ {
44
+ struct io_uring_sqe *sqe;
45
+ struct io_uring ring;
46
+ int fd = -1, i, iov_off, ret, fret;
47
+ struct iovec iovs[INFLIGHT];
48
+ const char *fname;
49
+ char buf[256];
50
+ loff_t off;
51
+
52
+ if (argc > 1) {
53
+ fname = argv[1];
54
+ } else {
55
+ srand((unsigned)time(NULL));
56
+ snprintf(buf, sizeof(buf), ".sqwait-%u-%u", (unsigned)rand(),
57
+ (unsigned)getpid());
58
+ fname = buf;
59
+ t_create_file(fname, FILE_SIZE);
60
+ }
61
+
62
+ fret = T_EXIT_SKIP;
63
+ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SQPOLL);
64
+ if (ret < 0) {
65
+ if (errno == EINVAL || errno == EPERM)
66
+ goto err;
67
+ fprintf(stderr, "queue init %d\n", ret);
68
+ fret = T_EXIT_FAIL;
69
+ goto err;
70
+ }
71
+
72
+ fd = open(fname, O_RDONLY | O_DIRECT);
73
+ if (fd < 0) {
74
+ if (errno == EACCES || errno == EPERM || errno == EINVAL)
75
+ return T_EXIT_SKIP;
76
+ perror("open");
77
+ fret = T_EXIT_FAIL;
78
+ goto err;
79
+ }
80
+
81
+ for (i = 0; i < INFLIGHT; i++) {
82
+ if (posix_memalign(&iovs[i].iov_base, 4096, 4096))
83
+ goto err;
84
+ iovs[i].iov_len = 4096;
85
+ }
86
+
87
+ iov_off = off = 0;
88
+ for (i = 0; i < NR_IOS; i++) {
89
+ struct iovec *iov = &iovs[iov_off];
90
+
91
+ sqe = io_uring_get_sqe(&ring);
92
+ if (!sqe) {
93
+ ret = io_uring_sqring_wait(&ring);
94
+ if (ret < 0) {
95
+ if (ret == -EINVAL)
96
+ return T_EXIT_SKIP;
97
+ fprintf(stderr, "sqwait=%d\n", ret);
98
+ fret = T_EXIT_FAIL;
99
+ goto err;
100
+ }
101
+ sqe = io_uring_get_sqe(&ring);
102
+ if (!sqe) {
103
+ fprintf(stderr, "No sqe post wait\n");
104
+ fret = T_EXIT_FAIL;
105
+ goto err;
106
+ }
107
+ }
108
+ io_uring_prep_read(sqe, fd, iov->iov_base, iov->iov_len, 0);
109
+ io_uring_submit(&ring);
110
+ inflight++;
111
+
112
+ iov_off++;
113
+ if (iov_off == INFLIGHT)
114
+ iov_off = 0;
115
+ off += 8192;
116
+ if (off > FILE_SIZE - 8192)
117
+ off = 0;
118
+ if (reap(&ring)) {
119
+ fret = T_EXIT_FAIL;
120
+ goto err;
121
+ }
122
+ }
123
+
124
+ if (fd != -1)
125
+ close(fd);
126
+ if (fname != argv[1])
127
+ unlink(fname);
128
+ io_uring_queue_exit(&ring);
129
+ return T_EXIT_PASS;
130
+ err:
131
+ if (fd != -1)
132
+ close(fd);
133
+ if (fname != argv[1])
134
+ unlink(fname);
135
+ return fret;
136
+ }
@@ -13,7 +13,7 @@
13
13
  #include "liburing.h"
14
14
  #include "helpers.h"
15
15
 
16
- static int no_sync_cancel;
16
+ static int no_sync_cancel, no_sync_cancel_op;
17
17
 
18
18
  static int test_sync_cancel_timeout(struct io_uring *ring, int async, int by_op)
19
19
  {
@@ -47,6 +47,11 @@ static int test_sync_cancel_timeout(struct io_uring *ring, int async, int by_op)
47
47
  reg.opcode = IORING_OP_READ;
48
48
  reg.timeout.tv_nsec = 1;
49
49
  ret = io_uring_register_sync_cancel(ring, &reg);
50
+ /* earlier kernels had sync cancel, but not per-op */
51
+ if (ret == -EINVAL) {
52
+ no_sync_cancel_op = 1;
53
+ return 0;
54
+ }
50
55
  if (async) {
51
56
  /* we expect -ETIME here, but can race and get 0 */
52
57
  if (ret != -ETIME && ret != 0) {
@@ -244,6 +249,8 @@ int main(int argc, char *argv[])
244
249
  fprintf(stderr, "test_sync_cancel_timeout 0 0\n");
245
250
  return T_EXIT_FAIL;
246
251
  }
252
+ if (no_sync_cancel_op)
253
+ return T_EXIT_PASS;
247
254
 
248
255
  ret = test_sync_cancel_timeout(&ring, 0, 1);
249
256
  if (ret) {
@@ -1228,14 +1228,19 @@ static int test_timeout_link_cancel(void)
1228
1228
  exit(0);
1229
1229
  }
1230
1230
 
1231
- if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
1232
- perror("waitpid()");
1233
- return 1;
1234
- }
1235
- if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) {
1236
- fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
1237
- return 1;
1238
- }
1231
+ do {
1232
+ if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
1233
+ perror("waitpid()");
1234
+ return 1;
1235
+ }
1236
+ if (!WIFEXITED(wstatus))
1237
+ continue;
1238
+ if (WEXITSTATUS(wstatus)) {
1239
+ fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
1240
+ return 1;
1241
+ }
1242
+ break;
1243
+ } while (1);
1239
1244
 
1240
1245
  for (i = 0; i < 2; ++i) {
1241
1246
  ret = io_uring_wait_cqe(&ring, &cqe);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uringmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-06 00:00:00.000000000 Z
11
+ date: 2024-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -84,22 +84,32 @@ files:
84
84
  - README.md
85
85
  - Rakefile
86
86
  - TODO.md
87
+ - examples/bm_snooze.rb
88
+ - examples/bm_write.rb
89
+ - examples/dns_client.rb
87
90
  - examples/echo_server.rb
88
91
  - examples/http_server.rb
89
- - examples/http_server_multishot.rb
90
- - examples/http_server_simpler.rb
91
92
  - examples/inout.rb
92
93
  - examples/nc.rb
94
+ - examples/server_client.rb
95
+ - examples/snooze.rb
96
+ - examples/write_dev_null.rb
93
97
  - ext/um/extconf.rb
94
98
  - ext/um/um.c
95
99
  - ext/um/um.h
100
+ - ext/um/um_buffer.c
96
101
  - ext/um/um_class.c
97
102
  - ext/um/um_const.c
98
103
  - ext/um/um_ext.c
104
+ - ext/um/um_mutex_class.c
99
105
  - ext/um/um_op.c
106
+ - ext/um/um_queue_class.c
107
+ - ext/um/um_sync.c
100
108
  - ext/um/um_utils.c
101
109
  - lib/uringmachine.rb
110
+ - lib/uringmachine/dns_resolver.rb
102
111
  - lib/uringmachine/version.rb
112
+ - supressions/ruby.supp
103
113
  - test/helper.rb
104
114
  - test/test_um.rb
105
115
  - uringmachine.gemspec
@@ -149,6 +159,7 @@ files:
149
159
  - vendor/liburing/examples/poll-bench.c
150
160
  - vendor/liburing/examples/proxy.c
151
161
  - vendor/liburing/examples/proxy.h
162
+ - vendor/liburing/examples/reg-wait.c
152
163
  - vendor/liburing/examples/rsrc-update-bench.c
153
164
  - vendor/liburing/examples/send-zerocopy.c
154
165
  - vendor/liburing/examples/ucontext-cp.c
@@ -207,6 +218,7 @@ files:
207
218
  - vendor/liburing/test/buf-ring.c
208
219
  - vendor/liburing/test/ce593a6c480a.c
209
220
  - vendor/liburing/test/close-opath.c
221
+ - vendor/liburing/test/cmd-discard.c
210
222
  - vendor/liburing/test/config
211
223
  - vendor/liburing/test/connect-rep.c
212
224
  - vendor/liburing/test/connect.c
@@ -239,6 +251,8 @@ files:
239
251
  - vendor/liburing/test/fd-install.c
240
252
  - vendor/liburing/test/fd-pass.c
241
253
  - vendor/liburing/test/fdinfo.c
254
+ - vendor/liburing/test/fifo-nonblock-read.c
255
+ - vendor/liburing/test/file-exit-unreg.c
242
256
  - vendor/liburing/test/file-register.c
243
257
  - vendor/liburing/test/file-update.c
244
258
  - vendor/liburing/test/file-verify.c
@@ -314,6 +328,7 @@ files:
314
328
  - vendor/liburing/test/probe.c
315
329
  - vendor/liburing/test/read-before-exit.c
316
330
  - vendor/liburing/test/read-mshot-empty.c
331
+ - vendor/liburing/test/read-mshot-stdin.c
317
332
  - vendor/liburing/test/read-mshot.c
318
333
  - vendor/liburing/test/read-write.c
319
334
  - vendor/liburing/test/recv-msgall-stream.c
@@ -324,10 +339,12 @@ files:
324
339
  - vendor/liburing/test/reg-fd-only.c
325
340
  - vendor/liburing/test/reg-hint.c
326
341
  - vendor/liburing/test/reg-reg-ring.c
342
+ - vendor/liburing/test/reg-wait.c
327
343
  - vendor/liburing/test/regbuf-clone.c
328
344
  - vendor/liburing/test/regbuf-merge.c
329
345
  - vendor/liburing/test/register-restrictions.c
330
346
  - vendor/liburing/test/rename.c
347
+ - vendor/liburing/test/resize-rings.c
331
348
  - vendor/liburing/test/ring-leak.c
332
349
  - vendor/liburing/test/ring-leak2.c
333
350
  - vendor/liburing/test/ringbuf-read.c
@@ -364,6 +381,7 @@ files:
364
381
  - vendor/liburing/test/sqpoll-exec.c
365
382
  - vendor/liburing/test/sqpoll-exit-hang.c
366
383
  - vendor/liburing/test/sqpoll-sleep.c
384
+ - vendor/liburing/test/sqwait.c
367
385
  - vendor/liburing/test/statx.c
368
386
  - vendor/liburing/test/stdout.c
369
387
  - vendor/liburing/test/submit-and-wait.c
@@ -1,57 +0,0 @@
1
- require_relative '../lib/iou'
2
- require 'socket'
3
- require 'http/parser'
4
-
5
- def log(msg)
6
- # return
7
- STDERR.puts msg
8
- end
9
-
10
- socket = TCPServer.open('127.0.0.1', 1234)
11
- log 'Listening on port 1234... (multishot read)'
12
-
13
- @ring = IOU::Ring.new
14
- @bg_id = @ring.setup_buffer_ring(count: 1024, size: 4096)
15
-
16
- @ring.prep_accept(fd: socket.fileno, multishot: true) do |c|
17
- setup_connection(c[:result]) if c[:result] > 0
18
- end
19
-
20
- def setup_connection(fd)
21
- log "Connection accepted fd #{fd}"
22
-
23
- parser = Http::Parser.new
24
- parser.on_message_complete = -> {
25
- http_send_response(fd, "Hello, world!\n")
26
- }
27
-
28
- http_prep_read(fd, parser)
29
- end
30
-
31
- def http_prep_read(fd, parser)
32
- id = @ring.prep_read(fd: fd, multishot: true, buffer_group: @bg_id) do |c|
33
- if c[:result] > 0
34
- parser << c[:buffer]
35
- elsif c[:result] == 0
36
- log "Connection closed by client on fd #{fd}"
37
- else
38
- if c[:result] != -Errno::ECANCELED::Errno
39
- log "Got error #{c[:result]} on fd #{fd}, closing connection..."
40
- end
41
- @ring.prep_close(fd: fd) do |c|
42
- log "Connection closed on fd #{fd}, result #{c[:result]}"
43
- end
44
- end
45
- rescue HTTP::Parser::Error
46
- puts "Error parsing, closing connection..."
47
- @ring.prep_cancel(id)
48
- end
49
- end
50
-
51
- def http_send_response(fd, body)
52
- msg = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: keep-alive\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}"
53
- @ring.prep_write(fd: fd, buffer: msg)
54
- end
55
-
56
- trap('SIGINT') { exit! }
57
- @ring.process_completions_loop
@@ -1,34 +0,0 @@
1
- require_relative '../lib/iou'
2
- require 'socket'
3
- require 'http/parser'
4
-
5
- socket = TCPServer.open('127.0.0.1', 1234)
6
- puts 'Listening on port 1234... (multishot read)'
7
-
8
- @ring = IOU::Ring.new
9
- @buffer_group = @ring.setup_buffer_ring(count: 1024, size: 4096)
10
-
11
- @ring.prep_accept(fd: socket.fileno, multishot: true) do |c|
12
- http_handle_connection(c[:result]) if c[:result] > 0
13
- end
14
-
15
- def http_handle_connection(fd)
16
- parser = Http::Parser.new
17
- parser.on_message_complete = -> { http_send_response(fd, "Hello, world!\n") }
18
-
19
- @ring.prep_read(fd: fd, multishot: true, buffer_group: @buffer_group) do |c|
20
- if c[:result] > 0
21
- parser << c[:buffer]
22
- else
23
- puts "Connection closed on fd #{fd}"
24
- end
25
- end
26
- end
27
-
28
- def http_send_response(fd, body)
29
- msg = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: keep-alive\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}"
30
- @ring.prep_write(fd: fd, buffer: msg)
31
- end
32
-
33
- trap('SIGINT') { exit! }
34
- @ring.process_completions_loop