uringmachine 0.10 → 0.11.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/CHANGELOG.md +8 -0
  3. data/examples/bm_http_parse.rb +108 -35
  4. data/examples/bm_side_running.rb +83 -0
  5. data/examples/bm_sqlite.rb +1 -1
  6. data/ext/um/um.c +17 -1
  7. data/ext/um/um.h +30 -0
  8. data/ext/um/um_ext.c +2 -0
  9. data/ext/um/um_stream.c +372 -0
  10. data/ext/um/um_stream_class.c +121 -0
  11. data/lib/uringmachine/version.rb +1 -1
  12. data/lib/uringmachine.rb +20 -16
  13. data/test/test_stream.rb +133 -0
  14. data/test/test_um.rb +63 -0
  15. data/uringmachine.gemspec +1 -0
  16. data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
  17. data/vendor/liburing/.gitignore +1 -0
  18. data/vendor/liburing/CHANGELOG +10 -0
  19. data/vendor/liburing/README +5 -0
  20. data/vendor/liburing/configure +1 -1
  21. data/vendor/liburing/examples/Makefile +1 -0
  22. data/vendor/liburing/examples/helpers.c +25 -0
  23. data/vendor/liburing/examples/helpers.h +13 -0
  24. data/vendor/liburing/examples/io_uring-test.c +3 -0
  25. data/vendor/liburing/examples/proxy.c +1 -1
  26. data/vendor/liburing/examples/reg-wait.c +41 -6
  27. data/vendor/liburing/examples/send-zerocopy.c +79 -32
  28. data/vendor/liburing/examples/zcrx.c +436 -0
  29. data/vendor/liburing/liburing.spec +1 -1
  30. data/vendor/liburing/src/Makefile +0 -1
  31. data/vendor/liburing/src/arch/generic/syscall.h +2 -2
  32. data/vendor/liburing/src/arch/syscall-defs.h +2 -2
  33. data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
  34. data/vendor/liburing/src/include/liburing.h +179 -59
  35. data/vendor/liburing/src/int_flags.h +4 -1
  36. data/vendor/liburing/src/liburing-ffi.map +14 -2
  37. data/vendor/liburing/src/liburing.map +9 -2
  38. data/vendor/liburing/src/queue.c +35 -30
  39. data/vendor/liburing/src/register.c +46 -15
  40. data/vendor/liburing/src/sanitize.c +6 -9
  41. data/vendor/liburing/src/setup.c +37 -71
  42. data/vendor/liburing/src/syscall.c +2 -2
  43. data/vendor/liburing/test/232c93d07b74.c +1 -0
  44. data/vendor/liburing/test/Makefile +9 -0
  45. data/vendor/liburing/test/accept-test.c +1 -0
  46. data/vendor/liburing/test/cmd-discard.c +16 -8
  47. data/vendor/liburing/test/connect.c +11 -7
  48. data/vendor/liburing/test/epwait.c +420 -0
  49. data/vendor/liburing/test/eventfd-ring.c +30 -5
  50. data/vendor/liburing/test/fallocate.c +1 -1
  51. data/vendor/liburing/test/fixed-hugepage.c +10 -7
  52. data/vendor/liburing/test/fixed-seg.c +187 -0
  53. data/vendor/liburing/test/helpers.c +121 -0
  54. data/vendor/liburing/test/helpers.h +13 -0
  55. data/vendor/liburing/test/init-mem.c +2 -0
  56. data/vendor/liburing/test/io_uring_passthrough.c +78 -62
  57. data/vendor/liburing/test/iopoll-overflow.c +5 -4
  58. data/vendor/liburing/test/iopoll.c +20 -10
  59. data/vendor/liburing/test/iowait.c +141 -0
  60. data/vendor/liburing/test/nvme.h +2 -0
  61. data/vendor/liburing/test/pipe-bug.c +11 -5
  62. data/vendor/liburing/test/pipe-eof.c +11 -1
  63. data/vendor/liburing/test/read-inc-file.c +150 -0
  64. data/vendor/liburing/test/read-write.c +21 -14
  65. data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
  66. data/vendor/liburing/test/recv-multishot.c +2 -2
  67. data/vendor/liburing/test/reg-wait.c +449 -120
  68. data/vendor/liburing/test/regbuf-clone.c +53 -0
  69. data/vendor/liburing/test/resize-rings.c +25 -2
  70. data/vendor/liburing/test/rsrc_tags.c +67 -14
  71. data/vendor/liburing/test/send-zerocopy.c +52 -130
  72. data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
  73. data/vendor/liburing/test/socket-nb.c +158 -0
  74. data/vendor/liburing/test/sqwait.c +9 -11
  75. data/vendor/liburing/test/timeout.c +198 -0
  76. data/vendor/liburing/test/vec-regbuf.c +609 -0
  77. data/vendor/liburing/test/wait-timeout.c +1 -1
  78. data/vendor/liburing/test/wq-aff.c +5 -1
  79. data/vendor/liburing/test/zcrx.c +928 -0
  80. metadata +30 -4
  81. data/vendor/liburing/.github/workflows/codespell.yml +0 -25
  82. data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85de1c3c67da5ef2a64b64a0370312208009683e9a42504bfbd7577bb6bee9f7
