uringmachine 0.30.0 → 0.32.0

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -4
  3. data/README.md +45 -38
  4. data/TODO.md +21 -4
  5. data/benchmark/bm_io_pipe.rb +2 -2
  6. data/benchmark/common.rb +16 -16
  7. data/benchmark/gets.rb +5 -5
  8. data/benchmark/gets_concurrent.rb +12 -12
  9. data/benchmark/http_parse.rb +14 -14
  10. data/benchmark/http_server_accept_queue.rb +11 -7
  11. data/benchmark/http_server_multi_accept.rb +7 -7
  12. data/benchmark/http_server_multi_ractor.rb +7 -7
  13. data/benchmark/http_server_single_thread.rb +8 -8
  14. data/benchmark/openssl.rb +50 -22
  15. data/docs/design/buffer_pool.md +1 -1
  16. data/examples/fiber_concurrency_io.rb +52 -0
  17. data/examples/fiber_concurrency_naive.rb +26 -0
  18. data/examples/fiber_concurrency_runqueue.rb +33 -0
  19. data/examples/fiber_concurrency_um.rb +16 -0
  20. data/examples/io_uring_simple.c +33 -0
  21. data/examples/pg.rb +2 -2
  22. data/examples/stream.rb +2 -2
  23. data/examples/um_cancellation.rb +20 -0
  24. data/examples/um_fiber_scheduler.rb +10 -0
  25. data/examples/um_io.rb +19 -0
  26. data/examples/um_mo.c +32 -0
  27. data/examples/um_multishot.rb +15 -0
  28. data/examples/um_ssl.rb +11 -0
  29. data/ext/um/um.c +20 -3
  30. data/ext/um/um.h +24 -18
  31. data/ext/um/um_ext.c +2 -4
  32. data/ext/um/um_io.c +775 -0
  33. data/ext/um/um_io_class.c +394 -0
  34. data/ext/um/um_ssl.c +37 -2
  35. data/ext/um/um_utils.c +1 -1
  36. data/grant-2025/final-report.md +2 -0
  37. data/grant-2025/journal.md +1 -1
  38. data/lib/uringmachine/version.rb +1 -1
  39. data/lib/uringmachine.rb +18 -18
  40. data/test/{test_stream.rb → test_io.rb} +290 -153
  41. data/test/test_um.rb +18 -18
  42. metadata +17 -6
  43. data/ext/um/um_stream.c +0 -706
  44. data/ext/um/um_stream_class.c +0 -317
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a97099f1d89b2333b8be056c91acabad63fad122ce4c802a666e4abb10aca93b
4
- data.tar.gz: '095878ee7df374be5dc87b74ea636b3def2b611006c76c7d86ae7c00ad064f47'
3
+ metadata.gz: 299bd9cc7810b3d67352cf1c35e1bad8228d26dc1495d2e03e8283299347836a
4
+ data.tar.gz: 1241fd5922a26d0223a6d345984e7548bb4486160a5f7f70cb25f4356cde4736
5
5
  SHA512:
6
- metadata.gz: 339349fd4116011334517f124201a1cf425762c1bafe33ba61fa3eaf175fa5064512f780f8354f8fc317515bab6c4914cb41fba2022d23c17aac7e08d18cad7b
7
- data.tar.gz: 02c7b30e4143f07382f2788a9f242e6f051f57b438fc3ecc63153a13f318bbbab69e5239add2af31e277c68b21483be60bd542863c8f7aa358d7fa1b0c0793e9
6
+ metadata.gz: 0075bd142ba474e475eb53fca3eb8e88bbb5fdba8214d7832b34582f3089e2720e99e069f49d7244b2c2cd9f5536ca5113589b9a5658d3f3679e3d6352043e1d
7
+ data.tar.gz: fe68ab2c66601a0aa5786e86b86173b5c6b94a1f58d0a7151546c4c596b1d625912ebd32670c8230ab301886f3a6a0a35edff1cd7a472f5253cb181e0156a1f7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # 0.32.0 2026-04-03
2
+
3
+ - Rename `UM::Connection` to `UM::IO`
4
+
5
+ # 0.31.0 2026-03-31
6
+
7
+ - Rework `Stream` into `Connection` class:
8
+ - Rename modes, improve SSL detection
9
+ - Rename and enhance different read methods
10
+ - Add `#write` method
11
+ - Add `#resp_write` method
12
+
1
13
  # 0.30.0 2026-03-23
