uringmachine 0.3 → 0.5

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +23 -0
  4. data/README.md +128 -0
  5. data/TODO.md +14 -0
  6. data/examples/bm_snooze.rb +89 -0
  7. data/examples/bm_write.rb +56 -0
  8. data/examples/dns_client.rb +12 -0
  9. data/examples/echo_server.rb +18 -40
  10. data/examples/http_server.rb +42 -43
  11. data/examples/inout.rb +19 -0
  12. data/examples/nc.rb +36 -0
  13. data/examples/server_client.rb +64 -0
  14. data/examples/snooze.rb +44 -0
  15. data/examples/write_dev_null.rb +16 -0
  16. data/ext/um/extconf.rb +24 -23
  17. data/ext/um/um.c +524 -278
  18. data/ext/um/um.h +146 -44
  19. data/ext/um/um_buffer.c +49 -0
  20. data/ext/um/um_class.c +217 -106
  21. data/ext/um/um_const.c +213 -0
  22. data/ext/um/um_ext.c +4 -0
  23. data/ext/um/um_mutex_class.c +47 -0
  24. data/ext/um/um_op.c +86 -114
  25. data/ext/um/um_queue_class.c +58 -0
  26. data/ext/um/um_sync.c +273 -0
  27. data/ext/um/um_utils.c +49 -4
  28. data/lib/uringmachine/dns_resolver.rb +84 -0
  29. data/lib/uringmachine/version.rb +1 -1
  30. data/lib/uringmachine.rb +28 -0
  31. data/supressions/ruby.supp +71 -0
  32. data/test/helper.rb +8 -0
  33. data/test/test_um.rb +685 -46
  34. data/vendor/liburing/.github/workflows/build.yml +29 -1
  35. data/vendor/liburing/.gitignore +6 -0
  36. data/vendor/liburing/CHANGELOG +16 -0
  37. data/vendor/liburing/CONTRIBUTING.md +165 -0
  38. data/vendor/liburing/configure +64 -0
  39. data/vendor/liburing/examples/Makefile +9 -1
  40. data/vendor/liburing/examples/kdigest.c +405 -0
  41. data/vendor/liburing/examples/proxy.c +75 -8
  42. data/vendor/liburing/examples/reg-wait.c +159 -0
  43. data/vendor/liburing/liburing.pc.in +1 -1
  44. data/vendor/liburing/liburing.spec +1 -1
  45. data/vendor/liburing/src/Makefile +16 -2
  46. data/vendor/liburing/src/include/liburing/io_uring.h +77 -0
  47. data/vendor/liburing/src/include/liburing/sanitize.h +39 -0
  48. data/vendor/liburing/src/include/liburing.h +59 -6
  49. data/vendor/liburing/src/int_flags.h +10 -3
  50. data/vendor/liburing/src/liburing-ffi.map +16 -0
  51. data/vendor/liburing/src/liburing.map +10 -0
  52. data/vendor/liburing/src/queue.c +28 -16
  53. data/vendor/liburing/src/register.c +106 -1
  54. data/vendor/liburing/src/sanitize.c +176 -0
  55. data/vendor/liburing/src/setup.c +47 -19
  56. data/vendor/liburing/src/setup.h +6 -0
  57. data/vendor/liburing/test/35fa71a030ca.c +7 -0
  58. data/vendor/liburing/test/500f9fbadef8.c +2 -0
  59. data/vendor/liburing/test/7ad0e4b2f83c.c +0 -25
  60. data/vendor/liburing/test/917257daa0fe.c +7 -0
  61. data/vendor/liburing/test/Makefile +38 -4
  62. data/vendor/liburing/test/a0908ae19763.c +7 -0
  63. data/vendor/liburing/test/a4c0b3decb33.c +7 -0
  64. data/vendor/liburing/test/accept.c +14 -4
  65. data/vendor/liburing/test/b19062a56726.c +7 -0
  66. data/vendor/liburing/test/bind-listen.c +2 -2
  67. data/vendor/liburing/test/buf-ring-nommap.c +10 -3
  68. data/vendor/liburing/test/buf-ring.c +2 -0
  69. data/vendor/liburing/test/cmd-discard.c +427 -0
  70. data/vendor/liburing/test/coredump.c +7 -0
  71. data/vendor/liburing/test/cq-overflow.c +13 -1
  72. data/vendor/liburing/test/d4ae271dfaae.c +11 -3
  73. data/vendor/liburing/test/defer-taskrun.c +2 -2
  74. data/vendor/liburing/test/defer-tw-timeout.c +4 -1
  75. data/vendor/liburing/test/defer.c +2 -2
  76. data/vendor/liburing/test/double-poll-crash.c +1 -1
  77. data/vendor/liburing/test/eeed8b54e0df.c +2 -0
  78. data/vendor/liburing/test/eventfd.c +0 -1
  79. data/vendor/liburing/test/exit-no-cleanup.c +11 -0
  80. data/vendor/liburing/test/fadvise.c +9 -26
  81. data/vendor/liburing/test/fdinfo.c +9 -1
  82. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  83. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  84. data/vendor/liburing/test/file-register.c +14 -2
  85. data/vendor/liburing/test/file-update.c +1 -1
  86. data/vendor/liburing/test/file-verify.c +27 -16
  87. data/vendor/liburing/test/files-exit-hang-timeout.c +1 -2
  88. data/vendor/liburing/test/fixed-buf-iter.c +3 -1
  89. data/vendor/liburing/test/fixed-hugepage.c +12 -1
  90. data/vendor/liburing/test/fsnotify.c +1 -0
  91. data/vendor/liburing/test/futex.c +16 -4
  92. data/vendor/liburing/test/helpers.c +47 -0
  93. data/vendor/liburing/test/helpers.h +6 -0
  94. data/vendor/liburing/test/init-mem.c +5 -3
  95. data/vendor/liburing/test/io-cancel.c +0 -24
  96. data/vendor/liburing/test/io_uring_passthrough.c +4 -0
  97. data/vendor/liburing/test/io_uring_register.c +38 -8
  98. data/vendor/liburing/test/iopoll-leak.c +4 -0
  99. data/vendor/liburing/test/iopoll-overflow.c +1 -1
  100. data/vendor/liburing/test/iopoll.c +3 -3
  101. data/vendor/liburing/test/kallsyms.c +203 -0
  102. data/vendor/liburing/test/link-timeout.c +159 -0
  103. data/vendor/liburing/test/linked-defer-close.c +224 -0
  104. data/vendor/liburing/test/madvise.c +12 -25
  105. data/vendor/liburing/test/min-timeout-wait.c +0 -25
  106. data/vendor/liburing/test/min-timeout.c +0 -25
  107. data/vendor/liburing/test/mkdir.c +6 -0
  108. data/vendor/liburing/test/msg-ring.c +8 -2
  109. data/vendor/liburing/test/napi-test.c +16 -3
  110. data/vendor/liburing/test/no-mmap-inval.c +3 -1
  111. data/vendor/liburing/test/nop.c +44 -0
  112. data/vendor/liburing/test/ooo-file-unreg.c +1 -1
  113. data/vendor/liburing/test/open-close.c +40 -0
  114. data/vendor/liburing/test/openat2.c +37 -14
  115. data/vendor/liburing/test/poll-many.c +13 -7
  116. data/vendor/liburing/test/poll-mshot-update.c +17 -10
  117. data/vendor/liburing/test/poll-v-poll.c +6 -3
  118. data/vendor/liburing/test/pollfree.c +148 -0
  119. data/vendor/liburing/test/read-mshot-empty.c +158 -153
  120. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  121. data/vendor/liburing/test/read-mshot.c +282 -27
  122. data/vendor/liburing/test/read-write.c +78 -13
  123. data/vendor/liburing/test/recv-msgall-stream.c +3 -0
  124. data/vendor/liburing/test/recv-msgall.c +5 -0
  125. data/vendor/liburing/test/recvsend_bundle-inc.c +680 -0
  126. data/vendor/liburing/test/recvsend_bundle.c +94 -31
  127. data/vendor/liburing/test/reg-fd-only.c +15 -5
  128. data/vendor/liburing/test/reg-wait.c +251 -0
  129. data/vendor/liburing/test/regbuf-clone.c +645 -0
  130. data/vendor/liburing/test/regbuf-merge.c +7 -0
  131. data/vendor/liburing/test/register-restrictions.c +86 -85
  132. data/vendor/liburing/test/rename.c +59 -1
  133. data/vendor/liburing/test/resize-rings.c +643 -0
  134. data/vendor/liburing/test/ringbuf-read.c +5 -0
  135. data/vendor/liburing/test/ringbuf-status.c +5 -1
  136. data/vendor/liburing/test/rsrc_tags.c +1 -1
  137. data/vendor/liburing/test/runtests.sh +16 -1
  138. data/vendor/liburing/test/send-zerocopy.c +59 -0
  139. data/vendor/liburing/test/short-read.c +1 -0
  140. data/vendor/liburing/test/socket.c +43 -0
  141. data/vendor/liburing/test/splice.c +3 -1
  142. data/vendor/liburing/test/sq-poll-dup.c +1 -1
  143. data/vendor/liburing/test/sq-poll-share.c +2 -0
  144. data/vendor/liburing/test/sqpoll-disable-exit.c +8 -0
  145. data/vendor/liburing/test/sqpoll-exit-hang.c +1 -25
  146. data/vendor/liburing/test/sqpoll-sleep.c +40 -33
  147. data/vendor/liburing/test/sqwait.c +136 -0
  148. data/vendor/liburing/test/statx.c +89 -0
  149. data/vendor/liburing/test/stdout.c +2 -0
  150. data/vendor/liburing/test/submit-and-wait.c +1 -25
  151. data/vendor/liburing/test/submit-reuse.c +4 -26
  152. data/vendor/liburing/test/symlink.c +12 -1
  153. data/vendor/liburing/test/sync-cancel.c +56 -22
  154. data/vendor/liburing/test/thread-exit.c +5 -0
  155. data/vendor/liburing/test/timeout-new.c +1 -26
  156. data/vendor/liburing/test/timeout.c +25 -34
  157. data/vendor/liburing/test/unlink.c +94 -1
  158. data/vendor/liburing/test/uring_cmd_ublk.c +1252 -0
  159. data/vendor/liburing/test/waitid.c +62 -8
  160. data/vendor/liburing/test/wq-aff.c +35 -0
  161. data/vendor/liburing/test/xfail_prep_link_timeout_out_of_scope.c +46 -0
  162. data/vendor/liburing/test/xfail_register_buffers_out_of_scope.c +51 -0
  163. metadata +37 -6
  164. data/examples/event_loop.rb +0 -69
  165. data/examples/fibers.rb +0 -105
  166. data/examples/http_server_multishot.rb +0 -57
  167. data/examples/http_server_simpler.rb +0 -34
