uringmachine 0.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
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