uringmachine 0.2 → 0.4

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +85 -0
  4. data/TODO.md +5 -0
  5. data/examples/echo_server.rb +18 -40
  6. data/examples/inout.rb +19 -0
  7. data/examples/nc.rb +36 -0
  8. data/ext/um/extconf.rb +6 -15
  9. data/ext/um/um.c +340 -53
  10. data/ext/um/um.h +33 -11
  11. data/ext/um/um_class.c +101 -119
  12. data/ext/um/um_const.c +184 -0
  13. data/ext/um/um_op.c +39 -18
  14. data/ext/um/um_utils.c +48 -3
  15. data/lib/uringmachine/version.rb +1 -1
  16. data/lib/uringmachine.rb +12 -0
  17. data/test/helper.rb +13 -12
  18. data/test/test_um.rb +301 -3
  19. data/vendor/liburing/.github/workflows/build.yml +29 -1
  20. data/vendor/liburing/.gitignore +1 -0
  21. data/vendor/liburing/CHANGELOG +15 -0
  22. data/vendor/liburing/CONTRIBUTING.md +165 -0
  23. data/vendor/liburing/configure +32 -0
  24. data/vendor/liburing/examples/Makefile +8 -1
  25. data/vendor/liburing/examples/kdigest.c +405 -0
  26. data/vendor/liburing/examples/proxy.c +75 -8
  27. data/vendor/liburing/liburing.pc.in +1 -1
  28. data/vendor/liburing/src/Makefile +16 -2
  29. data/vendor/liburing/src/include/liburing/io_uring.h +31 -0
  30. data/vendor/liburing/src/include/liburing/sanitize.h +39 -0
  31. data/vendor/liburing/src/include/liburing.h +31 -4
  32. data/vendor/liburing/src/liburing-ffi.map +5 -0
  33. data/vendor/liburing/src/liburing.map +1 -0
  34. data/vendor/liburing/src/queue.c +3 -0
  35. data/vendor/liburing/src/register.c +36 -0
  36. data/vendor/liburing/src/sanitize.c +176 -0
  37. data/vendor/liburing/src/setup.c +1 -1
  38. data/vendor/liburing/test/35fa71a030ca.c +7 -0
  39. data/vendor/liburing/test/500f9fbadef8.c +2 -0
  40. data/vendor/liburing/test/7ad0e4b2f83c.c +0 -25
  41. data/vendor/liburing/test/917257daa0fe.c +7 -0
  42. data/vendor/liburing/test/Makefile +31 -4
  43. data/vendor/liburing/test/a0908ae19763.c +7 -0
  44. data/vendor/liburing/test/a4c0b3decb33.c +7 -0
  45. data/vendor/liburing/test/accept.c +14 -4
  46. data/vendor/liburing/test/b19062a56726.c +7 -0
  47. data/vendor/liburing/test/bind-listen.c +2 -2
  48. data/vendor/liburing/test/buf-ring-nommap.c +10 -3
  49. data/vendor/liburing/test/buf-ring.c +2 -0
  50. data/vendor/liburing/test/coredump.c +7 -0
  51. data/vendor/liburing/test/cq-overflow.c +13 -1
  52. data/vendor/liburing/test/d4ae271dfaae.c +11 -3
  53. data/vendor/liburing/test/defer-taskrun.c +2 -2
  54. data/vendor/liburing/test/defer-tw-timeout.c +4 -1
  55. data/vendor/liburing/test/defer.c +2 -2
  56. data/vendor/liburing/test/double-poll-crash.c +1 -1
  57. data/vendor/liburing/test/eeed8b54e0df.c +2 -0
  58. data/vendor/liburing/test/eventfd.c +0 -1
  59. data/vendor/liburing/test/exit-no-cleanup.c +11 -0
  60. data/vendor/liburing/test/fadvise.c +9 -26
  61. data/vendor/liburing/test/fdinfo.c +9 -1
  62. data/vendor/liburing/test/file-register.c +14 -2
  63. data/vendor/liburing/test/file-update.c +1 -1
  64. data/vendor/liburing/test/file-verify.c +27 -16
  65. data/vendor/liburing/test/files-exit-hang-timeout.c +1 -2
  66. data/vendor/liburing/test/fixed-buf-iter.c +3 -1
  67. data/vendor/liburing/test/fixed-hugepage.c +12 -1
  68. data/vendor/liburing/test/fsnotify.c +1 -0
  69. data/vendor/liburing/test/futex.c +16 -4
  70. data/vendor/liburing/test/helpers.c +47 -0
  71. data/vendor/liburing/test/helpers.h +6 -0
  72. data/vendor/liburing/test/init-mem.c +5 -3
  73. data/vendor/liburing/test/io-cancel.c +0 -24
  74. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  75. data/vendor/liburing/test/io_uring_register.c +25 -6
  76. data/vendor/liburing/test/iopoll-leak.c +4 -0
  77. data/vendor/liburing/test/iopoll-overflow.c +1 -1
  78. data/vendor/liburing/test/iopoll.c +3 -3
  79. data/vendor/liburing/test/kallsyms.c +203 -0
  80. data/vendor/liburing/test/link-timeout.c +159 -0
  81. data/vendor/liburing/test/linked-defer-close.c +224 -0
  82. data/vendor/liburing/test/madvise.c +12 -25
  83. data/vendor/liburing/test/min-timeout-wait.c +0 -25
  84. data/vendor/liburing/test/min-timeout.c +0 -25
  85. data/vendor/liburing/test/mkdir.c +6 -0
  86. data/vendor/liburing/test/msg-ring.c +8 -2
  87. data/vendor/liburing/test/napi-test.c +15 -2
  88. data/vendor/liburing/test/no-mmap-inval.c +2 -0
  89. data/vendor/liburing/test/nop.c +44 -0
  90. data/vendor/liburing/test/ooo-file-unreg.c +1 -1
  91. data/vendor/liburing/test/open-close.c +40 -0
  92. data/vendor/liburing/test/openat2.c +37 -14
  93. data/vendor/liburing/test/poll-many.c +13 -7
  94. data/vendor/liburing/test/poll-mshot-update.c +17 -10
  95. data/vendor/liburing/test/poll-v-poll.c +6 -3
  96. data/vendor/liburing/test/pollfree.c +148 -0
  97. data/vendor/liburing/test/read-mshot-empty.c +156 -153
  98. data/vendor/liburing/test/read-mshot.c +276 -27
  99. data/vendor/liburing/test/read-write.c +78 -13
  100. data/vendor/liburing/test/recv-msgall-stream.c +3 -0
  101. data/vendor/liburing/test/recv-msgall.c +5 -0
  102. data/vendor/liburing/test/recvsend_bundle-inc.c +680 -0
  103. data/vendor/liburing/test/recvsend_bundle.c +92 -29
  104. data/vendor/liburing/test/reg-fd-only.c +14 -4
  105. data/vendor/liburing/test/regbuf-clone.c +187 -0
  106. data/vendor/liburing/test/regbuf-merge.c +7 -0
  107. data/vendor/liburing/test/register-restrictions.c +86 -85
  108. data/vendor/liburing/test/rename.c +59 -1
  109. data/vendor/liburing/test/ringbuf-read.c +5 -0
  110. data/vendor/liburing/test/ringbuf-status.c +5 -1
  111. data/vendor/liburing/test/runtests.sh +16 -1
  112. data/vendor/liburing/test/send-zerocopy.c +59 -0
  113. data/vendor/liburing/test/short-read.c +1 -0
  114. data/vendor/liburing/test/socket.c +43 -0
  115. data/vendor/liburing/test/splice.c +3 -1
  116. data/vendor/liburing/test/sq-poll-dup.c +1 -1
  117. data/vendor/liburing/test/sq-poll-share.c +2 -0
  118. data/vendor/liburing/test/sqpoll-disable-exit.c +8 -0
  119. data/vendor/liburing/test/sqpoll-exit-hang.c +1 -25
  120. data/vendor/liburing/test/sqpoll-sleep.c +1 -25
  121. data/vendor/liburing/test/statx.c +89 -0
  122. data/vendor/liburing/test/stdout.c +2 -0
  123. data/vendor/liburing/test/submit-and-wait.c +1 -25
  124. data/vendor/liburing/test/submit-reuse.c +4 -26
  125. data/vendor/liburing/test/symlink.c +12 -1
  126. data/vendor/liburing/test/sync-cancel.c +48 -21
  127. data/vendor/liburing/test/thread-exit.c +5 -0
  128. data/vendor/liburing/test/timeout-new.c +1 -26
  129. data/vendor/liburing/test/timeout.c +12 -26
  130. data/vendor/liburing/test/unlink.c +94 -1
  131. data/vendor/liburing/test/uring_cmd_ublk.c +1252 -0
  132. data/vendor/liburing/test/waitid.c +62 -8
  133. data/vendor/liburing/test/wq-aff.c +35 -0
  134. data/vendor/liburing/test/xfail_prep_link_timeout_out_of_scope.c +46 -0
  135. data/vendor/liburing/test/xfail_register_buffers_out_of_scope.c +51 -0
  136. metadata +17 -4
  137. data/examples/event_loop.rb +0 -69
  138. data/examples/fibers.rb +0 -105