data/test/test_um.rb CHANGED
@@ -3,13 +3,37 @@
3
3
  require_relative 'helper'
4
4
  require 'socket'
5
5
 
6
- class SchedulingTest < UMBaseTest
6
+ class UringMachineTest < Minitest::Test
7
+ def test_kernel_version
8
+ v = UringMachine.kernel_version
9
+ assert_kind_of Integer, v
10
+ assert_in_range 600..700, v
11
+ end
12
+ end
13
+
14
+ class FiberTest < UMBaseTest
15
+ def test_spin
16
+ x = nil
17
+ f = machine.spin do
18
+ x = :foo
19
+ end
20
+
21
+ assert_kind_of Fiber, f
22
+ assert_nil x
23
+
24
+ machine.snooze
25
+
26
+ assert_equal :foo, x
27
+ end
28
+ end
29
+
30
+ class ScheduleTest < UMBaseTest
7
31
  def test_schedule_and_yield
8
32
  buf = []
9
- cur = Fiber.current
33
+ main = Fiber.current
10
34
  f = Fiber.new do |x|
11
35
  buf << [21, x]
12
- machine.schedule(cur, 21)
36
+ machine.schedule(main, 21)
13
37
  buf << 22
14
38
  x = machine.yield
15
39
  buf << [23, x]