4
- data.tar.gz: 13a34495c1987c85891ee5db9c196fbf09b6ebcd9a2221026341023e63e5a8e8
3
+ metadata.gz: ccb8488c3f313b7a3890ae110fc5cebc7ac0062bbaa9ef362fb7ff5b02c680b9
4
+ data.tar.gz: 41f2c23a9427609c4d01a6eef319cbd40d029cf85918fd6c8d00e5b502f83ef6
5
5
  SHA512:
6
- metadata.gz: 7b10f6a2c6e4d0bccaebb75c50e702ca0126eeb712a25ac32631b21ddcafd550dcceab2028a4f1a9b380538aa19067e0fa08346137a760307193af0acef64ed1
7
- data.tar.gz: 0dc3949e9256f139cc1caab14b2de6b63e16af61c569de59b761153d8d05a2030bad0e299ca9044452cc628fd25accff8fe3e89c59e6d4c053f049339ddce2c3
6
+ metadata.gz: 9bd08ebae21a7a10407ff04102d9cbf491bfab65ebe601b6ab3a6b7790632c946873415af4f45321e959bd39e875ff386e8c85f74329743204a9c0c047ce5da0
7
+ data.tar.gz: 3cd63222c0b990ef83f2b324aa46b36bd142a7b43a1a273428a9b70a95cfe25e0a1b06a2985a7463fe51a995c78e82838e34ee20d3c332cc46278ffd738652dd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2025-06-02 Version 0.11.1
2
+
3
+ - Fix `UM::Stream` behaviour on GC
4
+
5
+ # 2025-06-02 Version 0.11
6
+
7
+ - Implement `UM::Stream` class for read streams
8
+
1
9
  # 2025-05-05 Version 0.10
2
10
 
3
11
  - Add `Thread#machine`
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/inline'
3
+ # require 'bundler/inline'
4
4
 
5
- gemfile do
6
- source 'https://rubygems.org'
7
- gem 'uringmachine', path: '..'
8
- gem 'benchmark-ips'
9
- gem 'http_parser.rb'
10
- end
5
+ # gemfile do
6
+ # source 'https://rubygems.org'
7
+ # gem 'uringmachine', path: '..'
8
+ # gem 'benchmark-ips'
9
+ # gem 'http_parser.rb'
10
+ # end
11
11
 
12
- require 'benchmark/ips'
12
+ require 'bundler/setup'
13
13
  require 'uringmachine'
14
+ require 'benchmark/ips'
14
15
  require 'http/parser'
15
16
 
16
17
  $machine = UM.new
@@ -19,6 +20,8 @@ HTTP_MSG = "GET /foo/bar HTTP/1.1\r\nServer: foobar.com\r\nFoo: bar\r\n\r\n"
19
20
 
20
21
  $count = 0
21
22
 
23
+ STDOUT.sync = true
24
+
22
25
  def parse_http_parser
