uringmachine 0.4 → 0.5.1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +16 -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_sqlite.rb +89 -0
  8. data/examples/bm_write.rb +56 -0
  9. data/examples/dns_client.rb +12 -0
  10. data/examples/http_server.rb +42 -43
  11. data/examples/pg.rb +85 -0
  12. data/examples/server_client.rb +64 -0
  13. data/examples/snooze.rb +44 -0
  14. data/examples/stream.rb +85 -0
  15. data/examples/write_dev_null.rb +16 -0
  16. data/ext/um/extconf.rb +81 -14
  17. data/ext/um/um.c +468 -414
  18. data/ext/um/um.h +149 -40
  19. data/ext/um/um_async_op.c +40 -0
  20. data/ext/um/um_async_op_class.c +136 -0
  21. data/ext/um/um_buffer.c +49 -0
  22. data/ext/um/um_class.c +176 -44
  23. data/ext/um/um_const.c +174 -9
  24. data/ext/um/um_ext.c +8 -0
  25. data/ext/um/um_mutex_class.c +47 -0
  26. data/ext/um/um_op.c +89 -111
  27. data/ext/um/um_queue_class.c +58 -0
  28. data/ext/um/um_ssl.c +850 -0
  29. data/ext/um/um_ssl.h +22 -0
  30. data/ext/um/um_ssl_class.c +138 -0
  31. data/ext/um/um_sync.c +273 -0
  32. data/ext/um/um_utils.c +1 -1
  33. data/lib/uringmachine/dns_resolver.rb +84 -0
  34. data/lib/uringmachine/ssl/context_builder.rb +96 -0
  35. data/lib/uringmachine/ssl.rb +394 -0
  36. data/lib/uringmachine/version.rb +1 -1
  37. data/lib/uringmachine.rb +27 -3
  38. data/supressions/ruby.supp +71 -0
  39. data/test/helper.rb +6 -0
  40. data/test/test_async_op.rb +119 -0
  41. data/test/test_ssl.rb +155 -0
  42. data/test/test_um.rb +464 -47
  43. data/uringmachine.gemspec +3 -2
  44. data/vendor/liburing/.gitignore +5 -0
  45. data/vendor/liburing/CHANGELOG +1 -0
  46. data/vendor/liburing/configure +32 -0
  47. data/vendor/liburing/examples/Makefile +1 -0
  48. data/vendor/liburing/examples/reg-wait.c +159 -0
  49. data/vendor/liburing/liburing.spec +1 -1
  50. data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
  51. data/vendor/liburing/src/include/liburing.h +28 -2
  52. data/vendor/liburing/src/int_flags.h +10 -3
  53. data/vendor/liburing/src/liburing-ffi.map +13 -2
  54. data/vendor/liburing/src/liburing.map +9 -0
  55. data/vendor/liburing/src/queue.c +25 -16
  56. data/vendor/liburing/src/register.c +73 -4
  57. data/vendor/liburing/src/setup.c +46 -18
  58. data/vendor/liburing/src/setup.h +6 -0
  59. data/vendor/liburing/test/Makefile +7 -0
  60. data/vendor/liburing/test/cmd-discard.c +427 -0
  61. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  62. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  63. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  64. data/vendor/liburing/test/io_uring_register.c +13 -2
  65. data/vendor/liburing/test/napi-test.c +1 -1
  66. data/vendor/liburing/test/no-mmap-inval.c +1 -1
  67. data/vendor/liburing/test/read-mshot-empty.c +2 -0
  68. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  69. data/vendor/liburing/test/read-mshot.c +6 -0
  70. data/vendor/liburing/test/recvsend_bundle.c +2 -2
  71. data/vendor/liburing/test/reg-fd-only.c +1 -1
  72. data/vendor/liburing/test/reg-wait.c +251 -0
  73. data/vendor/liburing/test/regbuf-clone.c +458 -0
  74. data/vendor/liburing/test/resize-rings.c +643 -0
  75. data/vendor/liburing/test/rsrc_tags.c +1 -1
  76. data/vendor/liburing/test/sqpoll-sleep.c +39 -8
  77. data/vendor/liburing/test/sqwait.c +136 -0
  78. data/vendor/liburing/test/sync-cancel.c +8 -1
  79. data/vendor/liburing/test/timeout.c +13 -8
  80. metadata +52 -8
  81. data/examples/http_server_multishot.rb +0 -57
  82. 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.1
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-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2.7
19
+ version: 1.2.8
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2.7
26
+ version: 1.2.8
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 2.10.0
61
+ version: 2.14.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 2.10.0
68
+ version: 2.14.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: localhost
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.3.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.3.1
69
83
  description:
70
84
  email: sharon@noteflakes.com
71
85
  executables: []
@@ -84,23 +98,45 @@ files:
84
98
  - README.md
85
99
  - Rakefile
86
100
  - TODO.md
101
+ - examples/bm_snooze.rb
102
+ - examples/bm_sqlite.rb
103
+ - examples/bm_write.rb
104
+ - examples/dns_client.rb
87
105
  - examples/echo_server.rb