@@ -49,12 +73,11 @@ class SchedulingTest < UMBaseTest
49
73
  assert_equal [e], buf
50
74
  end
51
75
 
52
- def test_interrupt
53
- cur = Fiber.current
76
+ def test_schedule_exception2
77
+ main = Fiber.current
54
78
  e = CustomError.new
55
79
  f = Fiber.new do
56
- machine.interrupt(cur, e)
57
- assert_equal 2, machine.pending_count
80
+ machine.schedule(main, e)
58
81
  machine.yield
59
82
  end
60
83
 
@@ -62,17 +85,11 @@ class SchedulingTest < UMBaseTest
62
85
  t0 = monotonic_clock
63
86
 
64
87
  # the call to schedule means an op is checked out
65
- assert_equal 1, machine.pending_count
88
+ assert_equal 0, machine.pending_count
66
89
  begin
67
90
  machine.sleep(1)
68
91
  rescue Exception => e2
69
92
  end
70
- # the sleep op has been cancelled, but we still need to process the
71
- # cancellation. Calling snooze should take care of that.
72
- assert_equal 1, machine.pending_count
73
- machine.snooze
74
-
75
- # CQE should have been received, and the op checked in
76
93
  assert_equal 0, machine.pending_count
77
94
  t1 = monotonic_clock
78
95
 
@@ -96,13 +113,7 @@ class SchedulingTest < UMBaseTest
96
113
  buf << 5
97
114
  end
98
115
 
99
- # at this point, the sleep cancelled CQE should not yet have been received.
100
- # So we still have a pending operation. Snooze should have let the CQE be
101
- # received.
102
- assert_equal 1, machine.pending_count
103
- machine.snooze
104
116
  assert_equal 0, machine.pending_count
105
-
106
117
  assert_equal [1, 2, 5], buf
107
118
  assert_kind_of TOError, e
108
119
  end
@@ -117,7 +128,7 @@ class SchedulingTest < UMBaseTest
117
128
  end
118
129
 
119
130
  assert_equal 1, machine.pending_count
120
- machine.snooze
131
+ machine.sleep(0.01) # wait for cancelled CQEs
121
132
  assert_equal 0, machine.pending_count
122
133
 
123
134
  assert_kind_of RuntimeError, e
@@ -130,7 +141,7 @@ class SchedulingTest < UMBaseTest
130
141
  assert_equal 42, v
131
142
 
132
143
  assert_equal 1, machine.pending_count
133
- machine.snooze
144
+ machine.sleep 0.01 # wait for cancelled CQE
134
145
  assert_equal 0, machine.pending_count
135
146
  end
136
147
 
@@ -152,6 +163,10 @@ class SchedulingTest < UMBaseTest
152
163
  rescue => e
153
164
  end
154
165
 
166
+ assert_equal 2, machine.pending_count
167
+ machine.sleep(0.01) # wait for cancelled CQEs
168
+ assert_equal 0, machine.pending_count
169
+
155
170
  assert_kind_of TO2Error, e
156
171
  assert_equal [3], buf
157
172
  end
@@ -160,11 +175,41 @@ end
160
175
  class SleepTest < UMBaseTest
161
176
  def test_sleep
162
177
  t0 = monotonic_clock
178
+ assert_equal 0, machine.pending_count
163
179
  res = machine.sleep(0.1)
180
+ assert_equal 0, machine.pending_count
164
181
  t1 = monotonic_clock
165
182
  assert_in_range 0.09..0.13, t1 - t0
166
183
  assert_equal 0.1, res
167
184
  end