2
14
 
3
15
  - Add `Stream#each`
@@ -30,7 +42,7 @@
30
42
 
31
43
  # 0.28.2 2026-02-20
32
44
 
33
- - Fix `Stream#get_string`
45
+ - Fix `Stream#read`
34
46
 
35
47
  # 0.28.1 2026-02-20
36
48
 
@@ -169,9 +181,9 @@
169
181
 
170
182
  # 2025-06-03 Version 0.12
171
183
 
172
- - Add buffer, maxlen params to `Stream#get_line`
173
- - Add buffer param to `Stream#get_string`
174
- - Remove `Stream#resp_get_line`, `Stream#resp_get_string` methods
184
+ - Add buffer, maxlen params to `Stream#read_line`
185
+ - Add buffer param to `Stream#read`
186
+ - Remove `Stream#resp_read_line`, `Stream#resp_read` methods
175
187
 
176
188
  # 2025-06-02 Version 0.11.1
177
189
 
data/README.md CHANGED
@@ -37,7 +37,7 @@ implementation that allows integration with the entire Ruby ecosystem.
37
37
  - Excellent performance characteristics for concurrent I/O-bound applications.
38
38
  - `Fiber::Scheduler` implementation to automatically integrate with the Ruby
39
39
  ecosystem in a transparent fashion.
