uringmachine 0.20.0 → 0.21.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.
data/test/test_um.rb CHANGED
@@ -11,6 +11,80 @@ class UringMachineTest < Minitest::Test
11
11
  end
12
12
  end
13
13
 
14
+ class EntriesTest < Minitest::Test
15
+ def test_default_entries
16
+ m = UM.new
17
+ assert_equal 4096, m.entries
18
+ end
19
+
20
+ def test_custom_entries_value
21
+ m = UM.new(13)
22
+ assert_equal 13, m.entries
23
+ end
24
+ end
25
+
26
+ class SQPOLLTest < Minitest::Test
27
+ def test_sqpoll_timeout
28
+ m = UM.new(10, 0.05)
29
+
30
+ r, w = UM.pipe
31
+
32
+ buf = nil
33
+ t = Thread.new { buf = IO.new(r).readpartial(3) }
34
+
35
+ # let SQPOLL worker thread timeout
36
+ sleep(0.06)
37
+
38
+ # SQE is prepared but not submitted
39
+ m.write_async(w, 'foo')
40
+
41
+ # thread should timeout
42
+ ret = t.join(0.03)
43
+ assert_nil buf
44
+ ensure
45
+ t.kill rescue nil
46
+ end
47
+
48
+ def test_sqpoll_timeout_with_submit
49
+ m = UM.new(10, 0.05)
50
+
51
+ r, w = UM.pipe
52
+
53
+ buf = nil
54
+ t = Thread.new { buf = IO.new(r).readpartial(3) }
55
+
56
+ # let SQPOLL worker thread timeout
57
+ sleep(0.06)
58
+
59
+ # SQE is prepared but not submitted
60
+ m.write_async(w, 'foo')
61
+ ret = m.submit
62
+ assert_equal 1, ret
63
+
64
+ # thread should timeout
65
+ ret = t.join(0.1)
66
+ assert_equal 'foo', buf
67
+ ensure
68
+ t.kill rescue nil
69
+ end
70
+ end
71
+
72
+ class SubmitTest < UMBaseTest
73
+ def test_submit
74
+ _r, w = UM.pipe
75
+
76
+ machine.write_async(w, 'foo')
77
+ machine.write_async(w, 'bar')
78
+ machine.write_async(w, 'baz')
79
+
80
+ assert_equal 3, machine.pending_count
81
+ assert_equal 3, machine.submit
82
+ assert_equal 0, machine.submit
83
+ machine.snooze
84
+ assert_equal 0, machine.pending_count
85
+ end
86
+ end
87
+
14
88
  class SpinTest < UMBaseTest
15
89
  def test_spin
16
90
  x = nil
@@ -327,16 +401,36 @@ class PeriodicallyTest < UMBaseTest
327
401
  rescue Cancel
328
402
  cancel = 1
329
403
  end
330
- 20.times { machine.snooze }
331
- assert_equal 0, machine.pending_count
404
+ assert_equal 1, cancel
332
405
  t1 = monotonic_clock
333
406
  assert_in_range 0.05..0.08, t1 - t0
334
407
  assert_in_range 4..6, count
335
- assert_equal 1, cancel
336
408
 
337
409
  end
338
410
  end
339
411
 
412
+ class StatsTest < UMBaseTest
413
+ def test_op_counts
414
+ _r, w = IO.pipe
415
+
416
+ assert_equal 0, machine.pending_count
417
+ assert_equal 0, machine.total_op_count
418
+ machine.write_async(w.fileno, 'foo')
419
+ assert_equal 1, machine.pending_count
420
+ assert_equal 1, machine.total_op_count
421
+ machine.snooze
422
+ assert_equal 0, machine.pending_count
423
+ assert_equal 1, machine.total_op_count
424
+
425
+ machine.write_async(w.fileno, 'foo')
426
+ assert_equal 1, machine.pending_count
427
+ assert_equal 2, machine.total_op_count
428
+ machine.snooze
429
+ assert_equal 0, machine.pending_count
430
+ assert_equal 2, machine.total_op_count
431
+ end
432
+ end
433
+
340
434
  class ReadTest < UMBaseTest