185
+
186
+ class C; end
187
+
188
+ def test_sleep_interrupted
189
+ t0 = monotonic_clock
190
+ ret = machine.timeout(0.03, C) do
191
+ machine.sleep 1
192
+ end
193
+ t1 = monotonic_clock
194
+ assert_in_range 0.02..0.04, t1 - t0
195
+ assert_kind_of C, ret
196
+ end
197
+
198
+ class D < RuntimeError; end
199
+
200
+ def test_sleep_with_timeout
201
+ t0 = monotonic_clock
202
+ ret = begin
203
+ machine.timeout(0.03, D) do
204
+ machine.sleep 1
205
+ end
206
+ rescue => e
207
+ e
208
+ end
209
+ t1 = monotonic_clock
210
+ assert_in_range 0.02..0.04, t1 - t0
211
+ assert_kind_of D, ret
212
+ end
168
213
  end
169
214
 
170
215
  class ReadTest < UMBaseTest
@@ -173,7 +218,9 @@ class ReadTest < UMBaseTest
173
218
  w << 'foobar'
174
219
 
175
220
  buf = +''
221
+ assert_equal 0, machine.pending_count
176
222
  res = machine.read(r.fileno, buf, 3)
223
+ assert_equal 0, machine.pending_count
177
224
  assert_equal 3, res
178
225
  assert_equal 'foo', buf
179
226
 
@@ -195,6 +242,7 @@ class ReadTest < UMBaseTest
195
242
  assert_raises(Errno::EBADF) do
196
243
  machine.read(w.fileno, +'', 8192)
197
244
  end
245
+ assert_equal 0, machine.pending_count
198
246
  end
199
247
 
200
248
  def test_read_with_buffer_offset
@@ -230,22 +278,24 @@ end
230
278
 
231
279
  class ReadEachTest < UMBaseTest
232
280
  def test_read_each
281
+ skip if UringMachine.kernel_version < 607
282
+
233
283
  r, w = IO.pipe
234
284
  bufs = []
235
-
236
285
  bgid = machine.setup_buffer_ring(4096, 1024)
237
286
  assert_equal 0, bgid
238
287
 
239
288
  f = Fiber.new do
240
289
  w << 'foo'
241
- machine.snooze
290
+ machine.sleep 0.02
242
291
  w << 'bar'
243
- machine.snooze
292
+ machine.sleep 0.02
244
293
  w << 'baz'
245
- machine.snooze
294
+ machine.sleep 0.02
246
295
  w.close
247
296
  machine.yield
248
297
  end
298
+
249
299
  machine.schedule(f, nil)
250
300
 
251
301
  machine.read_each(r.fileno, bgid) do |buf|
@@ -258,8 +308,9 @@ class ReadEachTest < UMBaseTest
258
308
 
259
309
  # send once and close write fd
260
310
  def test_read_each_raising_1
261
- r, w = IO.pipe
311
+ skip if UringMachine.kernel_version < 607
262
312
 
313
+ r, w = IO.pipe
263
314
  bgid = machine.setup_buffer_ring(4096, 1024)
264
315
  assert_equal 0, bgid
265
316
 
@@ -281,8 +332,9 @@ class ReadEachTest < UMBaseTest
281
332
 
282
333
  # send once and leave write fd open
283
334
  def test_read_each_raising_2
284
- r, w = IO.pipe
335
+ skip if UringMachine.kernel_version < 607
285
336
 
337
+ r, w = IO.pipe
286
338
  bgid = machine.setup_buffer_ring(4096, 1024)
287
339
  assert_equal 0, bgid
288
340
 
@@ -299,17 +351,15 @@ class ReadEachTest < UMBaseTest
299
351
  assert_kind_of RuntimeError, e
300
352
  assert_equal 'hi', e.message
301
353
 
302
- # since the write fd is still open, the read_each impl is supposed to cancel
303
- # the op, which is done asynchronously.
304
- assert_equal 1, machine.pending_count
305
- machine.snooze
354
+ machine.snooze # in case the final CQE has not yet arrived
306
355
  assert_equal 0, machine.pending_count
307
356
  end
308
357
 
309
358
  # send twice
310
359
  def test_read_each_raising_3
311
- r, w = IO.pipe
360
+ skip if UringMachine.kernel_version < 607
312
361
 
362
+ r, w = IO.pipe
313
363
  bgid = machine.setup_buffer_ring(4096, 1024)
314
364
  assert_equal 0, bgid
315
365
 
@@ -327,19 +377,55 @@ class ReadEachTest < UMBaseTest
327
377
  assert_kind_of RuntimeError, e
328
378
  assert_equal 'hi', e.message
329
379
 
330
- # since the write fd is still open, the read_each impl is supposed to cancel
331
- # the op, which is done asynchronously.
332
- assert_equal 1, machine.pending_count
333
- machine.snooze
380
+ machine.snooze # in case the final CQE has not yet arrived
334
381
  assert_equal 0, machine.pending_count
335
382
  end