40
- - Read streams with automatic buffer management.
40
+ - [IO](#io-api) class with automatic buffer management for reading.
41
41
  - Optimized I/O for encrypted SSL connections.
42
42
 
43
43
  ## Design
@@ -286,64 +286,69 @@ fiber = Fiber.schedule do
286
286
  end
287
287
  ```
288
288
 
289
- ## Read Streams
289
+ ## IO API
290
290
 
291
- A UringMachine stream is used to efficiently read from a socket or other file
292
- descriptor. Streams are ideal for implementing the read side of protocols, and
293
- provide an API that is useful for both line-based protocols and binary
294
- (frame-based) protocols.
291
+ `UringMachine::IO` is a class designed for efficiently read from and write to a
292
+ socket or other file descriptor. The IO class is ideal for implementing
293
+ line-based and binary (frame-based) protocols.
295
294
 
296
- A stream is associated with a UringMachine instance and a target file descriptor
297
- (see also [stream modes](#stream-modes) below). Behind the scenes, streams take
298
- advantage of io_uring's registered buffers feature, and more recently, the
299
- introduction of [incremental buffer
295
+ An IO is associated with a UringMachine instance and a target file descriptor
296
+ (or SSL socket, see also [IO modes](#io-modes) below). Behind the scenes, the IO
297
+ class takes advantage of io_uring's provided buffers feature, and more recently,
298
+ the introduction of [incremental buffer
300
299
  consumption](https://github.com/axboe/liburing/wiki/What's-new-with-io_uring-in-6.11-and-6.12#incremental-provided-buffer-consumption).
301
300
 
302
- When streams are used, UringMachine automatically manages the buffers it
301
+ When IO instances are used, UringMachine automatically manages the buffers it
303
302
  provides to the kernel, maximizing buffer reuse and minimizing allocations.
304
303
  UringMachine also responds to stress conditions (increased incoming traffic) by
305
304
  automatically provisioning additional buffers.
306
305
 
307
- To create a stream for a given fd, use `UM#stream`:
306
+ To create an IO for a given fd, use `UM#io`:
308
307
 
309
308
  ```ruby
310
- stream = machine.stream(fd)
309
+ io = machine.io(fd)
311
310
 
312
- # you can also provide a block that will be passed the stream instance:
313
- machine.stream(fd) { |s| do_something_with(s) }
311
+ # you can provide a block that will be passed the IO instance:
312
+ machine.io(fd) { |io| do_something_with(io) }
314
313
 
315
- # you can also instantiate a stream directly:
316
- stream = UM::Stream.new(machine, fd)
314
+ # you can also instantiate an IO directly:
315
+ io = UM::IO.new(machine, fd)
317
316
  ```
318
317
 
319
- The following API is used to interact with the stream:
318
+ The following API is used to interact with an IO:
320
319
 
321
320
  ```ruby
322
321
  # Read until a newline character is encountered:
323
- line = stream.get_line(0)
322
+ line = io.read_line(0)
324
323
 
325
324
  # Read line with a maximum length of 13 bytes:
326
- line = stream.get_line(13)
325
+ line = io.read_line(13)
327
326
 
328
327
  # Read all data:
329
- buf = stream.get_string(0)
328
+ buf = io.read(0)
330
329
 
331
330
  # Read exactly 13 bytes:
332
- buf = stream.get_string(13)
331
+ buf = io.read(13)
333
332
 
334
333
  # Read up to 13 bytes:
335
- buf = stream.get_string(-13)
334
+ buf = io.read(-13)
335
+
336
+ # Read continuously until EOF
337
+ io.read_each { |data| ... }
336
338
 
337
339
  # Skip 3 bytes:
338
- stream.skip(3)
340
+ io.skip(3)
341
+
342
+ # Write
343
+ io.write('foo', 'bar', 'baz')
339
344
  ```
340
345
 
341
346
  Here's an example of a how a basic HTTP request parser might be implemented
342
- using a stream:
347
+ using a `UM::IO`:
343
348
 
344
349
  ```ruby
345
- def parse_http_request_headers(stream)
346
- request_line = stream.get_line(0)
350
+ def parse_http_request_headers(io)
351
+ request_line = io.read_line(0)
347
352
  m = request_line.match(REQUEST_LINE_RE)
348
353
  return nil if !m
349
354
 
@@ -354,7 +359,7 @@ def parse_http_request_headers(stream)
354
359
  }
355
360
 
356
361
  while true
357
- line = stream.get_line(0)
362
+ line = io.read_line(0)
358
363
  break if !line || line.empty?
359
364
 
360
365
  m = line.match(HEADER_RE)
@@ -364,24 +369,26 @@ def parse_http_request_headers(stream)
364
369
  end
365
370
  ```
366
371
 
367
- ### Stream modes
372
+ ### IO modes
368
373
 
369
- Stream modes allow streams to be transport agnostic. Currently streams support
370
- three modes:
374
+ IO modes allow IOs to be transport agnostic. The following modes are currently
375
+ supported:
371
376
 
372
- - `:bp_read` - use the buffer pool, read data using multishot read
377
+ - `:fd` - use the buffer pool, read data using multishot read
373
378
  (this is the default mode).
374
- - `:bp_recv` - use the buffer pool, read data using multishot recv.
379
+ - `:socket` - use the buffer pool, read data using multishot recv.
375
380
  - `:ssl` - read from an `SSLSocket` object.
376
381
 
377
- The mode is specified as an additional argument to `Stream.new`:
382
+ The mode is specified as an additional argument to `IO.new`:
378
383
 
379
384
  ```ruby
380
- # stream using recv:
381
- stream = machine.stream(fd, :bp_recv)
385
+ # using recv/send:
386
+ io = machine.io(fd, :socket)
382
387
 
383
- # stream on an SSL socket:
384
- stream = machine.stream(ssl, :ssl)
388
+ # SSL I/O:
389
+ io = machine.io(ssl, :ssl)
390
+ # or simply:
391
+ io = machine.io(ssl)
385
392
  ```
386
393
 
387
394
  ## Performance
data/TODO.md CHANGED
@@ -1,9 +1,28 @@
1
+ - Rename Connection to IO
2
+
3
+ ```ruby
4
+ io = machine.io(fd)
5
+ l = io.read_line(4)
6
+ io.write('foo')
7
+ ```
8
+
9
+ - Add `IO#fd`/`IO#target` method
10
+
11
+ - Add `UM#inspect` (show size, modes)
12
+ - Add `UM::IO#inspect` (show target, mode, pending bytes)
13
+
14
+ ## Reimplement multishot read/recv using buffer pool
15
+
16
+ - remove `#setup_buffer_ring` method
17
+ - use buffer pool, just like UM::Connection
18
+
1
19
  ## immediate
2
20
 
3
21
  - Add tests for support for Set in `machine#await`
4
22
  - Add tests for support for Set, Array in `machine#join`
5
- - Add `#read_file` for reading entire file
6
- - Add `#write_file` for writing entire file
23
+ - Add `UM#read_file` for reading entire file
24
+ - Add `UM#write_file` for writing entire file
25
+ - Rename stream methods: `:fd`, `:socket`, `:ssl`
7
26
 
8
27
  ## Balancing I/O with the runqueue
9
28
 
@@ -70,11 +89,9 @@
70
89
 
71
90
  ## ops still not implemented
72
91
 
73
- - splice / - tee
74
92
  - sendto
75
93
  - recvfrom
76
94
  - poll_multishot
77
- - fsync
78
95
  - mkdir / mkdirat
79
96
  - link / linkat / unlink / unlinkat / symlink
80
97
  - rename / renameat
@@ -2,8 +2,8 @@
2
2
 
3
3
  require_relative './common'
4
4
 
5
- GROUPS = 48
6
- ITERATIONS = 10000
5
+ GROUPS = ENV['C']&.to_i || 48
6
+ ITERATIONS = ENV['I']&.to_i || 10000
7
7
 
8
8
  SIZE = 1024
9
9
  DATA = '*' * SIZE
data/benchmark/common.rb CHANGED
@@ -62,35 +62,35 @@ class UMBenchmark
62
62
  # baseline_um: [:baseline_um, "UM no concurrency"],
63
63
  # thread_pool: [:thread_pool, "ThreadPool"],
64
64
 
65
- threads: [:threads, "Threads"],
65
+ # threads: [:threads, "Threads"],
66
66
 
67
- async_uring: [:scheduler, "Async uring"],
68
- async_uring_x2: [:scheduler_x, "Async uring x2"],
67
+ # async_uring: [:scheduler, "Async uring"],
68
+ # async_uring_x2: [:scheduler_x, "Async uring x2"],
69
69
 
70
70
  # async_epoll: [:scheduler, "Async epoll"],
71
71
  # async_epoll_x2: [:scheduler_x, "Async epoll x2"],
72
72
 
73
- um_fs: [:scheduler, "UM FS"],
74
- um_fs_x2: [:scheduler_x, "UM FS x2"],
73
+ # um_fs: [:scheduler, "UM FS"],
74
+ # um_fs_x2: [:scheduler_x, "UM FS x2"],
75
75
 
76
- um: [:um, "UM"],
77
- um_sidecar: [:um, "UM sidecar"],
76
+ # um: [:um, "UM"],
77
+ # um_sidecar: [:um, "UM sidecar"],
78
78
  # um_sqpoll: [:um, "UM sqpoll"],
79
79
  um_x2: [:um_x, "UM x2"],
80
- um_x4: [:um_x, "UM x4"],
81
- um_x8: [:um_x, "UM x8"],
80
+ # um_x4: [:um_x, "UM x4"],
81
+ # um_x8: [:um_x, "UM x8"],
82
82
  }