23
26
  current_fiber = Fiber.current
24
27
  $count += 1
@@ -45,10 +48,16 @@ def parse_http_parser
45
48
  end
46
49
 
47
50
  $machine.write(w.fileno, HTTP_MSG)
48
- $machine.yield
51
+ ret = $machine.yield
52
+ ret
53
+ rescue Exception => e
54
+ p e: e
55
+ exit
49
56
  ensure
50
- $machine.close(r.fileno)
51
- $machine.close(w.fileno)
57
+ r.close rescue nil
58
+ w.close rescue nil
59
+ # $machine.close(r.fileno) rescue nil
60
+ # $machine.close(w.fileno) rescue nil
52
61
  end
53
62
 
54
63
  require 'stringio'
@@ -100,50 +109,114 @@ def parse_headers(fd)
100
109
  end
101
110
 
102
111
  def parse_http_stringio
103
- current_fiber = Fiber.current
104
- r, w = IO.pipe
112
+ rfd, wfd = UM.pipe
113
+ queue = UM::Queue.new
105
114
 
106
115
  $machine.spin do
107
- headers = parse_headers(r.fileno)
108
- $machine.schedule(current_fiber, headers)
116
+ headers = parse_headers(rfd)
117
+ $machine.push(queue, headers)
109
118
  rescue Exception => e
110
119
  p e
111
120
  puts e.backtrace.join("\n")
112
121
  exit!
113
122
  end
114
123
 
115
- $machine.write(w.fileno, HTTP_MSG)
116
- $machine.yield
124
+ $machine.write(wfd, HTTP_MSG)
125
+ $machine.close(wfd)
126
+ $machine.shift(queue)
117
127
  ensure
118
- $machine.close(r.fileno)
119
- $machine.close(w.fileno)
128
+ ($machine.close(rfd) rescue nil) if rfd
129
+ ($machine.close(wfd) rescue nil) if wfd
120
130
  end
121
131
 
122
- # p parse_http_parser
123
- # p parse_http_stringio
124
- # exit
132
+ def stream_parse_headers(fd)
133
+ stream = UM::Stream.new($machine, fd)
125
134
 
126
- GC.disable
135
+ headers = stream_get_request_line(stream)
136
+ return nil if !headers
127
137
 
128
- def alloc_count
129
- count0 = ObjectSpace.count_objects[:TOTAL]
130
- yield
131
- count1 = ObjectSpace.count_objects[:TOTAL]
132
- count1 - count0
138
+ while true
139
+ line = stream.get_line()
140
+ break if line.empty?
141
+
142
+ m = line.match(RE_HEADER_LINE)
143
+ raise "Invalid header" if !m
144
+
145
+ headers[m[1]] = m[2]
146
+ end
147
+
148
+ headers
133
149
  end
134
150
 
135
- X = 100
136
- p(
137
- alloc_http_parser: alloc_count { X.times { parse_http_parser } },
138
- alloc_stringio: alloc_count { X.times { parse_http_stringio } }
139
- )
140
- exit
151
+ def stream_get_request_line(stream)
152
+ line = stream.get_line()
153
+
154
+ m = line.match(RE_REQUEST_LINE)
155
+ return nil if !m
156
+
157
+ {
158
+ 'method' => m[1].downcase,
159
+ 'path' => m[2],
160
+ 'protocol' => m[3].downcase
161
+ }
162
+ end
163
+
164
+ def parse_http_stream
165
+ rfd, wfd = UM.pipe
166
+ queue = UM::Queue.new
167
+
168
+ $machine.spin do
169
+ headers = stream_parse_headers(rfd)
170
+ $machine.push(queue, headers)
171
+ rescue Exception => e
172
+ p e
173
+ puts e.backtrace.join("\n")
174
+ exit!
175
+ end
176
+
177
+ $machine.write(wfd, HTTP_MSG)
178
+ $machine.shift(queue)
179
+ ensure
180
+ ($machine.close(rfd) rescue nil) if rfd
181
+ ($machine.close(wfd) rescue nil) if wfd
182
+ end
183
+
184
+ # 10000.times { parse_http_parser }
185
+ # 10000.times { parse_http_stringio }
186
+ # 10000.times { parse_http_stream }
187
+ # exit
188
+
189
+ # GC.disable
190
+
191
+ # OS = ObjectSpace
192
+
193
+ # def object_count
194
+ # counts = ObjectSpace.count_objects
195
+ # counts[:TOTAL] - counts[:FREE]
196
+ # end
197
+
198
+ # def alloc_count
199
+ # GC.start
200
+ # count0 = object_count
201
+ # yield
202
+ # count1 = object_count
203
+ # count1 - count0
204
+ # end
205
+
206
+ # X = 100
207
+ # p(
208
+ # alloc_http_parser: alloc_count { X.times { parse_http_parser } },
209
+ # alloc_stringio: alloc_count { X.times { parse_http_stringio } },
210
+ # alloc_stream: alloc_count { X.times { parse_http_stream } }
211
+ # )
212
+ # exit
141
213
 