341
435
  def test_read
342
436
  r, w = IO.pipe
@@ -464,6 +558,19 @@ class ReadTest < UMBaseTest
464
558
  machine.read(r, [])
465
559
  }
466
560
  end
561
+
562
+ def test_read_with_file_offset
563
+ fn = "/tmp/#{SecureRandom.hex}"
564
+ IO.write(fn, 'foobar')
565
+
566
+ fd = machine.open(fn, UM::O_RDONLY)
567
+ buffer = +''
568
+ result = machine.read(fd, buffer, 100, 0, 2)
569
+ assert_equal 4, result
570
+ assert_equal 'obar', buffer
571
+ ensure
572
+ machine.close(fd)
573
+ end
467
574
  end
468
575
 
469
576
  class ReadEachTest < UMBaseTest
@@ -614,11 +721,13 @@ class WriteTest < UMBaseTest
614
721
  r, w = IO.pipe
615
722
 
616
723
  assert_equal 0, machine.pending_count
617
- machine.write(w.fileno, 'foo')
724
+ res = machine.write(w.fileno, 'foo')
725
+ assert_equal 3, res
618
726
  assert_equal 0, machine.pending_count
619
727
  assert_equal 'foo', r.readpartial(3)
620
728
 
621
- machine.write(w.fileno, 'bar', 2)
729
+ res = machine.write(w.fileno, 'bar', 2)
730
+ assert_equal 2, res
622
731
  assert_equal 'ba', r.readpartial(3)
623
732
  end
624
733
 
@@ -632,6 +741,24 @@ class WriteTest < UMBaseTest
632
741
  assert_equal 0, machine.pending_count
633
742
  end
634
743
 
744
+ def test_write_zero_length
745
+ r, w = IO.pipe
746
+
747
+ res = machine.write(w.fileno, '')
748
+ assert_equal 0, res
749
+
750
+ res = machine.write(w.fileno, 'bar', 0)
751
+ assert_equal 0, res
752
+
753
+ buf = IO::Buffer.new(3)
754
+ buf.set_string('baz')
755
+ res = machine.write(w.fileno, buf, 0, 0)
756
+ assert_equal 0, res
757
+
758
+ w.close
759
+ assert_equal '', r.read
760
+ end
761
+
635
762
  def test_write_io_buffer
636
763
  r, w = UM.pipe
637
764
 
@@ -679,6 +806,19 @@ class WriteTest < UMBaseTest
679
806
  machine.write(w, [])
680
807
  }
681
808
  end
809
+
810
+ def test_write_with_file_offset
811
+ fn = "/tmp/#{SecureRandom.hex}"
812
+ IO.write(fn, 'foobar')
813
+
814
+ fd = machine.open(fn, UM::O_WRONLY)
815
+ result = machine.write(fd, 'baz', -1, 2)
816
+ assert_equal 3, result
817
+ assert_equal 'fobazr', IO.read(fn)
818
+ ensure
819
+ machine.close(fd)
820
+ end
821
+
682
822
  end
683
823
 
684
824
  class WriteAsyncTest < UMBaseTest
@@ -689,7 +829,7 @@ class WriteAsyncTest < UMBaseTest
689
829
  machine.write_async(w.fileno, 'foo')
690
830
  assert_equal 1, machine.pending_count
691
831
 
692
- machine.snooze
832
+ machine.snooze while machine.pending_count > 0
693
833
  assert_equal 0, machine.pending_count
694
834
  assert_equal 'foo', r.readpartial(3)
695
835
  end
@@ -705,7 +845,7 @@ class WriteAsyncTest < UMBaseTest
705
845
  GC.start
706
846
  assert_equal 1, machine.pending_count
707
847
 
708
- machine.snooze
848
+ machine.snooze while machine.pending_count > 0
709
849
  assert_equal 0, machine.pending_count
710
850
  assert_equal "foo#{123}#{'bar' * 48}", r.readpartial(len)
711
851
  end
@@ -728,7 +868,7 @@ class WriteAsyncTest < UMBaseTest
728
868
  write_buffer.set_string(msg)
729
869
 