83
83
 
84
84
  def run_benchmarks(b)
85
85
  STDOUT.sync = true
86
86
  @@benchmarks.each do |sym, (doer, name)|
87
87
  if respond_to?(:"do_#{doer}")
88
- STDOUT << "Running #{name}... "
89
- ts = nil
88
+ # STDOUT << "Running #{name}... "
89
+ # ts = nil
90
90
  b.report(name) {
91
- ts = measure_time { send(:"run_#{sym}") }
91
+ # ts = measure_time { send(:"run_#{sym}") }
92
+ send(:"run_#{sym}")
92
93
  }
93
- p ts
94
94
  cleanup
95
95
  end
96
96
  end
@@ -197,7 +197,7 @@ class UMBenchmark
197
197
  end
198
198
 
199
199
  def run_um
200
- machine = UM.new
200
+ machine = UM.new(size: 16384)
201
201
  fibers = []
202
202
  fds = []
203
203
  do_um(machine, fibers, fds)
@@ -226,7 +226,7 @@ class UMBenchmark
226
226
  def run_um_x2
227
227
  threads = 2.times.map do
228
228
  Thread.new do
229
- machine = UM.new
229
+ machine = UM.new(size: 16384)
230
230
  fibers = []
231
231
  fds = []
232
232
  do_um_x(2, machine, fibers, fds)