142
214
  Benchmark.ips do |x|
143
215
  x.config(:time => 5, :warmup => 3)
144
216
 
145
217
  x.report("http_parser") { parse_http_parser }
146
- x.report("homegrown") { parse_http_stringio }
218
+ x.report("stringio") { parse_http_stringio }
219
+ x.report("stream") { parse_http_stream }
147
220
 
148
221
  x.compare!
149
222
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ gem 'benchmark-ips'
9
+ end
10
+
11
+ require 'benchmark/ips'
12
+ require 'uringmachine'
13
+
14
+ def consume_from_queue(queue)
15
+ m = UM.new
16
+ while true
17
+ response_mailbox, closure = m.shift(queue)
18
+ result = closure.call
19
+ m.push(response_mailbox, result)
20
+ end
21
+ # rescue UM::Terminate
22
+ # # We can also add a timeout here
23
+ # t0 = Time.now
24
+ # while !queue.empty? && (Time.now - t0) < 10
25
+ # response_mailbox, closure = m.shift(queue)
26
+ # result = closure.call
27
+ # m.push(response_mailbox, result)
28
+ # end
29
+ end
30
+
31
+ N = 8
32
+
33
+ $machine = UM.new
34
+ @queue = UM::Queue.new
35
+ @threads = N.times.map { Thread.new { consume_from_queue(@queue) } }
36
+
37
+ def side_run(&block)
38
+ mailbox = Fiber.current.mailbox
39
+ $machine.push(@queue, [mailbox, block])
40
+ Thread.pass
41
+ $machine.shift(mailbox)
42
+ end
43
+
44
+ @rqueue = Queue.new
45
+ @rthreads = N.times.map { Thread.new { r_consume_from_queue(@rqueue) }}
46
+
47
+ def r_consume_from_queue(queue)
48
+ m = UM.new
49
+ while true
50
+ response_mailbox, closure = @rqueue.shift
51
+ result = closure.call
52
+ m.push(response_mailbox, result)
53
+ end
54
+ # rescue UM::Terminate
55
+ # # We can also add a timeout here
56
+ # t0 = Time.now
57
+ # while !queue.empty? && (Time.now - t0) < 10
58
+ # response_mailbox, closure = m.shift(queue)
59
+ # result = closure.call
60
+ # m.push(response_mailbox, result)
61
+ # end
62
+ end
63
+
64
+ def r_side_run(&block)
65
+ mailbox = Fiber.current.mailbox
66
+ @rqueue.push([mailbox, block])
67
+ Thread.pass
68
+ $machine.shift(mailbox)
69
+ end
70
+
71
+ # puts '*' * 40
72
+ # p r_side_run { }
73
+ # exit!
74
+
75
+ Benchmark.ips do |x|
76
+ x.config(:time => 5, :warmup => 2)
77
+
78
+ x.report("side-run") { side_run { } }
79
+ x.report("r-side-run") { r_side_run { } }
80
+ # x.report("snoozing") { $machine.snooze }
81
+
82
+ x.compare!
83
+ end
@@ -49,7 +49,7 @@ class UM
49
49
  def spin_actor(target)