data/ext/um/um_class.c CHANGED
@@ -1,5 +1,5 @@
1
1
  #include "um.h"
2
- #include <sys/mman.h>
2
+ #include <arpa/inet.h>
3
3
 
4
4
  VALUE cUM;
5
5
 
@@ -14,7 +14,7 @@ static void UM_compact(void *ptr) {
14
14
  }
15
15
 
16
16
  static void UM_free(void *ptr) {
17
- um_cleanup((struct um *)ptr);
17
+ um_teardown((struct um *)ptr);
18
18
  free(ptr);
19
19
  }
20
20
 
@@ -43,90 +43,16 @@ inline struct um *get_machine(VALUE self) {
43
43
 
44
44
  VALUE UM_initialize(VALUE self) {
45
45
  struct um *machine = RTYPEDDATA_DATA(self);
46
-
47
- machine->ring_initialized = 0;
48
- machine->unsubmitted_count = 0;
49
- machine->buffer_ring_count = 0;
50
- machine->pending_count = 0;
51
- machine->runqueue_head = NULL;
52
- machine->runqueue_tail = NULL;
53
- machine->freelist_head = NULL;
54
-
55
- unsigned prepared_limit = 4096;
56
- int flags = 0;
57
- #ifdef HAVE_IORING_SETUP_SUBMIT_ALL
58
- flags |= IORING_SETUP_SUBMIT_ALL;
59
- #endif
60
- #ifdef HAVE_IORING_SETUP_COOP_TASKRUN
61
- flags |= IORING_SETUP_COOP_TASKRUN;
62
- #endif
63
-
64
- while (1) {
65
- int ret = io_uring_queue_init(prepared_limit, &machine->ring, flags);
66
- if (likely(!ret)) break;
67
-
68
- // if ENOMEM is returned, try with half as much entries
69
- if (unlikely(ret == -ENOMEM && prepared_limit > 64))
70
- prepared_limit = prepared_limit / 2;
71
- else
72
- rb_syserr_fail(-ret, strerror(-ret));
73
- }
74
- machine->ring_initialized = 1;
75
-
46
+ um_setup(machine);
76
47
  return self;
77
48
  }
78
49
 
79
50
  VALUE UM_setup_buffer_ring(VALUE self, VALUE size, VALUE count) {
80
51
  struct um *machine = get_machine(self);
81
-
82
- if (machine->buffer_ring_count == BUFFER_RING_MAX_COUNT)
83
- rb_raise(rb_eRuntimeError, "Cannot setup more than BUFFER_RING_MAX_COUNT buffer rings");
84
-
85
- struct buf_ring_descriptor *desc = machine->buffer_rings + machine->buffer_ring_count;
86
- desc->buf_count = NUM2UINT(count);
87
- desc->buf_size = NUM2UINT(size);
88
-
89
- desc->br_size = sizeof(struct io_uring_buf) * desc->buf_count;
90
- void *mapped = mmap(
91
- NULL, desc->br_size, PROT_READ | PROT_WRITE,
92
- MAP_ANONYMOUS | MAP_PRIVATE, 0, 0
93
- );
94
- if (mapped == MAP_FAILED)
95
- rb_raise(rb_eRuntimeError, "Failed to allocate buffer ring");
96
-
97
- desc->br = (struct io_uring_buf_ring *)mapped;
98
- io_uring_buf_ring_init(desc->br);
99
-
100
- unsigned bg_id = machine->buffer_ring_count;
101
- struct io_uring_buf_reg reg = {
102
- .ring_addr = (unsigned long)desc->br,
103
- .ring_entries = desc->buf_count,
104
- .bgid = bg_id
105
- };
106
- int ret = io_uring_register_buf_ring(&machine->ring, &reg, 0);
107
- if (ret) {
108
- munmap(desc->br, desc->br_size);
109
- rb_syserr_fail(-ret, strerror(-ret));
110
- }
111
-
112
- desc->buf_base = malloc(desc->buf_count * desc->buf_size);
113
- if (!desc->buf_base) {
114
- io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, bg_id);
115
- rb_raise(rb_eRuntimeError, "Failed to allocate buffers");
116
- }
117
-
118
- int mask = io_uring_buf_ring_mask(desc->buf_count);
119
- for (unsigned i = 0; i < desc->buf_count; i++) {
120
- io_uring_buf_ring_add(
121
- desc->br, desc->buf_base + i * desc->buf_size, desc->buf_size,
122
- i, mask, i);
123
- }
124
- io_uring_buf_ring_advance(desc->br, desc->buf_count);
125
- machine->buffer_ring_count++;
126
- return UINT2NUM(bg_id);
52
+ int bgid = um_setup_buffer_ring(machine, NUM2UINT(size), NUM2UINT(count));
53
+ return INT2NUM(bgid);
127
54
  }