@@ -240,7 +240,7 @@ class UMBenchmark
240
240
  def run_um_x4
241
241
  threads = 4.times.map do
242
242
  Thread.new do
243
- machine = UM.new
243
+ machine = UM.new(size: 16384)
244
244
  fibers = []
245
245
  fds = []
246
246
  do_um_x(4, machine, fibers, fds)
data/benchmark/gets.rb CHANGED
@@ -34,16 +34,16 @@ def um_read
34
34
  end
35
35
  end
36
36
 
37
- @fd_stream = @machine.open('/dev/random', UM::O_RDONLY)
38
- @stream = UM::Stream.new(@machine, @fd_stream)
39
- def um_stream_get_line
40
- @stream.get_line(0)
37
+ @fd_io = @machine.open('/dev/random', UM::O_RDONLY)
38
+ @io = UM::IO.new(@machine, @fd_io)
39
+ def um_io_read_line
40
+ @io².read_line(0)
41
41
  end
42
42
 
43
43
  Benchmark.ips do |x|
44
44
  x.report('IO#gets') { io_gets }
45
45
  x.report('UM#read+buf') { um_read }
46
- x.report('UM::Stream') { um_stream_get_line }
46
+ x.report('UM::IO') { um_io_read_line }
47
47
 
48
48
  x.compare!(order: :baseline)
49
49
  end
@@ -83,40 +83,40 @@ ensure
83
83
  stop_server
84
84
  end
85
85
 
86
- @total_stream = 0
87
- def um_stream_do
86
+ @total_io = 0
87
+ def um_io_do
88
88
  # fd = @machine.open('/dev/random', UM::O_RDONLY)
89
89
  fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
90
90
  @machine.connect(fd, '127.0.0.1', 1234)
91
- stream = UM::Stream.new(@machine, fd)
92
- N.times { @total_stream += stream.get_line(0)&.bytesize || 0 }
91
+ io = UM::IO.new(@machine, fd)
92
+ N.times { @total_io += io.read_line(0)&.bytesize || 0 }
93
93
  rescue => e
94
94
  p e
95
95
  p e.backtrace
96
96
  ensure
97
- stream.clear
97
+ io.clear
98
98
  @machine.close(fd)
99
99
  end
100
100
 
101
- def um_stream
101
+ def um_io
102
102
  start_server
103
103
  ff = C.times.map {
104
104
  @machine.snooze
105
- @machine.spin { um_stream_do }
105
+ @machine.spin { um_io_do }
106
106
  }
