uringmachine 0.4 → 0.5.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/.github/workflows/test.yml +2 -1
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +44 -1
  5. data/TODO.md +12 -3
  6. data/examples/bm_snooze.rb +89 -0
  7. data/examples/bm_sqlite.rb +89 -0
  8. data/examples/bm_write.rb +56 -0
  9. data/examples/dns_client.rb +12 -0
  10. data/examples/http_server.rb +42 -43
  11. data/examples/pg.rb +85 -0
  12. data/examples/server_client.rb +64 -0
  13. data/examples/snooze.rb +44 -0
  14. data/examples/stream.rb +85 -0
  15. data/examples/write_dev_null.rb +16 -0
  16. data/ext/um/extconf.rb +81 -14
  17. data/ext/um/um.c +468 -414
  18. data/ext/um/um.h +149 -40
  19. data/ext/um/um_async_op.c +40 -0
  20. data/ext/um/um_async_op_class.c +136 -0
  21. data/ext/um/um_buffer.c +49 -0
  22. data/ext/um/um_class.c +176 -44
  23. data/ext/um/um_const.c +174 -9
  24. data/ext/um/um_ext.c +8 -0
  25. data/ext/um/um_mutex_class.c +47 -0
  26. data/ext/um/um_op.c +89 -111
  27. data/ext/um/um_queue_class.c +58 -0
  28. data/ext/um/um_ssl.c +850 -0
  29. data/ext/um/um_ssl.h +22 -0
  30. data/ext/um/um_ssl_class.c +138 -0
  31. data/ext/um/um_sync.c +273 -0
  32. data/ext/um/um_utils.c +1 -1
  33. data/lib/uringmachine/dns_resolver.rb +84 -0
  34. data/lib/uringmachine/ssl/context_builder.rb +96 -0
  35. data/lib/uringmachine/ssl.rb +394 -0
  36. data/lib/uringmachine/version.rb +1 -1
  37. data/lib/uringmachine.rb +27 -3
  38. data/supressions/ruby.supp +71 -0
  39. data/test/helper.rb +6 -0
  40. data/test/test_async_op.rb +119 -0
  41. data/test/test_ssl.rb +155 -0
  42. data/test/test_um.rb +464 -47
  43. data/uringmachine.gemspec +3 -2
  44. data/vendor/liburing/.gitignore +5 -0
  45. data/vendor/liburing/CHANGELOG +1 -0
  46. data/vendor/liburing/configure +32 -0
  47. data/vendor/liburing/examples/Makefile +1 -0
  48. data/vendor/liburing/examples/reg-wait.c +159 -0
  49. data/vendor/liburing/liburing.spec +1 -1
  50. data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
  51. data/vendor/liburing/src/include/liburing.h +28 -2
  52. data/vendor/liburing/src/int_flags.h +10 -3
  53. data/vendor/liburing/src/liburing-ffi.map +13 -2
  54. data/vendor/liburing/src/liburing.map +9 -0
  55. data/vendor/liburing/src/queue.c +25 -16
  56. data/vendor/liburing/src/register.c +73 -4
  57. data/vendor/liburing/src/setup.c +46 -18
  58. data/vendor/liburing/src/setup.h +6 -0
  59. data/vendor/liburing/test/Makefile +7 -0
  60. data/vendor/liburing/test/cmd-discard.c +427 -0
  61. data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
  62. data/vendor/liburing/test/file-exit-unreg.c +48 -0
  63. data/vendor/liburing/test/io_uring_passthrough.c +2 -0
  64. data/vendor/liburing/test/io_uring_register.c +13 -2
  65. data/vendor/liburing/test/napi-test.c +1 -1
  66. data/vendor/liburing/test/no-mmap-inval.c +1 -1
  67. data/vendor/liburing/test/read-mshot-empty.c +2 -0
  68. data/vendor/liburing/test/read-mshot-stdin.c +121 -0
  69. data/vendor/liburing/test/read-mshot.c +6 -0
  70. data/vendor/liburing/test/recvsend_bundle.c +2 -2
  71. data/vendor/liburing/test/reg-fd-only.c +1 -1
  72. data/vendor/liburing/test/reg-wait.c +251 -0
  73. data/vendor/liburing/test/regbuf-clone.c +458 -0
  74. data/vendor/liburing/test/resize-rings.c +643 -0
  75. data/vendor/liburing/test/rsrc_tags.c +1 -1
  76. data/vendor/liburing/test/sqpoll-sleep.c +39 -8
  77. data/vendor/liburing/test/sqwait.c +136 -0
  78. data/vendor/liburing/test/sync-cancel.c +8 -1
  79. data/vendor/liburing/test/timeout.c +13 -8
  80. metadata +52 -8
  81. data/examples/http_server_multishot.rb +0 -57
  82. 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