383
+
384
+ def test_read_each_break
385
+ skip if UringMachine.kernel_version < 607
386
+
387
+ r, w = IO.pipe
388
+ bgid = machine.setup_buffer_ring(4096, 1024)
389
+
390
+ t = Thread.new do
391
+ sleep 0.1
392
+ w << 'foo'
393
+ sleep 0.1
394
+ w.close
395
+ end
396
+
397
+ bufs = []
398
+ machine.read_each(r.fileno, bgid) do |b|
399
+ bufs << b
400
+ break
401
+ end
402
+
403
+ assert_equal ['foo'], bufs
404
+ machine.snooze # in case the final CQE has not yet arrived
405
+ assert_equal 0, machine.pending_count
406
+ ensure
407
+ t&.kill
408
+ end
409
+
410
+ def test_read_each_bad_file
411
+ skip if UringMachine.kernel_version < 607
412
+
413
+ _r, w = IO.pipe
414
+ bgid = machine.setup_buffer_ring(4096, 1024)
415
+
416
+ assert_raises(Errno::EBADF) do
417
+ machine.read_each(w.fileno, bgid)
418
+ end
419
+ end
336
420
  end
337
421
 
338
422
  class WriteTest < UMBaseTest
339
423
  def test_write
340
424
  r, w = IO.pipe
341
425
 
426
+ assert_equal 0, machine.pending_count
342
427
  machine.write(w.fileno, 'foo')
428
+ assert_equal 0, machine.pending_count
343
429
  assert_equal 'foo', r.readpartial(3)
344
430
 
345
431
  machine.write(w.fileno, 'bar', 2)
@@ -349,16 +435,33 @@ class WriteTest < UMBaseTest
349
435
  def test_write_bad_fd
350
436
  r, _w = IO.pipe
351
437
 
438
+ assert_equal 0, machine.pending_count
352
439
  assert_raises(Errno::EBADF) do
353
440
  machine.write(r.fileno, 'foo')
354
441
  end
442
+ assert_equal 0, machine.pending_count
443
+ end
444
+ end
445
+
446
+ class Closetest < UMBaseTest
447
+ def test_close
448
+ r, w = IO.pipe
449
+ machine.write(w.fileno, 'foo')
450
+ assert_equal 'foo', r.readpartial(3)
451
+
452
+ assert_equal 0, machine.pending_count
453
+ machine.close(w.fileno)
454
+ assert_equal 0, machine.pending_count
455
+ assert_equal '', r.read
456
+
457
+ assert_raises(Errno::EBADF) { machine.close(w.fileno) }
355
458
  end
356
459
  end
357
460
 
358
461
  class AcceptTest < UMBaseTest
359
462
  def setup
360
463
  super
361
- @port = 9000 + rand(1000)
464
+ @port = assign_port
362
465
  @server = TCPServer.open('127.0.0.1', @port)
363
466
  end
364
467
 
@@ -370,7 +473,9 @@ class AcceptTest < UMBaseTest
370
473
  def test_accept
371
474
  conn = TCPSocket.new('127.0.0.1', @port)
372
475
 
476
+ assert_equal 0, machine.pending_count
373
477
  fd = machine.accept(@server.fileno)
478
+ assert_equal 0, machine.pending_count
374
479
  assert_kind_of Integer, fd
375
480
  assert fd > 0
376
481
 
@@ -384,7 +489,7 @@ end
384
489
  class AcceptEachTest < UMBaseTest
385
490
  def setup
386
491
  super
387
- @port = 9000 + rand(1000)
492
+ @port = assign_port
388
493
  @server = TCPServer.open('127.0.0.1', @port)
389
494
  end
390
495
 
@@ -394,21 +499,555 @@ class AcceptEachTest < UMBaseTest
394
499
  end
395
500
 
396
501
  def test_accept_each
397
- conns = 3.times.map { TCPSocket.new('127.0.0.1', @port) }
502
+ conns = []
503
+ t = Thread.new do
504
+ sleep 0.05
505
+ 3.times { conns << TCPSocket.new('127.0.0.1', @port) }
506
+ end
398
507
 
399
508
  count = 0
400
509
  machine.accept_each(@server.fileno) do |fd|
401
- machine.write(fd, (count += 1).to_s)
510
+ count += 1
402
511
  break if count == 3
403
512
  end
404
513
 
405
514
  assert_equal 3, count
406
- assert_equal 1, machine.pending_count
407
- machine.snooze
408
515
  assert_equal 0, machine.pending_count