107
107
  @machine.await(ff)
108
- pp total: @total_stream
108
+ pp total: @total_io
109
109
  ensure
110
110
  stop_server
111
111
  end
112
112
 
113
113
  p(C:, N:)
114
- um_stream
114
+ um_io
115
115
  pp @machine.metrics
116
116
  exit
117
117
 
118
118
  Benchmark.bm do
119
- it.report('Thread/IO#gets') { io_gets }
120
- it.report('Fiber/UM#read+buf') { um_read }
121
- it.report('Fiber/UM::Stream') { um_stream }
119
+ it.report('Thread/IO#gets') { io_gets }
120
+ it.report('Fiber/UM#read+buf') { um_read }
121
+ it.report('Fiber/UM::IO') { um_io }
122
122
  end
@@ -65,7 +65,7 @@ require 'stringio'
65
65
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/1\.1)/i
66
66
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
67
67
 
68
- def get_line(fd, sio, buffer)
68
+ def read_line(fd, sio, buffer)
69
69
  while true
70
70
  line = sio.gets(chomp: true)
71
71
  return line if line
@@ -76,7 +76,7 @@ def get_line(fd, sio, buffer)
76
76
  end
77
77
 
78
78
  def get_request_line(fd, sio, buffer)
79
- line = get_line(fd, sio, buffer)
79
+ line = read_line(fd, sio, buffer)
80
80
 
81
81
  m = line.match(RE_REQUEST_LINE)
82
82
  return nil if !m
@@ -96,7 +96,7 @@ def parse_headers(fd)
96
96
  return nil if !headers
97
97
 
98
98
  while true
99
- line = get_line(fd, sio, buffer)
99
+ line = read_line(fd, sio, buffer)
100
100
  break if line.empty?
101
101
 
102
102
  m = line.match(RE_HEADER_LINE)
@@ -129,15 +129,15 @@ ensure
129
129
  ($machine.close(wfd) rescue nil) if wfd
130
130
  end
131
131
 
132
- def stream_parse_headers(fd)
133
- stream = UM::Stream.new($machine, fd)
132
+ def io_parse_headers(fd)
133
+ io = UM::IO.new($machine, fd)
134
134
 
135
135
  buf = String.new(capacity: 65536)
136
- headers = stream_get_request_line(stream, buf)
136
+ headers = io_get_request_line(io, buf)
137
137
  return nil if !headers
138
138
 
139
139
  while true
140
- line = stream.get_line(0)
140
+ line = io.read_line(0)
141
141
  break if line.empty?
142
142
 
143
143
  m = line.match(RE_HEADER_LINE)
@@ -149,8 +149,8 @@ def stream_parse_headers(fd)
149
149
  headers
150
150
  end
151
151
 
152
- def stream_get_request_line(stream, buf)
153
- line = stream.get_line(0)
152
+ def io_get_request_line(io, buf)
153
+ line = io.read_line(0)
154
154
 
155
155
  m = line.match(RE_REQUEST_LINE)
156
156
  return nil if !m
@@ -162,12 +162,12 @@ def stream_get_request_line(stream, buf)
162
162
  }
163
163
  end
164
164
 
165
- def parse_http_stream
165
+ def parse_http_io
166
166
  rfd, wfd = UM.pipe
167
167
  queue = UM::Queue.new
168
168
 
169
169
  $machine.spin do
170
- headers = stream_parse_headers(rfd)
170
+ headers = io_parse_headers(rfd)
171
171
  $machine.push(queue, headers)
172
172
  rescue Exception => e
173
173
  p e
@@ -188,7 +188,7 @@ def compare_allocs
188
188
  p(
189
189
  alloc_http_parser: alloc_count { x.times { parse_http_parser } },
190
190
  alloc_stringio: alloc_count { x.times { parse_http_stringio } },
191
- alloc_stream: alloc_count { x.times { parse_http_stream } }
191
+ alloc_io: alloc_count { x.times { parse_http_io } }
192
192
  )