@@ -167,6 +182,34 @@ class SleepTest < UMBaseTest
167
182
  assert_in_range 0.09..0.13, t1 - t0
168
183
  assert_equal 0.1, res
169
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
170
213
  end
171
214
 
172
215
  class ReadTest < UMBaseTest
@@ -199,6 +242,7 @@ class ReadTest < UMBaseTest
199
242
  assert_raises(Errno::EBADF) do
200
243
  machine.read(w.fileno, +'', 8192)
201
244
  end
245
+ assert_equal 0, machine.pending_count
202
246
  end
203
247
 
204
248
  def test_read_with_buffer_offset
@@ -234,22 +278,24 @@ end
234
278
 
235
279
  class ReadEachTest < UMBaseTest
236
280
  def test_read_each
281
+ skip if UringMachine.kernel_version < 607
282
+
237
283
  r, w = IO.pipe
238
284
  bufs = []
239
-
240
285
  bgid = machine.setup_buffer_ring(4096, 1024)
241
286
  assert_equal 0, bgid
242
287
 
243
288
  f = Fiber.new do
244
289
  w << 'foo'
245
- machine.snooze
290
+ machine.sleep 0.02
246
291
  w << 'bar'
247
- machine.snooze
292
+ machine.sleep 0.02
248
293
  w << 'baz'
249
- machine.snooze
294
+ machine.sleep 0.02
250
295
  w.close
251
296
  machine.yield
252
297
  end
298
+
253
299
  machine.schedule(f, nil)
254
300
 
255
301
  machine.read_each(r.fileno, bgid) do |buf|
@@ -262,8 +308,9 @@ class ReadEachTest < UMBaseTest
262
308
 
263
309
  # send once and close write fd
264
310
  def test_read_each_raising_1
265
- r, w = IO.pipe
311
+ skip if UringMachine.kernel_version < 607
266
312
 
313
+ r, w = IO.pipe
267
314
  bgid = machine.setup_buffer_ring(4096, 1024)
268
315
  assert_equal 0, bgid
269
316
 
@@ -285,8 +332,9 @@ class ReadEachTest < UMBaseTest
285
332
 
286
333
  # send once and leave write fd open
287
334
  def test_read_each_raising_2
288
- r, w = IO.pipe
335
+ skip if UringMachine.kernel_version < 607
289
336
 
337
+ r, w = IO.pipe
290
338
  bgid = machine.setup_buffer_ring(4096, 1024)
291
339
  assert_equal 0, bgid
292
340
 
@@ -303,17 +351,15 @@ class ReadEachTest < UMBaseTest
303
351
  assert_kind_of RuntimeError, e
304
352
  assert_equal 'hi', e.message
305
353
 
306
- # since the write fd is still open, the read_each impl is supposed to cancel
307
- # the op, which is done asynchronously.
308
- assert_equal 1, machine.pending_count
309
- machine.snooze
354
+ machine.snooze # in case the final CQE has not yet arrived
310
355
  assert_equal 0, machine.pending_count
311
356
  end
312
357
 
313
358
  # send twice
314
359
  def test_read_each_raising_3
315
- r, w = IO.pipe
360
+ skip if UringMachine.kernel_version < 607
316
361
 
362
+ r, w = IO.pipe
317
363
  bgid = machine.setup_buffer_ring(4096, 1024)
318
364
  assert_equal 0, bgid
319
365
 
@@ -331,12 +377,46 @@ class ReadEachTest < UMBaseTest
331
377
  assert_kind_of RuntimeError, e
332
378
  assert_equal 'hi', e.message
333
379
 
334
- # since the write fd is still open, the read_each impl is supposed to cancel
335
- # the op, which is done asynchronously.
336
- assert_equal 1, machine.pending_count
337
- machine.snooze
380
+ machine.snooze # in case the final CQE has not yet arrived
338
381
  assert_equal 0, machine.pending_count
339
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
340
420
  end
341
421
 
342
422
  class WriteTest < UMBaseTest