730
870
  machine.write_async(w, write_buffer)
731
- 3.times { machine.snooze }
871
+ machine.snooze while machine.pending_count > 0
732
872
  machine.close(w)
733
873
 
734
874
  str = +''
@@ -741,6 +881,32 @@ class WriteAsyncTest < UMBaseTest
741
881
 
742
882
  assert_raises(UM::Error) { machine.write_async(w, []) }
743
883
  end
884
+
885
+ def test_write_async_with_len
886
+ r, w = IO.pipe
887
+
888
+ assert_equal 0, machine.pending_count
889
+ machine.write_async(w.fileno, 'foobar', 4)
890
+
891
+ assert_equal 1, machine.pending_count
892
+ machine.snooze while machine.pending_count > 0
893
+ assert_equal 0, machine.pending_count
894
+ assert_equal 'foob', r.readpartial(6)
895
+ end
896
+
897
+ def test_write_async_with_file_offset
898
+ fn = "/tmp/#{SecureRandom.hex}"
899
+ IO.write(fn, 'foobar')
900
+
901
+ fd = machine.open(fn, UM::O_WRONLY)
902
+ machine.write_async(fd, 'baz', -1, 2)
903
+
904
+ assert_equal 1, machine.pending_count
905
+ machine.snooze while machine.pending_count > 0
906
+ assert_equal 'fobazr', IO.read(fn)
907
+ ensure
908
+ machine.close(fd)
909
+ end
744
910
  end
745
911
 
746
912
  class CloseTest < UMBaseTest
@@ -1276,8 +1442,6 @@ end
1276
1442
 
1277
1443
  class SynchronizeTest < UMBaseTest
1278
1444
  def test_synchronize_single
1279
- skip if !machine.respond_to?(:synchronize)
1280
-
1281
1445
  m = UM::Mutex.new
1282
1446
 
1283
1447
  buf = []
@@ -1293,7 +1457,6 @@ class SynchronizeTest < UMBaseTest
1293
1457
  end
1294
1458
 
1295
1459
  def test_synchronize_pair
1296
- skip if !machine.respond_to?(:synchronize)
1297
1460
  m = UM::Mutex.new
1298
1461
 
1299
1462
  buf = []
@@ -1348,8 +1511,6 @@ end
1348
1511
 
1349
1512
  class QueueTest < UMBaseTest
1350
1513
  def test_push_pop_1
1351
- skip if !machine.respond_to?(:synchronize)
1352
-
1353
1514
  q = UM::Queue.new
1354
1515
  assert_equal 0, q.count
1355
1516
  machine.push(q, :foo)
@@ -1363,8 +1524,6 @@ class QueueTest < UMBaseTest
1363
1524
  end
1364
1525
 
1365
1526
  def test_push_pop_2
1366
- skip if !machine.respond_to?(:synchronize)
1367
-
1368
1527
  q = UM::Queue.new
1369
1528
  buf = []
1370
1529
 
@@ -1395,8 +1554,6 @@ class QueueTest < UMBaseTest
1395
1554
  end
1396
1555
 
1397
1556
  def test_push_pop_3
1398
- skip if !machine.respond_to?(:synchronize)
1399
-
1400
1557
  q = UM::Queue.new
1401
1558
  buf = []
1402
1559
 
@@ -1423,8 +1580,6 @@ class QueueTest < UMBaseTest
1423
1580
  end
1424
1581
 
1425
1582
  def test_push_pop_4
1426
- skip if !machine.respond_to?(:synchronize)
1427
-
1428
1583
  q = UM::Queue.new
1429
1584
  buf = []
1430
1585
 
@@ -1452,8 +1607,6 @@ class QueueTest < UMBaseTest
1452
1607
  end
1453
1608
 
1454
1609
  def test_push_shift_1
1455
- skip if !machine.respond_to?(:synchronize)
1456
-
1457
1610
  q = UM::Queue.new
1458
1611
 
1459
1612
  machine.push(q, :foo)
@@ -1466,8 +1619,6 @@ class QueueTest < UMBaseTest
1466
1619
  end
1467
1620
 
1468
1621
  def test_shift_shift_1