128
55
 
129
-
130
56
  VALUE UM_pending_count(VALUE self) {
131
57
  struct um *machine = get_machine(self);
132
58
  return INT2FIX(machine->pending_count);
@@ -185,6 +111,89 @@ VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
185
111
  return um_read_each(machine, NUM2INT(fd), NUM2INT(bgid));
186
112
  }
187
113
 
114
+ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
115
+ struct um *machine = get_machine(self);
116
+ VALUE fd;
117
+ VALUE buffer;
118
+ VALUE len;
119
+ rb_scan_args(argc, argv, "21", &fd, &buffer, &len);
120
+
121
+ int bytes = NIL_P(len) ? RSTRING_LEN(buffer) : NUM2INT(len);
122
+ return um_write(machine, NUM2INT(fd), buffer, bytes);
123
+ }
124
+
125
+ VALUE UM_close(VALUE self, VALUE fd) {
126
+ struct um *machine = get_machine(self);
127
+ return um_close(machine, NUM2INT(fd));
128
+ }
129
+
130
+ VALUE UM_accept(VALUE self, VALUE fd) {
131
+ struct um *machine = get_machine(self);
132
+ return um_accept(machine, NUM2INT(fd));
133
+ }
134
+
135
+ VALUE UM_accept_each(VALUE self, VALUE fd) {
136
+ struct um *machine = get_machine(self);
137
+ return um_accept_each(machine, NUM2INT(fd));
138
+ }
139
+
140
+ VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flags) {
141
+ struct um *machine = get_machine(self);
142
+ return um_socket(machine, NUM2INT(domain), NUM2INT(type), NUM2INT(protocol), NUM2UINT(flags));
143
+ }
144
+
145
+ VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
146
+ struct um *machine = get_machine(self);
147
+
148
+ struct sockaddr_in addr;
149
+ memset(&addr, 0, sizeof(addr));
150
+ addr.sin_family = AF_INET;
151
+ addr.sin_addr.s_addr = inet_addr(StringValueCStr(host));
152
+ addr.sin_port = htons(NUM2INT(port));
153
+
154
+ return um_connect(machine, NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
155
+ }
156
+
157
+ VALUE UM_send(VALUE self, VALUE fd, VALUE buffer, VALUE len, VALUE flags) {
158
+ struct um *machine = get_machine(self);
159
+ return um_send(machine, NUM2INT(fd), buffer, NUM2INT(len), NUM2INT(flags));
160
+ }
161
+
162
+ VALUE UM_recv(VALUE self, VALUE fd, VALUE buffer, VALUE maxlen, VALUE flags) {
163
+ struct um *machine = get_machine(self);
164
+ return um_recv(machine, NUM2INT(fd), buffer, NUM2INT(maxlen), NUM2INT(flags));
165
+ }
166
+
167
+ VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) {
168
+ struct sockaddr_in addr;
169
+ memset(&addr, 0, sizeof(addr));
170
+ addr.sin_family = AF_INET;
171
+ addr.sin_addr.s_addr = inet_addr(StringValueCStr(host));
172
+ addr.sin_port = htons(NUM2INT(port));
173
+
174
+ #ifdef HAVE_IO_URING_PREP_BIND
175
+ struct um *machine = get_machine(self);
176
+ return um_bind(machine, NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
177
+ #else
178
+ int res = bind(NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
179
+ if (res)
180
+ rb_syserr_fail(errno, strerror(errno));
181
+ return INT2NUM(0);
182
+ #endif
183
+ }
184
+
185
+ VALUE UM_listen(VALUE self, VALUE fd, VALUE backlog) {
186
+ #ifdef HAVE_IO_URING_PREP_LISTEN
187
+ struct um *machine = get_machine(self);
188
+ return um_listen(machine, NUM2INT(fd), NUM2INT(backlog));
189
+ #else
190
+ int res = listen(NUM2INT(fd), NUM2INT(backlog));
191
+ if (res)
192
+ rb_syserr_fail(errno, strerror(errno));
193
+ return INT2NUM(0);
194
+ #endif
195
+ }
196
+
188
197
  void Init_UM(void) {
189
198
  rb_ext_ractor_safe(true);
190
199
 
@@ -204,44 +213,17 @@ void Init_UM(void) {
204
213
  rb_define_method(cUM, "sleep", UM_sleep, 1);
205
214
  rb_define_method(cUM, "read", UM_read, -1);
206
215
  rb_define_method(cUM, "read_each", UM_read_each, 2);
207
-
208
- // rb_define_method(cUM, "emit", UM_emit, 1);
209
-
210
- // rb_define_method(cUM, "prep_accept", UM_prep_accept, 1);
211
- // rb_define_method(cUM, "prep_cancel", UM_prep_cancel, 1);
212
- // rb_define_method(cUM, "prep_close", UM_prep_close, 1);
213
- // rb_define_method(cUM, "prep_nop", UM_prep_nop, 0);
214
- // rb_define_method(cUM, "prep_read", UM_prep_read, 1);
215
- // rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
216
- // rb_define_method(cUM, "prep_write", UM_prep_write, 1);
217
-
218
- // rb_define_method(cUM, "submit", UM_submit, 0);
219
- // rb_define_method(cUM, "wait_for_completion", UM_wait_for_completion, 0);
220
- // rb_define_method(cUM, "process_completions", UM_process_completions, -1);
221
- // rb_define_method(cUM, "process_completions_loop", UM_process_completions_loop, 0);
222
-
223
- // SYM_accept = MAKE_SYM("accept");
224
- // SYM_block = MAKE_SYM("block");
225
- // SYM_buffer = MAKE_SYM("buffer");
226
- // SYM_buffer_group = MAKE_SYM("buffer_group");
227
- // SYM_buffer_offset = MAKE_SYM("buffer_offset");
228
- // SYM_close = MAKE_SYM("close");
229
- // SYM_count = MAKE_SYM("count");
230
- // SYM_emit = MAKE_SYM("emit");
231
- // SYM_fd = MAKE_SYM("fd");
232
- // SYM_id = MAKE_SYM("id");
233
- // SYM_interval = MAKE_SYM("interval");
234
- // SYM_len = MAKE_SYM("len");
235
- // SYM_link = MAKE_SYM("link");
236
- // SYM_multishot = MAKE_SYM("multishot");
237
- // SYM_op = MAKE_SYM("op");
238
- // SYM_read = MAKE_SYM("read");
239
- // SYM_result = MAKE_SYM("result");
240
- // SYM_signal = MAKE_SYM("signal");
241
- // SYM_size = MAKE_SYM("size");
242
- // SYM_spec_data = MAKE_SYM("spec_data");
243
- // SYM_stop = MAKE_SYM("stop");
244
- // SYM_timeout = MAKE_SYM("timeout");
245
- // SYM_utf8 = MAKE_SYM("utf8");
246
- // SYM_write = MAKE_SYM("write");
216
+ rb_define_method(cUM, "write", UM_write, -1);
217
+ rb_define_method(cUM, "close", UM_close, 1);
218
+
219
+ rb_define_method(cUM, "accept", UM_accept, 1);
220
+ rb_define_method(cUM, "accept_each", UM_accept_each, 1);
221
+ rb_define_method(cUM, "socket", UM_socket, 4);
222
+ rb_define_method(cUM, "connect", UM_connect, 3);
223
+ rb_define_method(cUM, "send", UM_send, 4);
224
+ rb_define_method(cUM, "recv", UM_recv, 4);
225
+ rb_define_method(cUM, "bind", UM_bind, 3);
226
+ rb_define_method(cUM, "listen", UM_listen, 2);
227
+
228
+ um_define_net_constants(cUM);
247
229
  }
data/ext/um/um_const.c ADDED
@@ -0,0 +1,184 @@
1
+ #include "ruby.h"
2
+ #include <arpa/inet.h>
3
+ #include <sys/types.h>
4
+ #include <sys/socket.h>
5
+ #include <netinet/in.h>
6
+ #include <netinet/tcp.h>
7
+ #include <netinet/udp.h>
8
+ #include <netdb.h>
9
+ #include <net/if.h>
10
+
11
+
12
+ #define DEF_CONST_INT(mod, v) rb_define_const(mod, #v, INT2NUM(v))
13
+
14
+ void um_define_net_constants(VALUE mod) {
15
+ DEF_CONST_INT(mod, SOCK_STREAM);
16
+ DEF_CONST_INT(mod, SOCK_DGRAM);
17
+ DEF_CONST_INT(mod, SOCK_RAW);
18
+ DEF_CONST_INT(mod, SOCK_RDM);
19
+ DEF_CONST_INT(mod, SOCK_SEQPACKET);
20
+ DEF_CONST_INT(mod, SOCK_PACKET);
21
+ DEF_CONST_INT(mod, SOCK_CLOEXEC);
22
+
23
+ DEF_CONST_INT(mod, AF_UNSPEC);
24
+ DEF_CONST_INT(mod, PF_UNSPEC);
25
+ DEF_CONST_INT(mod, AF_INET);
26
+ DEF_CONST_INT(mod, PF_INET);
27
+ DEF_CONST_INT(mod, AF_INET6);
28
+ DEF_CONST_INT(mod, PF_INET6);
29
+ DEF_CONST_INT(mod, AF_UNIX);
30
+ DEF_CONST_INT(mod, PF_UNIX);
31
+ DEF_CONST_INT(mod, AF_LOCAL);
32
+ DEF_CONST_INT(mod, PF_LOCAL);
33
+ DEF_CONST_INT(mod, AF_ROUTE);
34
+ DEF_CONST_INT(mod, PF_ROUTE);
35
+ DEF_CONST_INT(mod, AF_MAX);
36
+ DEF_CONST_INT(mod, PF_MAX);
37
+
38
+ DEF_CONST_INT(mod, MSG_OOB);
39
+ DEF_CONST_INT(mod, MSG_PEEK);
40
+ DEF_CONST_INT(mod, MSG_DONTROUTE);
41
+ DEF_CONST_INT(mod, MSG_WAITALL);
42
+ DEF_CONST_INT(mod, MSG_DONTWAIT);
43
+ DEF_CONST_INT(mod, MSG_MORE);
44
+
45
+ DEF_CONST_INT(mod, SOL_SOCKET);
46
+ DEF_CONST_INT(mod, SOL_IP);
47
+
48
+ DEF_CONST_INT(mod, IPPROTO_IP);
49
+ DEF_CONST_INT(mod, IPPROTO_ICMP);
50
+ DEF_CONST_INT(mod, IPPROTO_IGMP);
51
+ DEF_CONST_INT(mod, IPPROTO_TCP);
52
+ DEF_CONST_INT(mod, IPPROTO_EGP);
53
+ DEF_CONST_INT(mod, IPPROTO_PUP);
54
+ DEF_CONST_INT(mod, IPPROTO_UDP);
55
+ DEF_CONST_INT(mod, IPPROTO_IDP);
56
+ DEF_CONST_INT(mod, IPPROTO_IPV6);
57
+ DEF_CONST_INT(mod, IPPROTO_NONE);
58
+ DEF_CONST_INT(mod, IPPROTO_ROUTING);
59
+ DEF_CONST_INT(mod, IPPROTO_RAW);
60
+ DEF_CONST_INT(mod, IPPROTO_MAX);
61
+
62
+ DEF_CONST_INT(mod, INADDR_ANY);
63
+ DEF_CONST_INT(mod, INADDR_BROADCAST);
64
+ DEF_CONST_INT(mod, INADDR_LOOPBACK);
65
+ DEF_CONST_INT(mod, INADDR_NONE);
66
+
67
+ DEF_CONST_INT(mod, IP_OPTIONS);
68
+ DEF_CONST_INT(mod, IP_HDRINCL);
69
+ DEF_CONST_INT(mod, IP_TOS);
70
+ DEF_CONST_INT(mod, IP_TTL);
71
+ DEF_CONST_INT(mod, IP_RECVOPTS);
72
+ DEF_CONST_INT(mod, IP_MINTTL);
73
+ DEF_CONST_INT(mod, IP_RECVTTL);
74
+
75
+ DEF_CONST_INT(mod, SO_DEBUG);
76
+ DEF_CONST_INT(mod, SO_REUSEADDR);
77
+ DEF_CONST_INT(mod, SO_REUSEPORT);
78
+ DEF_CONST_INT(mod, SO_TYPE);
79
+ DEF_CONST_INT(mod, SO_ERROR);
80
+ DEF_CONST_INT(mod, SO_DONTROUTE);
81
+ DEF_CONST_INT(mod, SO_BROADCAST);
82
+ DEF_CONST_INT(mod, SO_SNDBUF);
83
+ DEF_CONST_INT(mod, SO_RCVBUF);
84
+ DEF_CONST_INT(mod, SO_SNDBUFFORCE);
85
+ DEF_CONST_INT(mod, SO_RCVBUFFORCE);
86
+ DEF_CONST_INT(mod, SO_KEEPALIVE);
87
+ DEF_CONST_INT(mod, SO_OOBINLINE);
88
+ DEF_CONST_INT(mod, SO_PRIORITY);
89
+ DEF_CONST_INT(mod, SO_LINGER);
90
+ DEF_CONST_INT(mod, SO_PASSCRED);
91
+ DEF_CONST_INT(mod, SO_PEERCRED);
92
+ DEF_CONST_INT(mod, SO_RCVLOWAT);
93
+ DEF_CONST_INT(mod, SO_SNDLOWAT);
94
+ DEF_CONST_INT(mod, SO_RCVTIMEO);
95
+ DEF_CONST_INT(mod, SO_SNDTIMEO);
96
+ DEF_CONST_INT(mod, SO_ACCEPTCONN);
97
+ DEF_CONST_INT(mod, SO_PEERNAME);
98
+ DEF_CONST_INT(mod, SO_TIMESTAMP);
99
+ DEF_CONST_INT(mod, SO_MARK);
100
+ DEF_CONST_INT(mod, SO_PROTOCOL);
101
+ DEF_CONST_INT(mod, SO_DOMAIN);
102
+ DEF_CONST_INT(mod, SO_PEEK_OFF);
103
+ DEF_CONST_INT(mod, SO_BUSY_POLL);
104
+
105
+ DEF_CONST_INT(mod, TCP_NODELAY);
106
+ DEF_CONST_INT(mod, TCP_MAXSEG);
107
+ DEF_CONST_INT(mod, TCP_CORK);
108
+ DEF_CONST_INT(mod, TCP_DEFER_ACCEPT);
109
+ DEF_CONST_INT(mod, TCP_INFO);
110
+ DEF_CONST_INT(mod, TCP_KEEPCNT);
111
+ DEF_CONST_INT(mod, TCP_KEEPIDLE);
112
+ DEF_CONST_INT(mod, TCP_KEEPINTVL);
113
+ DEF_CONST_INT(mod, TCP_LINGER2);
114
+ DEF_CONST_INT(mod, TCP_MD5SIG);
115
+ DEF_CONST_INT(mod, TCP_QUICKACK);
116
+ DEF_CONST_INT(mod, TCP_SYNCNT);
117
+ DEF_CONST_INT(mod, TCP_WINDOW_CLAMP);
118
+ DEF_CONST_INT(mod, TCP_FASTOPEN);
119
+ DEF_CONST_INT(mod, TCP_CONGESTION);
120
+ DEF_CONST_INT(mod, TCP_COOKIE_TRANSACTIONS);
121
+ DEF_CONST_INT(mod, TCP_QUEUE_SEQ);
122
+ DEF_CONST_INT(mod, TCP_REPAIR);
123
+ DEF_CONST_INT(mod, TCP_REPAIR_OPTIONS);
124
+ DEF_CONST_INT(mod, TCP_REPAIR_QUEUE);
125
+ DEF_CONST_INT(mod, TCP_THIN_LINEAR_TIMEOUTS);
126
+ DEF_CONST_INT(mod, TCP_TIMESTAMP);
127
+ DEF_CONST_INT(mod, TCP_USER_TIMEOUT);
128
+
129
+ DEF_CONST_INT(mod, UDP_CORK);
130
+
131
+ DEF_CONST_INT(mod, AI_PASSIVE);
132
+ DEF_CONST_INT(mod, AI_CANONNAME);
133
+ DEF_CONST_INT(mod, AI_NUMERICHOST);
134
+ DEF_CONST_INT(mod, AI_NUMERICSERV);
135
+ DEF_CONST_INT(mod, AI_ALL);
136
+ DEF_CONST_INT(mod, AI_ADDRCONFIG);
137
+ DEF_CONST_INT(mod, AI_V4MAPPED);
138
+
139
+ DEF_CONST_INT(mod, NI_MAXHOST);
140
+ DEF_CONST_INT(mod, NI_MAXSERV);
141
+ DEF_CONST_INT(mod, NI_NOFQDN);
142
+ DEF_CONST_INT(mod, NI_NUMERICHOST);
143
+ DEF_CONST_INT(mod, NI_NAMEREQD);
144
+ DEF_CONST_INT(mod, NI_NUMERICSERV);
145
+ DEF_CONST_INT(mod, NI_DGRAM);
146
+
147
+ DEF_CONST_INT(mod, SHUT_RD);
148
+ DEF_CONST_INT(mod, SHUT_WR);
149
+ DEF_CONST_INT(mod, SHUT_RDWR);
150
+
151
+ DEF_CONST_INT(mod, IPV6_JOIN_GROUP);
152
+ DEF_CONST_INT(mod, IPV6_LEAVE_GROUP);
153
+ DEF_CONST_INT(mod, IPV6_MULTICAST_HOPS);
154
+ DEF_CONST_INT(mod, IPV6_MULTICAST_IF);
155
+ DEF_CONST_INT(mod, IPV6_MULTICAST_LOOP);
156
+ DEF_CONST_INT(mod, IPV6_UNICAST_HOPS);
157
+ DEF_CONST_INT(mod, IPV6_V6ONLY);
158
+ DEF_CONST_INT(mod, IPV6_CHECKSUM);
159
+ DEF_CONST_INT(mod, IPV6_DONTFRAG);
160
+ DEF_CONST_INT(mod, IPV6_DSTOPTS);
161
+ DEF_CONST_INT(mod, IPV6_HOPLIMIT);
162
+ DEF_CONST_INT(mod, IPV6_HOPOPTS);
163
+ DEF_CONST_INT(mod, IPV6_NEXTHOP);
164
+ DEF_CONST_INT(mod, IPV6_PATHMTU);
165
+ DEF_CONST_INT(mod, IPV6_PKTINFO);
166
+ DEF_CONST_INT(mod, IPV6_RECVDSTOPTS);
167
+ DEF_CONST_INT(mod, IPV6_RECVHOPLIMIT);
168
+ DEF_CONST_INT(mod, IPV6_RECVHOPOPTS);
169
+ DEF_CONST_INT(mod, IPV6_RECVPKTINFO);
170
+ DEF_CONST_INT(mod, IPV6_RECVRTHDR);
171
+ DEF_CONST_INT(mod, IPV6_RECVTCLASS);
172
+ DEF_CONST_INT(mod, IPV6_RTHDR);
173
+ DEF_CONST_INT(mod, IPV6_RTHDRDSTOPTS);
174
+ DEF_CONST_INT(mod, IPV6_RTHDR_TYPE_0);
175
+ DEF_CONST_INT(mod, IPV6_RECVPATHMTU);
176
+ DEF_CONST_INT(mod, IPV6_TCLASS);
177
+
178
+ DEF_CONST_INT(mod, INET_ADDRSTRLEN);
179
+ DEF_CONST_INT(mod, INET6_ADDRSTRLEN);
180
+
181
+ DEF_CONST_INT(mod, IF_NAMESIZE);
182
+
183
+ DEF_CONST_INT(mod, SOMAXCONN);
184
+ }
data/ext/um/um_op.c CHANGED
@@ -1,17 +1,33 @@
1
1
  #include "um.h"
2
2
 
3
+ inline struct um_result_entry *um_result_checkout(struct um *machine) {
4
+ if (machine->result_freelist) {
5
+ struct um_result_entry *entry = machine->result_freelist;
6
+ machine->result_freelist = entry->next;
7
+ return entry;
8
+ }
9
+
10
+ struct um_result_entry *entry = malloc(sizeof(struct um_result_entry));
11
+ return entry;
12
+ }
13
+
14
+ inline void um_result_checkin(struct um *machine, struct um_result_entry *entry) {
15
+ entry->next = machine->result_freelist;
16
+ machine->result_freelist = entry;
17
+ }
18
+
3
19
  inline void um_op_result_cleanup(struct um *machine, struct um_op *op) {
4
20
  struct um_result_entry *entry = op->results_head;
5
21
  while (entry) {
6
22
  struct um_result_entry *next = entry->next;
7
- free(entry);
23
+ um_result_checkin(machine, entry);
8
24
  entry = next;
9
25
  }
10
26
  op->results_head = op->results_tail = NULL;
11
27
  }
12
28
 
13
- inline void um_op_result_push(struct um *machine, struct um_op *op, int result, int flags) {
14
- struct um_result_entry *entry = malloc(sizeof(struct um_result_entry));
29
+ inline void um_op_result_push(struct um *machine, struct um_op *op, __s32 result, __u32 flags) {
30
+ struct um_result_entry *entry = um_result_checkout(machine);
15
31
  entry->next = 0;
16
32
  entry->result = result;
17
33
  entry->flags = flags;
@@ -24,7 +40,7 @@ inline void um_op_result_push(struct um *machine, struct um_op *op, int result,
24
40
  }
25
41
  }
26
42
 
27
- inline int um_op_result_shift(struct um *machine, struct um_op *op, int *result, int *flags) {
43
+ inline int um_op_result_shift(struct um *machine, struct um_op *op, __s32 *result, __u32 *flags) {
28
44
  if (!op->results_head) return 0;
29
45
 
30
46
  struct um_result_entry *entry = op->results_head;
@@ -33,7 +49,7 @@ inline int um_op_result_shift(struct um *machine, struct um_op *op, int *result,
33
49
  op->results_head = entry->next;
34
50
  if (!op->results_head)
35
51
  op->results_tail = NULL;
36
- free(entry);
52
+ um_result_checkin(machine, entry);
37
53
  return 1;
38
54
  }
39
55
 
@@ -45,25 +61,22 @@ inline void um_op_clear(struct um_op *op) {
45
61
  inline struct um_op *um_op_checkout(struct um *machine) {
46
62
  machine->pending_count++;
47
63
 
48
- if (machine->freelist_head) {
49
- struct um_op *op = machine->freelist_head;
50
- machine->freelist_head = op->next;
51
- um_op_clear(op);
52
- return op;
53
- }
64
+ struct um_op *op = machine->op_freelist;
65
+ if (op)
66
+ machine->op_freelist = op->next;
67
+ else
68
+ op = malloc(sizeof(struct um_op));
54
69
 
55
- struct um_op *op = malloc(sizeof(struct um_op));
56
70
  um_op_clear(op);
57
71
  return op;
58
72
  }
59
73
 
60
74
  inline void um_op_checkin(struct um *machine, struct um_op *op) {
61
- um_op_result_cleanup(machine, op);
62
-
63
75
  machine->pending_count--;
64
76
 
65
- op->next = machine->freelist_head;
66
- machine->freelist_head = op;
77
+ um_op_result_cleanup(machine, op);
78
+ op->next = machine->op_freelist;
79
+ machine->op_freelist = op;
67
80
  }
68
81
 
69
82
  inline struct um_op *um_runqueue_find_by_fiber(struct um *machine, VALUE fiber) {
@@ -108,7 +121,7 @@ inline struct um_op *um_runqueue_shift(struct um *machine) {
108
121
 
109
122
  op->prev = NULL;
110
123
  if (!op->next) {
111
- machine->runqueue_head = machine->runqueue_tail = NULL;
124
+ machine->runqueue_head = machine->runqueue_tail = NULL;
112
125
  }
113
126
  else {
114
127
  machine->runqueue_head = op->next;
@@ -117,7 +130,7 @@ inline struct um_op *um_runqueue_shift(struct um *machine) {
117
130
  return op;
118
131
  }
119
132
 
120
- inline void um_free_linked_list(struct um *machine, struct um_op *op) {
133
+ inline void um_free_op_linked_list(struct um *machine, struct um_op *op) {
121
134
  while (op) {
122
135
  struct um_op *next = op->next;
123
136
  um_op_result_cleanup(machine, op);
@@ -125,3 +138,11 @@ inline void um_free_linked_list(struct um *machine, struct um_op *op) {
125
138
  op = next;
126
139
  }
127
140
  }
141
+
142
+ inline void um_free_result_linked_list(struct um *machine, struct um_result_entry *entry) {
143
+ while (entry) {
144
+ struct um_result_entry *next = entry->next;
145
+ free(entry);
146
+ entry = next;
147
+ }
148
+ }
data/ext/um/um_utils.c CHANGED
@@ -1,4 +1,6 @@
1
1
  #include "um.h"
2
+ #include <sys/mman.h>
3
+ #include <stdlib.h>
2
4
 
3
5
  inline struct __kernel_timespec um_double_to_timespec(double value) {
4
6
  double integral;
@@ -46,13 +48,56 @@ static inline void adjust_read_buffer_len(VALUE buffer, int result, int ofs) {
46
48
  rb_str_set_len(buffer, len + (unsigned)ofs);
47
49
  }
48
50
 
49
- inline void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, int result, int flags) {
51
+ inline void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags) {
50
52
  if (!result) return;
51
53
 
52
54
  adjust_read_buffer_len(buffer, result, buffer_offset);
53
55
  }
54
56
 
55
- inline VALUE get_string_from_buffer_ring(struct um *machine, int bgid, int result, int flags) {
57
+ int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count) {
58
+ if (machine->buffer_ring_count == BUFFER_RING_MAX_COUNT)
59
+ rb_raise(rb_eRuntimeError, "Cannot setup more than BUFFER_RING_MAX_COUNT buffer rings");
60
+
61
+ struct buf_ring_descriptor *desc = machine->buffer_rings + machine->buffer_ring_count;
62
+ desc->buf_count = count;
63
+ desc->buf_size = size;
64
+
65
+ desc->br_size = sizeof(struct io_uring_buf) * desc->buf_count;
66
+ void *mapped = mmap(
67
+ NULL, desc->br_size, PROT_READ | PROT_WRITE,
68
+ MAP_ANONYMOUS | MAP_PRIVATE, 0, 0
69
+ );
70
+ if (mapped == MAP_FAILED)
71
+ rb_raise(rb_eRuntimeError, "Failed to allocate buffer ring");
72
+
73
+ desc->br = (struct io_uring_buf_ring *)mapped;
74
+ io_uring_buf_ring_init(desc->br);
75
+
76
+ unsigned bg_id = machine->buffer_ring_count;
77
+ int ret;
78
+ desc->br = io_uring_setup_buf_ring(&machine->ring, count, bg_id, 0, &ret);
79
+ if (!desc->br) {
80
+ munmap(desc->br, desc->br_size);
81
+ rb_syserr_fail(ret, strerror(ret));
82
+ }
83
+
84
+ if (posix_memalign(&desc->buf_base, 4096, desc->buf_count * desc->buf_size)) {
85
+ io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, bg_id);
86
+ rb_raise(rb_eRuntimeError, "Failed to allocate buffers");
87
+ }
88
+
89
+ desc->buf_mask = io_uring_buf_ring_mask(desc->buf_count);
90
+ void *ptr = desc->buf_base;
91
+ for (unsigned i = 0; i < desc->buf_count; i++) {
92
+ io_uring_buf_ring_add(desc->br, ptr, desc->buf_size, i, desc->buf_mask, i);
93
+ ptr += desc->buf_size;
94
+ }
95
+ io_uring_buf_ring_advance(desc->br, desc->buf_count);
96
+ machine->buffer_ring_count++;
97
+ return bg_id;
98
+ }
99
+
100
+ inline VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags) {
56
101
  if (!result) return Qnil;
57
102
 
58
103
  unsigned buf_idx = flags >> IORING_CQE_BUFFER_SHIFT;
@@ -64,7 +109,7 @@ inline VALUE get_string_from_buffer_ring(struct um *machine, int bgid, int resul
64
109
 
65
110
  // add buffer back to buffer ring
66
111
  io_uring_buf_ring_add(
67
- desc->br, src, desc->buf_size, buf_idx, io_uring_buf_ring_mask(desc->buf_count), 0
112
+ desc->br, src, desc->buf_size, buf_idx, desc->buf_mask, 0
68
113
  );
69
114
  io_uring_buf_ring_advance(desc->br, 1);
70
115
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.2'
4
+ VERSION = '0.4'
5
5
  end
data/lib/uringmachine.rb CHANGED
@@ -3,3 +3,15 @@
3
3
  require_relative './um_ext'
4
4
 
5
5
  UM = UringMachine
6
+
7
+ class UringMachine
8
+ def spin(value = nil, &block)
9
+ Fiber.new do |resume_value|
10
+ block.(resume_value)
11
+ rescue Exception => e
12
+ raise RuntimeError, "Unhandled fiber exception: #{e.inspect}"
13
+ ensure
14
+ self.yield
15
+ end.tap { |f| schedule(f, value) }
16
+ end
17
+ end