193
193
  ensure
194
194
  GC.enable
@@ -213,8 +213,8 @@ def benchmark
213
213
  x.config(:time => 5, :warmup => 3)
214
214
 
215
215
  x.report("http_parser") { parse_http_parser }
216
- x.report("stringio") { parse_http_stringio }
217
- x.report("stream") { parse_http_stream }
216
+ x.report("StringIO") { parse_http_stringio }
217
+ x.report("UM::IO") { parse_http_io }
218
218
 
219
219
  x.compare!
220
220
  end
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def io_get_request_line(io, buf)
16
+ line = io.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(io, buf)
30
+ headers = io_get_request_line(io, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = io.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -51,17 +51,21 @@ def send_response(machine, fd)
51
51
  end
52
52
 
53
53
  def handle_connection(machine, fd)
54
- stream = UM::Stream.new(machine, fd)
54
+ io = UM::IO.new(machine, fd)
55
55
  buf = String.new(capacity: 65536)
56
56
 
57
57
  while true
58
- headers = get_headers(stream, buf)
58
+ headers = get_headers(io, buf)
59
59
  break if !headers
60
60
 
61
61
  send_response(machine, fd)
62
62
  end
63
63
  rescue InvalidHeadersError, SystemCallError => e
64
64
  # ignore
65
+ rescue => e
66
+ p e
67
+ p e.backtrace
68
+ exit!
65
69
  ensure
66
70
  machine.close_async(fd)
67
71
  end
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def io_get_request_line(io, buf)
16
+ line = io.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(io, buf)
30
+ headers = io_get_request_line(io, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = io.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -51,11 +51,11 @@ def send_response(machine, fd)
51
51
  end
52
52
 
53
53
  def handle_connection(machine, fd)
54
- stream = UM::Stream.new(machine, fd)
54
+ io = UM::IO.new(machine, fd)
55
55
  buf = String.new(capacity: 65536)
56
56
 
57
57
  while true
58
- headers = get_headers(stream, buf)
58
+ headers = get_headers(io, buf)
59
59
  break if !headers
60
60
 
61
61
  send_response(machine, fd)
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def io_get_request_line(io, buf)
16
+ line = io.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(io, buf)
30
+ headers = io_get_request_line(io, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = io.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -53,11 +53,11 @@ end
53
53
 
54
54
  def handle_connection(machine, fd)
55
55
  machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
56
- stream = UM::Stream.new(machine, fd)
56
+ io = UM::IO.new(machine, fd)
57
57
  buf = String.new(capacity: 65536)
58
58
 
59
59
  while true
60
- headers = get_headers(stream, buf)
60
+ headers = get_headers(io, buf)
61
61
  break if !headers
62
62
 
63
63
  send_response(machine, fd)
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def io_get_request_line(io, buf)
16
+ line = io.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(io, buf)
30
+ headers = io_get_request_line(io, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = io.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -52,11 +52,11 @@ end
52
52
 
53
53
  def handle_connection(machine, fd)
54
54
  machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
55
- stream = UM::Stream.new(machine, fd)
55
+ io = UM::IO.new(machine, fd)
56
56
  buf = String.new(capacity: 65536)
57
57
 
58
58
  while true
59
- headers = get_headers(stream, buf)
59
+ headers = get_headers(io, buf)
60
60
  break if !headers
61
61
 
62
62
  send_response(machine, fd)
@@ -77,4 +77,4 @@ machine.bind(fd, '127.0.0.1', PORT)
77
77
  machine.listen(fd, 128)
78
78
 
79
79
  puts "Listening on localhost:#{PORT}"
80
- machine.accept_each(fd) { |conn| machine.spin { handle_connection(machine, conn) } }
80
+ machine.accept_each(fd) { | io| machine.spin { handle_connection(machine, io) } }