1469
- skip if !machine.respond_to?(:synchronize)
1470
-
1471
1622
  q = UM::Queue.new
1472
1623
 
1473
1624
  machine.unshift(q, :foo)
@@ -1479,6 +1630,15 @@ class QueueTest < UMBaseTest
1479
1630
  assert_equal :foo, machine.shift(q)
1480
1631
  end
1481
1632
 
1633
+ def test_shift_exception_value
1634
+ q = UM::Queue.new
1635
+ machine.unshift(q, Exception.new("foo"))
1636
+
1637
+ e = machine.shift(q)
1638
+ assert_kind_of Exception, e
1639
+ assert_equal "foo", e.message
1640
+ end
1641
+
1482
1642
  def test_cross_thread_push_shift
1483
1643
  q = UM::Queue.new
1484
1644
 
@@ -1502,6 +1662,42 @@ class QueueTest < UMBaseTest
1502
1662
 
1503
1663
  assert_equal [0, 1, 2], items
1504
1664
  end
1665
+
1666
+ def test_cross_thread_cross_queue_comms
1667
+ worker_queue = UM::Queue.new
1668
+
1669
+ buf = []
1670
+ t1 = Thread.new {
1671
+ m = UM.new
1672
+ (1..10).each {
1673
+ q = UM::Queue.new
1674
+ m.push(worker_queue, [q, it])
1675
+ res = m.shift(q)
1676
+ buf << res
1677
+ }
1678
+ }
1679
+
1680
+ t2 = Thread.new {
1681
+ m = UM.new
1682
+ loop do
1683
+ q, v = m.shift(worker_queue)
1684
+ break if q == :STOP
1685
+
1686
+ res = v * 10
1687
+ m.push(q, res)
1688
+ end
1689
+ }
1690
+
1691
+ t1.join
1692
+ q = UM::Queue.new
1693
+ machine.push(worker_queue, :STOP)
1694
+ t2.join
1695
+
1696
+ assert_equal (1..10).map { it * 10 }, buf
1697
+ ensure
1698
+ t1.kill rescue nil
1699
+ t2.kill rescue nil
1700
+ end
1505
1701
  end
1506
1702
 
1507
1703
  class OpenTest < UMBaseTest
@@ -1646,6 +1842,85 @@ class PollTest < UMBaseTest
1646
1842
  end
1647
1843
  end
1648
1844
 
1845
+ class SelectTest < UMBaseTest
1846
+ def test_select
1847
+ rfd1, wfd1 = UM.pipe
1848
+ rfd2, wfd2 = UM.pipe
1849
+
1850
+ events = []
1851
+ machine.spin do
1852
+ events << 1
1853
+ events << machine.select([rfd1, rfd2], [], [])
1854
+ events << 2
1855
+ events << machine.select([rfd1, rfd2], [], [])
1856
+ events << 3
1857
+ machine.snooze
1858
+ events << machine.select([], [wfd1, wfd2], [])
1859
+ events << 4
1860
+ end
1861
+
1862
+ machine.snooze
1863
+ assert_equal [1], events
1864
+
1865
+ machine.write(wfd1, 'foo')
1866
+ machine.snooze
1867
+ assert_equal [1, [[rfd1], [], []], 2], events
1868
+
1869
+ machine.write(wfd2, 'foo')
1870
+
1871
+ machine.snooze
1872
+ assert_equal [1, [[rfd1], [], []], 2, [[rfd1, rfd2], [], []], 3], events
1873
+
1874
+ machine.snooze
1875
+
1876
+ assert_equal [
1877
+ 1, [[rfd1], [], []],
1878
+ 2, [[rfd1, rfd2], [], []],
1879
+ 3, [[], [wfd1, wfd2], []],
1880
+ 4
1881
+ ], events
1882
+
1883
+ machine.close(rfd1)
1884
+ machine.close(rfd2)
1885
+ end
1886
+
1887
+ def test_select_single
1888
+ rfd1, wfd1 = UM.pipe
1889
+
1890
+ events = []
1891
+ machine.spin do
1892
+ events << 1
1893
+ events << machine.select([rfd1], [], [])
1894
+ events << 2
1895
+ machine.snooze
1896
+ events << machine.select([], [wfd1], [])
1897
+ events << 3
1898
+ end
1899
+
1900
+ machine.snooze
1901
+ assert_equal [1], events
1902
+
1903
+ machine.write(wfd1, 'foo')
1904
+ machine.snooze
1905
+ assert_equal [1, [[rfd1], [], []], 2], events
1906
+
1907
+ 3.times { machine.snooze }
1908
+ assert_equal [1, [[rfd1], [], []], 2, [[], [wfd1], []], 3], events
1909
+
1910
+ machine.close(rfd1)
1911
+ machine.close(wfd1)
1912
+ end
1913
+
1914
+ def test_select_empty
1915
+ ret = machine.select([], [], [])
1916
+ assert_equal [[], [], []], ret
1917
+ end
1918
+
1919
+ def test_select_bad_fd
1920
+ assert_raises(Errno::EBADF) { machine.select([9876, 9877], [], []) }
1921
+ end
1922
+ end
1923
+
1649
1924
  class WaitidTest < UMBaseTest