88
106
  - examples/http_server.rb
89
- - examples/http_server_multishot.rb
90
- - examples/http_server_simpler.rb
91
107
  - examples/inout.rb
92
108
  - examples/nc.rb
109
+ - examples/pg.rb
110
+ - examples/server_client.rb
111
+ - examples/snooze.rb
112
+ - examples/stream.rb
113
+ - examples/write_dev_null.rb
93
114
  - ext/um/extconf.rb
94
115
  - ext/um/um.c
95
116
  - ext/um/um.h
117
+ - ext/um/um_async_op.c
118
+ - ext/um/um_async_op_class.c
119
+ - ext/um/um_buffer.c
96
120
  - ext/um/um_class.c
97
121
  - ext/um/um_const.c
98
122
  - ext/um/um_ext.c
123
+ - ext/um/um_mutex_class.c
99
124
  - ext/um/um_op.c
125
+ - ext/um/um_queue_class.c
126
+ - ext/um/um_ssl.c
127
+ - ext/um/um_ssl.h
128
+ - ext/um/um_ssl_class.c
129
+ - ext/um/um_sync.c
100
130
  - ext/um/um_utils.c
101
131
  - lib/uringmachine.rb
132
+ - lib/uringmachine/dns_resolver.rb
133
+ - lib/uringmachine/ssl.rb
134
+ - lib/uringmachine/ssl/context_builder.rb
102
135
  - lib/uringmachine/version.rb
136
+ - supressions/ruby.supp
103
137
  - test/helper.rb
138
+ - test/test_async_op.rb
139
+ - test/test_ssl.rb
104
140
  - test/test_um.rb
105
141
  - uringmachine.gemspec
106
142
  - vendor/liburing/.github/actions/codespell/stopwords
@@ -149,6 +185,7 @@ files:
149
185
  - vendor/liburing/examples/poll-bench.c
150
186
  - vendor/liburing/examples/proxy.c
151
187
  - vendor/liburing/examples/proxy.h
188
+ - vendor/liburing/examples/reg-wait.c
152
189
  - vendor/liburing/examples/rsrc-update-bench.c
153
190
  - vendor/liburing/examples/send-zerocopy.c
154
191
  - vendor/liburing/examples/ucontext-cp.c
@@ -207,6 +244,7 @@ files:
207
244
  - vendor/liburing/test/buf-ring.c
208
245
  - vendor/liburing/test/ce593a6c480a.c
209
246
  - vendor/liburing/test/close-opath.c
247
+ - vendor/liburing/test/cmd-discard.c
210
248
  - vendor/liburing/test/config
211
249
  - vendor/liburing/test/connect-rep.c
212
250
  - vendor/liburing/test/connect.c
@@ -239,6 +277,8 @@ files:
239
277
  - vendor/liburing/test/fd-install.c
240
278
  - vendor/liburing/test/fd-pass.c
241
279
  - vendor/liburing/test/fdinfo.c
280
+ - vendor/liburing/test/fifo-nonblock-read.c
281
+ - vendor/liburing/test/file-exit-unreg.c
242
282
  - vendor/liburing/test/file-register.c
243
283
  - vendor/liburing/test/file-update.c
244
284
  - vendor/liburing/test/file-verify.c
@@ -314,6 +354,7 @@ files:
314
354
  - vendor/liburing/test/probe.c
315
355
  - vendor/liburing/test/read-before-exit.c
316
356
  - vendor/liburing/test/read-mshot-empty.c
357
+ - vendor/liburing/test/read-mshot-stdin.c
317
358
  - vendor/liburing/test/read-mshot.c
318
359
  - vendor/liburing/test/read-write.c
319
360
  - vendor/liburing/test/recv-msgall-stream.c
@@ -324,10 +365,12 @@ files:
324
365
  - vendor/liburing/test/reg-fd-only.c
325
366
  - vendor/liburing/test/reg-hint.c
326
367
  - vendor/liburing/test/reg-reg-ring.c
368
+ - vendor/liburing/test/reg-wait.c
327
369
  - vendor/liburing/test/regbuf-clone.c
328
370
  - vendor/liburing/test/regbuf-merge.c
329
371
  - vendor/liburing/test/register-restrictions.c
330
372
  - vendor/liburing/test/rename.c
373
+ - vendor/liburing/test/resize-rings.c
331
374
  - vendor/liburing/test/ring-leak.c
332
375
  - vendor/liburing/test/ring-leak2.c
333
376
  - vendor/liburing/test/ringbuf-read.c
@@ -364,6 +407,7 @@ files:
364
407
  - vendor/liburing/test/sqpoll-exec.c
365
408
  - vendor/liburing/test/sqpoll-exit-hang.c
366
409
  - vendor/liburing/test/sqpoll-sleep.c
410
+ - vendor/liburing/test/sqwait.c
367
411
  - vendor/liburing/test/statx.c
368
412
  - vendor/liburing/test/stdout.c
369
413
  - 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