50
50
  f = UM::Actor.new(self, target)
51
51
  schedule(f, nil)
52
- @@fiber_map[f] = true
52
+ @@fiber_map[f] = f
53
53
  f
54
54
  end
55
55
  end
data/ext/um/um.c CHANGED
@@ -356,6 +356,22 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
356
356
  return raise_if_exception(ret);
357
357
  }
358
358
 
359
+ inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen) {
360
+ struct um_op op;
361
+ um_prep_op(machine, &op, OP_READ);
362
+ struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
363
+ io_uring_prep_read(sqe, fd, buffer, maxlen, -1);
364
+
365
+ VALUE ret = um_fiber_switch(machine);
366
+ if (um_check_completion(machine, &op)) {
367
+ return op.result.res;
368
+
369
+ }
370
+
371
+ raise_if_exception(ret);
372
+ return 0;
373
+ }
374
+
359
375
  VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
360
376
  struct um_op op;
361
377
  um_prep_op(machine, &op, OP_WRITE);
@@ -575,7 +591,7 @@ VALUE um_waitpid(struct um *machine, int pid, int options) {
575
591
  struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
576
592
 
577
593
  siginfo_t infop;
578
- io_uring_prep_waitid(sqe, P_PID, pid, &infop, options, 0);
594
+ io_uring_prep_waitid(sqe, pid == 0 ? P_ALL : P_PID, pid, &infop, options, 0);
579
595
 
580
596
  VALUE ret = um_fiber_switch(machine);
581
597
  if (um_check_completion(machine, &op))
data/ext/um/um.h CHANGED
@@ -153,6 +153,24 @@ struct um_async_op {
153
153
  struct um_op *op;
154
154
  };
155
155
 
156
+ struct um_stream {
157
+ VALUE self;
158
+
159
+ struct um *machine;
160
+ int fd;
161
+ VALUE buffer;
162
+ ulong len;
163
+ ulong pos;
164
+ int eof;
165
+ };
166
+
167
+ struct um_write_buffer {
168
+ VALUE str;
169
+ size_t capa;
170
+ size_t len;
171
+ char *ptr;
172
+ };
173
+
156
174
  extern VALUE cUM;
157
175
  extern VALUE cMutex;
158
176
  extern VALUE cQueue;
@@ -210,6 +228,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
210
228
  VALUE um_sleep(struct um *machine, double duration);
211
229
  VALUE um_periodically(struct um *machine, double interval);
212
230
  VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset);
231
+ size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen);
213
232
  VALUE um_read_each(struct um *machine, int fd, int bgid);
214
233
  VALUE um_write(struct um *machine, int fd, VALUE str, int len);
215
234
  VALUE um_close(struct um *machine, int fd);
@@ -251,6 +270,17 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
251
270
  VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
252
271
  VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
253
272
 
273
+ int stream_read_more(struct um_stream *stream);
274
+ VALUE stream_get_line(struct um_stream *stream);
275
+ VALUE stream_get_string(struct um_stream *stream, ulong len);
276
+ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer);
277
+ VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer);
278
+ VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
279
+ void resp_encode(struct um_write_buffer *buf, VALUE obj);
280
+
281
+ void write_buffer_init(struct um_write_buffer *buf, VALUE str);
282
+ void write_buffer_update_len(struct um_write_buffer *buf);
283
+
254
284
  void um_define_net_constants(VALUE mod);
255
285
 
256
286
  #endif // UM_H
data/ext/um/um_ext.c CHANGED
@@ -3,6 +3,7 @@ void Init_Mutex();
3
3
  void Init_Queue();
4
4
  void Init_AsyncOp();
5
5
  void Init_SSL();
6
+ void Init_Stream();
6
7
 
7
8
  void Init_um_ext(void) {
8
9
  Init_UM();
@@ -10,4 +11,5 @@ void Init_um_ext(void) {
10
11
  Init_Queue();
11
12
  Init_AsyncOp();
12
13
  // Init_SSL();
14
+ Init_Stream();
13
15
  }