1650
1925
  def test_waitid
1651
1926
  msg = 'hello from child'
data/uringmachine.gemspec CHANGED
@@ -18,10 +18,10 @@ Gem::Specification.new do |s|
18
18
  s.extra_rdoc_files = ["README.md"]
19
19
  s.extensions = ["ext/um/extconf.rb"]
20
20
  s.require_paths = ["lib"]
21
- s.required_ruby_version = '>= 3.4'
21
+ s.required_ruby_version = '>= 3.5'
22
22
 
23
- s.add_development_dependency 'rake-compiler', '1.2.9'
24
- s.add_development_dependency 'minitest', '5.25.4'
25
- s.add_development_dependency 'benchmark-ips', '2.14.0'
26
- s.add_development_dependency 'http_parser.rb', '0.8.0'
23
+ s.add_development_dependency 'rake-compiler', '~>1.3.0'
24
+ s.add_development_dependency 'minitest', '~>5.26.2'
25
+ s.add_development_dependency 'benchmark-ips', '~>2.14.0'
26
+ s.add_development_dependency 'http_parser.rb', '~>0.8.0'
27
27
  end
@@ -966,6 +966,7 @@ enum io_uring_socket_op {
966
966
  SOCKET_URING_OP_GETSOCKOPT,
967
967
  SOCKET_URING_OP_SETSOCKOPT,
968
968
  SOCKET_URING_OP_TX_TIMESTAMP,
969
+ SOCKET_URING_OP_GETSOCKNAME,
969
970
  };
970
971
 
971
972
  /*
@@ -1572,6 +1572,19 @@ IOURINGINLINE void io_uring_prep_cmd_sock(struct io_uring_sqe *sqe,
1572
1572
  sqe->level = level;
1573
1573
  }
1574
1574
 
1575
+ IOURINGINLINE void io_uring_prep_cmd_getsockname(struct io_uring_sqe *sqe,
1576
+ int fd, struct sockaddr *sockaddr,
1577
+ socklen_t *sockaddr_len,
1578
+ int peer)
1579
+ LIBURING_NOEXCEPT
1580
+ {
1581
+ io_uring_prep_uring_cmd(sqe, SOCKET_URING_OP_GETSOCKNAME, fd);
1582
+
1583
+ sqe->addr = (uintptr_t) sockaddr;
1584
+ sqe->addr3 = (unsigned long) (uintptr_t) sockaddr_len;
1585
+ sqe->optlen = peer;
1586
+ }
1587
+
1575
1588
  IOURINGINLINE void io_uring_prep_waitid(struct io_uring_sqe *sqe,
1576
1589
  idtype_t idtype,
1577
1590
  id_t id,
@@ -258,4 +258,5 @@ LIBURING_2.13 {
258
258
  io_uring_prep_uring_cmd;
259
259
  io_uring_prep_uring_cmd128;
260
260
  io_uring_get_sqe128;
261
+ io_uring_prep_cmd_getsockname;
261
262
  } LIBURING_2.12;