516
+ ensure
517
+ t&.kill
518
+ end
519
+ end
520
+
521
+ class SocketTest < UMBaseTest
522
+ def test_socket
523
+ assert_equal 0, machine.pending_count
524
+ fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0);
525
+ assert_equal 0, machine.pending_count
526
+ assert_kind_of Integer, fd
527
+ assert fd > 0
528
+
529
+ assert_raises(Errno::EDESTADDRREQ) { machine.write(fd, 'foo') }
530
+ end
531
+ end
532
+
533
+ class ConnectTest < UMBaseTest
534
+ def setup
535
+ super
536
+ @port = assign_port
537
+ @server = TCPServer.open('127.0.0.1', @port)
538
+ end
539
+
540
+ def teardown
541
+ @server&.close
542
+ super
543
+ end
544
+
545
+ def test_connect
546
+ t = Thread.new do
547
+ conn = @server.accept
548
+ conn.write('foobar')
549
+ sleep
550
+ end
551
+
552
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
553
+ assert_equal 0, machine.pending_count
554
+ res = machine.connect(fd, '127.0.0.1', @port)
555
+ assert_equal 0, machine.pending_count
556
+ assert_equal 0, res
557
+
558
+ buf = +''
559
+ res = machine.read(fd, buf, 42)
560
+ assert_equal 6, res
561
+ assert_equal 'foobar', buf
562
+ ensure
563
+ t&.kill
564
+ end
565
+
566
+ def test_connect_with_bad_addr
567
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
568
+ assert_equal 0, machine.pending_count
569
+ assert_raises(Errno::ENETUNREACH) { machine.connect(fd, 'a.b.c.d', @port) }
570
+ assert_equal 0, machine.pending_count
571
+ end
572
+ end
573
+
574
+ class SendTest < UMBaseTest
575
+ def setup
576
+ super
577
+ @port = assign_port
578
+ @server = TCPServer.open('127.0.0.1', @port)
579
+ end
580
+
581
+ def teardown
582
+ @server&.close
583
+ super
584
+ end
585
+
586
+ def test_send
587
+ t = Thread.new do
588
+ conn = @server.accept
589
+ str = conn.readpartial(42)
590
+ conn.write("You said: #{str}")
591
+ sleep
592
+ end
593
+
594
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
595
+ res = machine.connect(fd, '127.0.0.1', @port)
596
+ assert_equal 0, res
597
+
598
+ res = machine.send(fd, 'foobar', 6, 0)
599
+ assert_equal 6, res
600
+
601
+ buf = +''
602
+ res = machine.read(fd, buf, 42)
603
+ assert_equal 16, res
604
+ assert_equal 'You said: foobar', buf
605
+ ensure
606
+ t&.kill
607
+ end
608
+ end
609
+
610
+ class RecvTest < UMBaseTest
611
+ def setup
612
+ super
613
+ @port = assign_port
614
+ @server = TCPServer.open('127.0.0.1', @port)
615
+ end
616
+
617
+ def teardown
618
+ @server&.close
619
+ super
620
+ end
621
+
622
+ def test_recv
623
+ t = Thread.new do
624
+ conn = @server.accept
625
+ conn.write('foobar')
626
+ sleep
627
+ end
628
+
629
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
630
+ res = machine.connect(fd, '127.0.0.1', @port)
631
+ assert_equal 0, res
632
+
633
+ buf = +''
634
+ res = machine.recv(fd, buf, 42, 0)
635
+ assert_equal 6, res
636
+ assert_equal 'foobar', buf
637
+ ensure
638
+ t&.kill
639
+ end
640
+ end
641
+
642
+ class RecvEachTest < UMBaseTest
643
+ def setup
644
+ super
645
+ @port = assign_port
646
+ @server = TCPServer.open('127.0.0.1', @port)
647
+ end
648
+
649
+ def teardown
650
+ @server&.close
651
+ super
652
+ end
653
+
654
+ def test_recv_each
655
+ t = Thread.new do
656
+ conn = @server.accept
657
+ conn.write('abc')
658
+ sleep 0.01
659
+ conn.write('def')
660
+ sleep 0.01
661
+ conn.write('ghi')
662
+ sleep 0.01
663
+ conn.close
664
+ sleep
665
+ end
666
+
667
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
668
+ res = machine.connect(fd, '127.0.0.1', @port)
669
+ assert_equal 0, res
670
+
671
+ bgid = machine.setup_buffer_ring(4096, 1024)
672
+ assert_equal 0, bgid
673
+
674
+ bgid2 = machine.setup_buffer_ring(4096, 1024)
675
+ assert_equal 1, bgid2
676
+
677
+ bufs = []
678
+
679
+ machine.recv_each(fd, bgid, 0) do |buf|
680
+ bufs << buf
681
+ end
682
+ assert_equal ['abc', 'def', 'ghi'], bufs
683
+ ensure
684
+ t&.kill
685
+ end
686
+ end
687
+
688
+ class BindTest < UMBaseTest
689
+ def setup
690
+ super
691
+ @port = assign_port
692
+ end
693
+
694
+ def test_bind
695
+ assert_equal 0, machine.pending_count
696
+ fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
697
+ res = machine.bind(fd, '127.0.0.1', @port)
698
+ assert_equal 0, res
699
+ assert_equal 0, machine.pending_count
700
+
701
+ peer = UDPSocket.new
702
+ peer.connect('127.0.0.1', @port)
703
+ peer.send 'foo', 0
704
+
705
+ buf = +''
706
+ res = machine.recv(fd, buf, 8192, 0)
707
+ assert_equal 3, res
708
+ assert_equal 'foo', buf
709
+ end
710
+
711
+ def test_bind_invalid_args
712
+ assert_equal 0, machine.pending_count
713
+
714
+ fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
715
+ assert_raises(Errno::EACCES) { machine.bind(fd, 'foo.bar.baz', 3) }
716
+ assert_raises(Errno::EBADF) { machine.bind(-3, '127.0.01', 1234) }
717
+
718
+ assert_equal 0, machine.pending_count
719
+ end
720
+ end
721
+
722
+ class ListenTest < UMBaseTest
723
+ def setup
724
+ super
725
+ @port = assign_port
726
+ end
727
+
728
+ def test_listen
729
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
730
+ machine.bind(fd, '127.0.0.1', @port)
731
+ res = machine.listen(fd, 5)
732
+ assert_equal 0, res
733
+ assert_equal 0, machine.pending_count
734
+
735
+ conn = nil
736
+ t = Thread.new do
737
+ sleep 0.01
738
+ conn = TCPSocket.new('127.0.0.1', @port)
739
+ end
740
+
741
+ conn_fd = machine.accept(fd)
742
+ t.join
743
+ assert_kind_of TCPSocket, conn
744
+
745
+ machine.send(conn_fd, 'foo', 3, 0)
746
+
747
+ buf = conn.readpartial(42)
748
+ assert_equal 'foo', buf
749
+ ensure
750
+ t&.kill
751
+ end
752
+ end
753
+
754
+ class ConstTest < UMBaseTest
755
+ def test_constants
756
+ assert_equal UM::SOCK_STREAM, UM::SOCK_STREAM
757
+ end
758
+ end
759
+
760
+ class GetSetSockOptTest < UMBaseTest
761
+ def test_getsockopt_setsockopt
762
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
763
+ reuseaddr = machine.getsockopt(fd, UM::SOL_SOCKET, UM::SO_REUSEADDR)
764
+ assert_equal 0, reuseaddr
765
+
766
+ res = machine.setsockopt(fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
767
+ assert_equal 0, res
768
+
769
+ reuseaddr = machine.getsockopt(fd, UM::SOL_SOCKET, UM::SO_REUSEADDR)
770
+ assert_equal 1, reuseaddr
771
+ end
772
+ end
773
+
774
+ class SynchronizeTest < UMBaseTest
775
+ def test_synchronize_single
776
+ skip if !machine.respond_to?(:synchronize)
777
+
778
+ m = UM::Mutex.new
779
+
780
+ buf = []
781
+ machine.synchronize(m) do
782
+ buf << 1
783
+ end
784
+ machine.synchronize(m) do
785
+ buf << 2
786
+ end
787
+
788
+ assert_equal [1, 2], buf
789
+ assert_equal 0, machine.pending_count
790
+ end
791
+
792
+ def test_synchronize_pair
793
+ skip if !machine.respond_to?(:synchronize)
794
+ m = UM::Mutex.new
795
+
796
+ buf = []
797
+
798
+ f1 = Fiber.new do
799
+ machine.synchronize(m) do
800
+ buf << 11
801
+ machine.sleep(0.01)
802
+ buf << 12
803
+ end
804
+ buf << 13
805
+ machine.yield
806
+ end
807
+
808
+ f2 = Fiber.new do
809
+ machine.synchronize(m) do
810
+ buf << 21
811
+ machine.sleep(0.01)
812
+ buf << 22
813
+ end
814
+ buf << 23
815
+ machine.yield
816
+ end
817
+
818
+ machine.schedule(f1, nil)
819
+ machine.schedule(f2, nil)
820
+
821
+ machine.sleep(0.03)
822
+ assert_equal [11, 12, 13, 21, 22, 23], buf
823
+ assert_equal 0, machine.pending_count
824
+ end
825
+ end
826
+
827
+ class QueueTest < UMBaseTest
828
+ def test_push_pop_1
829
+ skip if !machine.respond_to?(:synchronize)
830
+
831
+ q = UM::Queue.new
832
+ assert_equal 0, q.count
833
+ machine.push(q, :foo)
834
+ machine.push(q, :bar)
835
+ assert_equal 2, q.count
836
+
837
+ assert_equal :bar, machine.pop(q)
838
+ assert_equal 1, q.count
839
+ assert_equal :foo, machine.pop(q)
840
+ assert_equal 0, q.count
841
+ end
842
+
843
+ def test_push_pop_2
844
+ skip if !machine.respond_to?(:synchronize)
845
+
846
+ q = UM::Queue.new
847
+ buf = []
409
848
 
410
- assert_equal '1', conns[0].readpartial(3)
411
- assert_equal '2', conns[1].readpartial(3)
412
- assert_equal '3', conns[2].readpartial(3)
849
+ f1 = Fiber.new do
850
+ buf << [1, machine.pop(q)]
851
+ machine.yield
852
+ end
853
+
854
+ machine.schedule(f1, nil)
855
+
856
+ f2 = Fiber.new do
857
+ buf << [2, machine.pop(q)]
858
+ machine.yield
859
+ end
860
+
861
+ machine.schedule(f2, nil)
862
+
863
+ machine.snooze
864
+ assert_equal [], buf
865
+
866
+ machine.push(q, :foo)
867
+ assert_equal 1, q.count
868
+ machine.sleep(0.02)
869
+ assert_equal [[1, :foo]], buf
870
+
871
+ machine.push(q, :bar)
872
+ assert_equal 1, q.count
873
+
874
+ machine.sleep(0.02)
875
+ assert_equal [[1, :foo], [2, :bar]], buf
876
+ assert_equal 0, q.count
877
+ end
878
+
879
+ def test_push_pop_3
880
+ skip if !machine.respond_to?(:synchronize)
881
+
882
+ q = UM::Queue.new
883
+ buf = []
884
+
885
+ machine.push(q, :foo)
886
+ machine.push(q, :bar)
887
+ assert_equal 2, q.count
888
+
889
+ f1 = Fiber.new do
890
+ buf << [1, machine.pop(q)]
891
+ machine.yield
892
+ end
893
+ machine.schedule(f1, nil)
894
+
895
+ f2 = Fiber.new do
896
+ buf << [2, machine.pop(q)]
897
+ machine.yield
898
+ end
899
+ machine.schedule(f2, nil)
900
+
901
+ 3.times { machine.snooze }
902
+
903
+ assert_equal [[1, :bar], [2, :foo]], buf.sort
904
+ assert_equal 0, q.count
905
+ end
906
+
907
+ def test_push_pop_4
908
+ skip if !machine.respond_to?(:synchronize)
909
+
910
+ q = UM::Queue.new
911
+ buf = []
912
+
913
+ machine.push(q, :foo)
914
+ assert_equal 1, q.count
915
+
916
+ f1 = Fiber.new do
917
+ buf << [1, machine.pop(q)]
918
+ machine.yield
919
+ end
920
+ machine.schedule(f1, nil)
921
+
922
+ f2 = Fiber.new do
923
+ buf << [2, machine.pop(q)]
924
+ machine.yield
925
+ end
926
+ machine.schedule(f2, nil)
927
+
928
+ machine.sleep 0.01
929
+
930
+ assert_equal [[1, :foo]], buf
931
+ machine.push(q, :bar)
932
+
933
+ machine.sleep 0.01
934
+ assert_equal [[1, :foo], [2, :bar]], buf
935
+ end
936
+
937
+ def test_push_shift_1
938
+ skip if !machine.respond_to?(:synchronize)
939
+
940
+ q = UM::Queue.new
941
+
942
+ machine.push(q, :foo)
943
+ machine.push(q, :bar)
944
+ machine.push(q, :baz)
945
+
946
+ assert_equal :foo, machine.shift(q)
947
+ assert_equal :bar, machine.shift(q)
948
+ assert_equal :baz, machine.shift(q)
949
+ end
950
+
951
+ def test_shift_shift_1
952
+ skip if !machine.respond_to?(:synchronize)
953
+
954
+ q = UM::Queue.new
955
+
956
+ machine.unshift(q, :foo)
957
+ machine.unshift(q, :bar)
958
+ machine.unshift(q, :baz)
959
+
960
+ assert_equal :baz, machine.shift(q)
961
+ assert_equal :bar, machine.shift(q)
962
+ assert_equal :foo, machine.shift(q)
413
963
  end
414
964
  end
965
+
966
+ class OpenTest < UMBaseTest
967
+ PATH = '/tmp/um_open_test'
968
+
969
+ def setup
970
+ super
971
+ FileUtils.rm(PATH, force: true)
972
+ end
973
+
974
+ def test_open
975
+ fd = machine.open(PATH, UM::O_CREAT | UM::O_WRONLY)
976
+ assert_kind_of Integer, fd
977
+ assert File.file?(PATH)
978
+
979
+ machine.write(fd, 'foo')
980
+ machine.close(fd)
981
+
982
+ assert_equal 'foo', IO.read(PATH)
983
+ end
984
+
985
+ def test_open_with_block
986
+ res = machine.open(PATH, UM::O_CREAT | UM::O_WRONLY) do |fd|
987
+ machine.write(fd, 'bar')
988
+ fd
989
+ end
990
+
991
+ assert_kind_of Integer, res
992
+ assert_raises(Errno::EBADF) { machine.close(res) }
993
+ assert_equal 'bar', IO.read(PATH)
994
+ end
995
+
996
+ def test_open_bad_arg
997
+ assert_raises(Errno::ENOENT) { machine.open(PATH, UM::O_RDONLY) }
998
+ assert_raises(Errno::ENOENT) { machine.open(PATH, UM::O_RDONLY) {} }
999
+ end
1000
+ end
1001
+
1002
+ class PipeTest < UMBaseTest
1003
+ def test_pipe
1004
+ rfd, wfd = UM.pipe
1005
+ ret = machine.write(wfd, 'foo')
1006
+ assert_equal 3, ret
1007
+
1008
+ ret = machine.close(wfd)
1009
+ assert_equal wfd, ret
1010
+
1011
+ buf = +''
1012
+ ret = machine.read(rfd, buf, 8192)
1013
+
1014
+ assert_equal 3, ret
1015
+ assert_equal 'foo', buf
1016
+
1017
+ ret = machine.close(rfd)
1018
+ assert_equal rfd, ret
1019
+ end
1020
+ end
1021
+
1022
+ class WaitTest < UMBaseTest
1023
+ def test_waitpid
1024
+ skip if UM.kernel_version < 607
1025
+
1026
+ msg = 'hello from child'
1027
+
1028
+ rfd, wfd = UM.pipe
1029
+ pid = fork do
1030
+ m = UM.new
1031
+ m.write(wfd, msg)
1032
+ m.close(wfd)
1033
+ exit 42
1034
+ end
1035
+
1036
+ ret = machine.waitpid(pid, UM::WEXITED)
1037
+ assert_kind_of Array, ret
1038
+ assert_equal [pid, 42], ret
1039
+
1040
+ buf = +''
1041
+ ret = machine.read(rfd, buf, 8192)
1042
+ assert_equal msg.bytesize, ret
1043
+ assert_equal msg, buf
1044
+ end
1045
+
1046
+ def test_waitpid_bad_pid
1047
+ skip if UM.kernel_version < 607
1048
+
1049
+ assert_raises(Errno::ECHILD) { machine.waitpid(1, UM::WEXITED) }
1050
+ end
1051
+
1052
+ end
1053
+