@@ -421,7 +501,7 @@ class AcceptEachTest < UMBaseTest
421
501
  def test_accept_each
422
502
  conns = []
423
503
  t = Thread.new do
424
- sleep 0.1
504
+ sleep 0.05
425
505
  3.times { conns << TCPSocket.new('127.0.0.1', @port) }
426
506
  end
427
507
 
@@ -432,8 +512,6 @@ class AcceptEachTest < UMBaseTest
432
512
  end
433
513
 
434
514
  assert_equal 3, count
435
- assert_equal 1, machine.pending_count
436
- machine.snooze
437
515
  assert_equal 0, machine.pending_count
438
516
  ensure
439
517
  t&.kill
@@ -471,7 +549,7 @@ class ConnectTest < UMBaseTest
471
549
  sleep
472
550
  end
473
551
 
474
- fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
552
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
475
553
  assert_equal 0, machine.pending_count
476
554
  res = machine.connect(fd, '127.0.0.1', @port)
477
555
  assert_equal 0, machine.pending_count
@@ -513,7 +591,7 @@ class SendTest < UMBaseTest
513
591
  sleep
514
592
  end
515
593
 
516
- fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
594
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
517
595
  res = machine.connect(fd, '127.0.0.1', @port)
518
596
  assert_equal 0, res
519
597
 
@@ -548,7 +626,7 @@ class RecvTest < UMBaseTest
548
626
  sleep
549
627
  end
550
628
 
551
- fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
629
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
552
630
  res = machine.connect(fd, '127.0.0.1', @port)
553
631
  assert_equal 0, res
554
632
 
@@ -561,6 +639,52 @@ class RecvTest < UMBaseTest
561
639
  end
562
640
  end
563
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
+
564
688
  class BindTest < UMBaseTest
565
689
  def setup
566
690
  super
@@ -569,7 +693,7 @@ class BindTest < UMBaseTest
569
693
 
570
694
  def test_bind
571
695
  assert_equal 0, machine.pending_count
572
- fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0);
696
+ fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
573
697
  res = machine.bind(fd, '127.0.0.1', @port)
574
698
  assert_equal 0, res
575
699
  assert_equal 0, machine.pending_count
@@ -587,7 +711,7 @@ class BindTest < UMBaseTest
587
711
  def test_bind_invalid_args
588
712
  assert_equal 0, machine.pending_count
589
713
 
590
- fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0);
714
+ fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
591
715
  assert_raises(Errno::EACCES) { machine.bind(fd, 'foo.bar.baz', 3) }
592
716
  assert_raises(Errno::EBADF) { machine.bind(-3, '127.0.01', 1234) }
593
717
 
@@ -602,7 +726,7 @@ class ListenTest < UMBaseTest
602
726
  end
603
727
 
604
728
  def test_listen
605
- fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
729
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
606
730
  machine.bind(fd, '127.0.0.1', @port)
607
731
  res = machine.listen(fd, 5)
608
732
  assert_equal 0, res
@@ -631,4 +755,297 @@ class ConstTest < UMBaseTest
631
755
  def test_constants
632
756
  assert_equal UM::SOCK_STREAM, UM::SOCK_STREAM
633
757
  end
634
- 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 = []
848
+
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)
963
+ end
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
+ end
data/uringmachine.gemspec CHANGED
@@ -20,8 +20,9 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
  s.required_ruby_version = '>= 3.3'
22
22
 
23
- s.add_development_dependency 'rake-compiler', '1.2.7'
23
+ s.add_development_dependency 'rake-compiler', '1.2.8'
24
24
  s.add_development_dependency 'minitest', '5.25.1'
25
25
  s.add_development_dependency 'http_parser.rb', '0.8.0'
26
- s.add_development_dependency 'benchmark-ips', '2.10.0'
26
+ s.add_development_dependency 'benchmark-ips', '2.14.0'
27
+ s.add_development_dependency 'localhost', '1.3.1'
27
28
  end
@@ -27,11 +27,16 @@
27
27
  /examples/send-zerocopy
28
28
  /examples/rsrc-update-bench
29
29
  /examples/kdigest
30
+ /examples/reg-wait
30
31
 
31
32
  /test/*.t
32
33
  /test/*.dmesg
33
34
  /test/output/
34
35
 
36
+ # Clang's compilation database file and directory.
37
+ /.cache
38
+ /compile_commands.json
39
+
35
40
  config-host.h
36
41
  config-host.mak
37
42
  config.log