uringmachine 0.19.1 → 0.20.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/TODO.md +0 -1
  4. data/examples/bm_fileno.rb +33 -0
  5. data/examples/bm_mutex.rb +85 -0
  6. data/examples/bm_mutex_single.rb +33 -0
  7. data/examples/bm_queue.rb +27 -28
  8. data/examples/bm_send.rb +2 -5
  9. data/examples/bm_snooze.rb +20 -42
  10. data/examples/fiber_scheduler_demo.rb +15 -51
  11. data/examples/fiber_scheduler_fork.rb +24 -0
  12. data/examples/nc_ssl.rb +71 -0
  13. data/ext/um/extconf.rb +5 -15
  14. data/ext/um/um.c +57 -41
  15. data/ext/um/um.h +21 -11
  16. data/ext/um/um_async_op_class.c +2 -2
  17. data/ext/um/um_buffer.c +1 -1
  18. data/ext/um/um_class.c +94 -23
  19. data/ext/um/um_const.c +51 -3
  20. data/ext/um/um_mutex_class.c +1 -1
  21. data/ext/um/um_queue_class.c +1 -1
  22. data/ext/um/um_stream.c +5 -5
  23. data/ext/um/um_stream_class.c +3 -0
  24. data/ext/um/um_sync.c +22 -27
  25. data/ext/um/um_utils.c +59 -19
  26. data/grant-2025/journal.md +229 -0
  27. data/grant-2025/tasks.md +66 -0
  28. data/lib/uringmachine/fiber_scheduler.rb +180 -48
  29. data/lib/uringmachine/version.rb +1 -1
  30. data/lib/uringmachine.rb +6 -0
  31. data/test/test_fiber_scheduler.rb +138 -0
  32. data/test/test_stream.rb +2 -2
  33. data/test/test_um.rb +427 -34
  34. data/vendor/liburing/.github/workflows/ci.yml +94 -1
  35. data/vendor/liburing/.github/workflows/test_build.c +9 -0
  36. data/vendor/liburing/configure +27 -0
  37. data/vendor/liburing/examples/Makefile +6 -0
  38. data/vendor/liburing/examples/helpers.c +8 -0
  39. data/vendor/liburing/examples/helpers.h +5 -0
  40. data/vendor/liburing/liburing.spec +1 -1
  41. data/vendor/liburing/src/Makefile +9 -3
  42. data/vendor/liburing/src/include/liburing/barrier.h +11 -5
  43. data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
  44. data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
  45. data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
  46. data/vendor/liburing/src/include/liburing.h +445 -121
  47. data/vendor/liburing/src/liburing-ffi.map +15 -0
  48. data/vendor/liburing/src/liburing.map +8 -0
  49. data/vendor/liburing/src/sanitize.c +4 -1
  50. data/vendor/liburing/src/setup.c +7 -4
  51. data/vendor/liburing/test/232c93d07b74.c +4 -16
  52. data/vendor/liburing/test/Makefile +15 -1
  53. data/vendor/liburing/test/accept.c +2 -13
  54. data/vendor/liburing/test/conn-unreach.c +132 -0
  55. data/vendor/liburing/test/fd-pass.c +32 -7
  56. data/vendor/liburing/test/fdinfo.c +39 -12
  57. data/vendor/liburing/test/fifo-futex-poll.c +114 -0
  58. data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
  59. data/vendor/liburing/test/futex.c +1 -1
  60. data/vendor/liburing/test/helpers.c +99 -2
  61. data/vendor/liburing/test/helpers.h +9 -0
  62. data/vendor/liburing/test/io_uring_passthrough.c +6 -12
  63. data/vendor/liburing/test/mock_file.c +379 -0
  64. data/vendor/liburing/test/mock_file.h +47 -0
  65. data/vendor/liburing/test/nop.c +2 -2
  66. data/vendor/liburing/test/nop32-overflow.c +150 -0
  67. data/vendor/liburing/test/nop32.c +126 -0
  68. data/vendor/liburing/test/pipe.c +166 -0
  69. data/vendor/liburing/test/poll-race-mshot.c +13 -1
  70. data/vendor/liburing/test/recv-mshot-fair.c +81 -34
  71. data/vendor/liburing/test/recvsend_bundle.c +1 -1
  72. data/vendor/liburing/test/resize-rings.c +2 -0
  73. data/vendor/liburing/test/ring-query.c +322 -0
  74. data/vendor/liburing/test/ringbuf-loop.c +87 -0
  75. data/vendor/liburing/test/runtests.sh +2 -2
  76. data/vendor/liburing/test/send-zerocopy.c +43 -5
  77. data/vendor/liburing/test/send_recv.c +102 -32
  78. data/vendor/liburing/test/shutdown.c +2 -12
  79. data/vendor/liburing/test/socket-nb.c +3 -14
  80. data/vendor/liburing/test/socket-rw-eagain.c +2 -12
  81. data/vendor/liburing/test/socket-rw-offset.c +2 -12
  82. data/vendor/liburing/test/socket-rw.c +2 -12
  83. data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
  84. data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
  85. data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
  86. data/vendor/liburing/test/timestamp.c +56 -19
  87. data/vendor/liburing/test/vec-regbuf.c +2 -4
  88. data/vendor/liburing/test/wq-aff.c +7 -0
  89. metadata +24 -2
data/test/test_um.rb CHANGED
@@ -164,7 +164,7 @@ class ScheduleTest < UMBaseTest
164
164
  }
165
165
  machine.join(*fs)
166
166
  ensure
167
- GC.stress = false
167
+ GC.stress = false
168
168
  end
169
169
 
170
170
  def test_timeout_with_raising_block
@@ -327,7 +327,7 @@ class PeriodicallyTest < UMBaseTest
327
327
  rescue Cancel
328
328
  cancel = 1
329
329
  end
330
- 5.times { machine.snooze }
330
+ 20.times { machine.snooze }
331
331
  assert_equal 0, machine.pending_count
332
332
  t1 = monotonic_clock
333
333
  assert_in_range 0.05..0.08, t1 - t0
@@ -419,6 +419,51 @@ class ReadTest < UMBaseTest
419
419
  assert_equal 3, result
420
420
  assert_equal 'baz', sio.read
421
421
  end
422
+
423
+ def test_read_io_buffer
424
+ r, w = UM.pipe
425
+ machine.write(w, 'foobar')
426
+
427
+ read_buffer = IO::Buffer.new(3)
428
+ res = machine.read(r, read_buffer, 3)
429
+ assert_equal 3, res
430
+ assert_equal 'foo', read_buffer.get_string(0, 3)
431
+
432
+ machine.close(w)
433
+
434
+ res = machine.read(r, read_buffer)
435
+ assert_equal 3, res
436
+ assert_equal 'bar', read_buffer.get_string(0, 3)
437
+ end
438
+
439
+ def test_read_io_buffer_resize
440
+ r, w = UM.pipe
441
+ machine.write(w, 'foobar')
442
+ machine.close(w)
443
+
444
+ read_buffer = IO::Buffer.new(3)
445
+ res = machine.read(r, read_buffer, 6)
446
+ assert_equal 6, res
447
+ assert_equal 6, read_buffer.size
448
+ assert_equal 'foobar', read_buffer.get_string(0, res)
449
+
450
+ r, w = UM.pipe
451
+ machine.write(w, 'foobar')
452
+ machine.close(w)
453
+
454
+ read_buffer = IO::Buffer.new(3)
455
+ res = machine.read(r, read_buffer, 128, -1)
456
+ assert_equal 6, res
457
+ assert_equal 131, read_buffer.size
458
+ assert_equal 'foobar', read_buffer.get_string(3, res)
459
+ end
460
+
461
+ def test_read_invalid_buffer
462
+ r, _w = UM.pipe
463
+ assert_raises(UM::Error) {
464
+ machine.read(r, [])
465
+ }
466
+ end
422
467
  end
423
468
 
424
469
  class ReadEachTest < UMBaseTest
@@ -586,6 +631,54 @@ class WriteTest < UMBaseTest
586
631
  end
587
632
  assert_equal 0, machine.pending_count
588
633
  end
634
+
635
+ def test_write_io_buffer
636
+ r, w = UM.pipe
637
+
638
+ msg = 'Hello world'
639
+ write_buffer = IO::Buffer.new(msg.bytesize)
640
+ write_buffer.set_string(msg, 0)
641
+
642
+ machine.write(w, write_buffer)
643
+ machine.close(w)
644
+
645
+ str = +''
646
+ machine.read(r, str, 8192)
647
+ assert_equal msg, str
648
+ end
649
+
650
+ def test_write_io_buffer_with_len
651
+ r, w = UM.pipe
652
+ msg = 'Hello world'
653
+ write_buffer = IO::Buffer.new(msg.bytesize)
654
+ write_buffer.set_string(msg)
655
+
656
+ machine.write(w, write_buffer, 5)
657
+ machine.close(w)
658
+
659
+ str = +''
660
+ machine.read(r, str, 8192)
661
+ assert_equal 'Hello', str
662
+
663
+ r, w = UM.pipe
664
+ msg = 'Hello world'
665
+ write_buffer = IO::Buffer.new(msg.bytesize)
666
+ write_buffer.set_string(msg)
667
+
668
+ machine.write(w, write_buffer, -1)
669
+ machine.close(w)
670
+
671
+ str = +''
672
+ machine.read(r, str, 8192)
673
+ assert_equal 'Hello world', str
674
+ end
675
+
676
+ def test_write_invalid_buffer
677
+ _r, w = UM.pipe
678
+ assert_raises(UM::Error) {
679
+ machine.write(w, [])
680
+ }
681
+ end
589
682
  end
590
683
 
591
684
  class WriteAsyncTest < UMBaseTest
@@ -626,6 +719,28 @@ class WriteAsyncTest < UMBaseTest
626
719
  machine.snooze
627
720
  assert_equal 0, machine.pending_count
628
721
  end
722
+
723
+ def test_write_async_io_buffer
724
+ r, w = UM.pipe
725
+
726
+ msg = 'Hello world'
727
+ write_buffer = IO::Buffer.new(msg.bytesize)
728
+ write_buffer.set_string(msg)
729
+
730
+ machine.write_async(w, write_buffer)
731
+ 3.times { machine.snooze }
732
+ machine.close(w)
733
+
734
+ str = +''
735
+ machine.read(r, str, 8192)
736
+ assert_equal msg, str
737
+ end
738
+
739
+ def test_write_async_invalid_buffer
740
+ _r, w = UM.pipe
741
+
742
+ assert_raises(UM::Error) { machine.write_async(w, []) }
743
+ end
629
744
  end
630
745
 
631
746
  class CloseTest < UMBaseTest
@@ -643,7 +758,7 @@ class CloseTest < UMBaseTest
643
758
  end
644
759
 
645
760
  def test_close_bad_fd
646
- r, w = IO.pipe
761
+ _r, w = IO.pipe
647
762
  machine.close(w.fileno)
648
763
 
649
764
  assert_raises(Errno::EBADF) { machine.close(w.fileno) }
@@ -902,6 +1017,78 @@ class SendTest < UMBaseTest
902
1017
  ensure
903
1018
  t&.kill
904
1019
  end
1020
+
1021
+
1022
+ def test_send_io_buffer
1023
+ @port = assign_port
1024
+ @server = TCPServer.open('127.0.0.1', @port)
1025
+
1026
+ t = Thread.new do
1027
+ conn = @server.accept
1028
+ str = conn.readpartial(42)
1029
+ conn.write("You said: #{str} (#{str.bytesize})")
1030
+ sleep
1031
+ end
1032
+
1033
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
1034
+ res = machine.connect(fd, '127.0.0.1', @port)
1035
+ assert_equal 0, res
1036
+
1037
+ buffer = IO::Buffer.new(6)
1038
+ buffer.set_string('foobar')
1039
+ res = machine.send(fd, buffer, 6, 0)
1040
+ assert_equal 6, res
1041
+
1042
+ buf = +''
1043
+ res = machine.read(fd, buf, 42)
1044
+ assert_equal 20, res
1045
+ assert_equal 'You said: foobar (6)', buf
1046
+ ensure
1047
+ t&.kill
1048
+ @server&.close
1049
+ end
1050
+
1051
+ def test_send_io_buffer_negative_len
1052
+ t = Thread.new do
1053
+ conn = @server.accept
1054
+ str = conn.readpartial(42)
1055
+ conn.write("You said: #{str} (#{str.bytesize})")
1056
+ sleep
1057
+ end
1058
+
1059
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
1060
+ res = machine.connect(fd, '127.0.0.1', @port)
1061
+ assert_equal 0, res
1062
+
1063
+ buffer = IO::Buffer.new(6)
1064
+ buffer.set_string('foobar')
1065
+ res = machine.send(fd, buffer, -1, 0)
1066
+ assert_equal 6, res
1067
+
1068
+ buf = +''
1069
+ res = machine.read(fd, buf, 42)
1070
+ assert_equal 20, res
1071
+ assert_equal 'You said: foobar (6)', buf
1072
+ ensure
1073
+ t&.kill
1074
+ end
1075
+
1076
+ def test_send_invalid_buffer
1077
+ t = Thread.new do
1078
+ conn = @server.accept
1079
+ str = conn.readpartial(42)
1080
+ conn.write("You said: #{str} (#{str.bytesize})")
1081
+ sleep
1082
+ end
1083
+
1084
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
1085
+ res = machine.connect(fd, '127.0.0.1', @port)
1086
+ assert_equal 0, res
1087
+
1088
+ assert_raises(UM::Error) { machine.send(fd, [], -1, 0) }
1089
+ ensure
1090
+ t&.kill
1091
+ end
905
1092
  end
906
1093
 
907
1094
  class RecvTest < UMBaseTest
@@ -934,6 +1121,25 @@ class RecvTest < UMBaseTest
934
1121
  ensure
935
1122
  t&.kill
936
1123
  end
1124
+
1125
+ def test_recv_io_buffer
1126
+ t = Thread.new do
1127
+ conn = @server.accept
1128
+ conn.write('foobar')
1129
+ sleep
1130
+ end
1131
+
1132
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
1133
+ res = machine.connect(fd, '127.0.0.1', @port)
1134
+ assert_equal 0, res
1135
+
1136
+ buf = IO::Buffer.new(12)
1137
+ res = machine.recv(fd, buf, 12, 0)
1138
+ assert_equal 6, res
1139
+ assert_equal 'foobar', buf.get_string(0, 6)
1140
+ ensure
1141
+ t&.kill
1142
+ end
937
1143
  end
938
1144
 
939
1145
  class RecvEachTest < UMBaseTest
@@ -1119,6 +1325,25 @@ class SynchronizeTest < UMBaseTest
1119
1325
  assert_equal [11, 12, 13, 21, 22, 23], buf
1120
1326
  assert_equal 0, machine.pending_count
1121
1327
  end
1328
+
1329
+ def test_synchronize_multi
1330
+ mutex = UM::Mutex.new
1331
+ buf = []
1332
+ fibers = (1..8).map { |i|
1333
+ machine.spin do
1334
+ machine.synchronize(mutex) do
1335
+ buf << (i * 10) + 1
1336
+ machine.sleep(0.01)
1337
+ buf << (i * 10) + 2
1338
+ end
1339
+ machine.snooze
1340
+ buf << (i * 10) + 3
1341
+ end
1342
+ }
1343
+
1344
+ machine.join(*fibers)
1345
+ assert_equal [11, 12, 21, 13, 22, 31, 23, 32, 41, 33, 42, 51, 43, 52, 61, 53, 62, 71, 63, 72, 81, 73, 82, 83], buf
1346
+ end
1122
1347
  end
1123
1348
 
1124
1349
  class QueueTest < UMBaseTest
@@ -1335,12 +1560,67 @@ class PipeTest < UMBaseTest
1335
1560
  end
1336
1561
  end
1337
1562
 
1563
+ class PidfdTest < UMBaseTest
1564
+ def test_pidfd_open
1565
+ pid = fork { exit 13 }
1566
+ fd = UM.pidfd_open(pid)
1567
+ assert_kind_of Integer, fd
1568
+
1569
+ pid2, status = machine.waitid(P_PIDFD, fd, UM::WEXITED)
1570
+ assert_equal pid, pid2
1571
+ assert_equal 13, status
1572
+ ensure
1573
+ machine.close(fd) rescue nil
1574
+ Process.wait(pid) rescue nil
1575
+ end
1576
+
1577
+ def test_pidfd_open_invalid_pid
1578
+ assert_raises(SystemCallError) { UM.pidfd_open(Process.pid + 1) }
1579
+ end
1580
+
1581
+ def test_pidfd_send_signal
1582
+ fd = UM.pidfd_open(Process.pid)
1583
+ buf = []
1584
+ trap('SIGUSR1') { buf << :SIGUSR1 }
1585
+
1586
+ ret = UM.pidfd_send_signal(fd, UM::SIGUSR1)
1587
+ assert_equal fd, ret
1588
+ sleep 0.01
1589
+
1590
+ assert_equal [:SIGUSR1], buf
1591
+ ensure
1592
+ machine.close(fd) rescue nil
1593
+ end
1594
+
1595
+ def test_pidfd_send_signal_test
1596
+ fd = UM.pidfd_open(Process.pid)
1597
+ buf = []
1598
+ trap('SIGUSR1') { buf << :SIGUSR1 }
1599
+
1600
+ ret = UM.pidfd_send_signal(fd, 0)
1601
+ assert_equal fd, ret
1602
+ sleep 0.01
1603
+ assert_equal [], buf
1604
+
1605
+ pid = fork { exit 13 }
1606
+ fd2 = UM.pidfd_open(pid)
1607
+ assert_kind_of Integer, fd2
1608
+
1609
+ Process.wait(pid)
1610
+ assert_raises(SystemCallError) { UM.pidfd_send_signal(fd2, 0) }
1611
+ ensure
1612
+ machine.close(fd) rescue nil
1613
+ machine.close(fd2) rescue nil
1614
+ Process.wait(pid) rescue nil
1615
+ end
1616
+ end
1617
+
1338
1618
  class PollTest < UMBaseTest
1339
1619
  def test_poll
1340
1620
  rfd, wfd = UM.pipe
1341
1621
 
1342
1622
  events = []
1343
- f1 = machine.spin do
1623
+ machine.spin do
1344
1624
  events << :pre
1345
1625
  events << machine.poll(rfd, UM::POLLIN)
1346
1626
  events << :post
@@ -1366,38 +1646,81 @@ class PollTest < UMBaseTest
1366
1646
  end
1367
1647
  end
1368
1648
 
1369
- class WaitTest < UMBaseTest
1370
- def test_waitpid
1371
- skip if UM.kernel_version < 607
1372
-
1649
+ class WaitidTest < UMBaseTest
1650
+ def test_waitid
1373
1651
  msg = 'hello from child'
1652
+ _rfd, wfd = UM.pipe
1653
+ child_pid = fork do
1654
+ m = UM.new
1655
+ m.write(wfd, msg)
1656
+ m.close(wfd)
1657
+ exit 42
1658
+ end
1374
1659
 
1375
- rfd, wfd = UM.pipe
1376
- pid = fork do
1660
+ pid, status = machine.waitid(UM::P_PID, child_pid, UM::WEXITED)
1661
+ assert_equal child_pid, pid
1662
+ assert_equal 42, status
1663
+ ensure
1664
+ Process.wait(child_pid) rescue nil
1665
+ end
1666
+
1667
+ def test_waitid_invalid_pid
1668
+ assert_raises(Errno::ECHILD) {
1669
+ machine.waitid(UM::P_PID, Process.pid + 1, UM::WEXITED)
1670
+ }
1671
+ end
1672
+
1673
+ def test_waitid_invalid_idtype
1674
+ assert_raises(Errno::EINVAL) {
1675
+ machine.waitid(1234, 0, UM::WEXITED)
1676
+ }
1677
+ end
1678
+
1679
+ def test_waitid_invalid_options
1680
+ assert_raises(Errno::EINVAL) {
1681
+ machine.waitid(P_ALL, 0, 1234)
1682
+ }
1683
+ end
1684
+
1685
+ def test_waitid_P_ALL
1686
+ msg = 'hello from child'
1687
+ _rfd, wfd = UM.pipe
1688
+ child_pid = fork do
1377
1689
  m = UM.new
1378
1690
  m.write(wfd, msg)
1379
1691
  m.close(wfd)
1380
1692
  exit 42
1381
1693
  end
1382
1694
 
1383
- ret = machine.waitpid(pid, UM::WEXITED)
1384
- assert_kind_of Array, ret
1385
- assert_equal [pid, 42], ret
1695
+ pid, status = machine.waitid(UM::P_ALL, 0, UM::WEXITED)
1696
+ assert_equal child_pid, pid
1697
+ assert_equal 42, status
1698
+ ensure
1699
+ Process.wait(child_pid) rescue nil
1700
+ end
1386
1701
 
1387
- buf = +''
1388
- ret = machine.read(rfd, buf, 8192)
1389
- assert_equal msg.bytesize, ret
1390
- assert_equal msg, buf
1702
+ def test_waitid_P_PGID
1703
+ msg = 'hello from child'
1704
+ _rfd, wfd = UM.pipe
1705
+ child_pid = fork do
1706
+ m = UM.new
1707
+ m.write(wfd, msg)
1708
+ m.close(wfd)
1709
+ exit 42
1710
+ end
1711
+
1712
+ pid, status = machine.waitid(UM::P_PGID, Process.getpgrp, UM::WEXITED)
1713
+ assert_equal child_pid, pid
1714
+ assert_equal 42, status
1391
1715
  ensure
1392
- Process.wait(pid) rescue Errno::ECHILD
1716
+ Process.wait(child_pid) rescue nil
1393
1717
  end
1394
1718
 
1395
- def test_waitpid_any
1396
- skip if UM.kernel_version < 607
1719
+ def test_waitid_status
1720
+ skip if !machine.respond_to?(:waitid_status)
1397
1721
 
1398
1722
  msg = 'hello from child'
1399
-
1400
- rfd, wfd = UM.pipe
1723
+ _rfd, wfd = UM.pipe
1401
1724
  pid = fork do
1402
1725
  m = UM.new
1403
1726
  m.write(wfd, msg)
@@ -1405,23 +1728,76 @@ class WaitTest < UMBaseTest
1405
1728
  exit 42
1406
1729
  end
1407
1730
 
1408
- ret = machine.waitpid(0, UM::WEXITED)
1409
- assert_kind_of Array, ret
1410
- assert_equal [pid, 42], ret
1731
+ status = machine.waitid_status(UM::P_PID, pid, UM::WEXITED)
1732
+ assert_kind_of Process::Status, status
1733
+ assert_equal pid, status.pid
1734
+ assert_equal 42, status.exitstatus
1735
+ ensure
1736
+ Process.wait(pid) rescue nil
1737
+ end
1411
1738
 
1412
- buf = +''
1413
- ret = machine.read(rfd, buf, 8192)
1414
- assert_equal msg.bytesize, ret
1415
- assert_equal msg, buf
1739
+ def test_waitid_status_invalid_pid
1740
+ skip if !machine.respond_to?(:waitid_status)
1741
+
1742
+ assert_raises(Errno::ECHILD) {
1743
+ machine.waitid_status(UM::P_PID, Process.pid + 1, UM::WEXITED)
1744
+ }
1745
+ end
1416
1746
 
1747
+ def test_waitid_status_invalid_idtype
1748
+ skip if !machine.respond_to?(:waitid_status)
1749
+
1750
+ assert_raises(Errno::EINVAL) {
1751
+ machine.waitid_status(1234, 0, UM::WEXITED)
1752
+ }
1753
+ end
1754
+
1755
+ def test_waitid_status_invalid_options
1756
+ skip if !machine.respond_to?(:waitid_status)
1757
+
1758
+ assert_raises(Errno::EINVAL) {
1759
+ machine.waitid_status(P_ALL, 0, 1234)
1760
+ }
1761
+ end
1762
+
1763
+ def test_waitid_status_P_ALL
1764
+ skip if !machine.respond_to?(:waitid_status)
1765
+
1766
+ msg = 'hello from child'
1767
+ _rfd, wfd = UM.pipe
1768
+ pid = fork do
1769
+ m = UM.new
1770
+ m.write(wfd, msg)
1771
+ m.close(wfd)
1772
+ exit 42
1773
+ end
1774
+
1775
+ status = machine.waitid_status(UM::P_ALL, 0, UM::WEXITED)
1776
+ assert_kind_of Process::Status, status
1777
+ assert_equal pid, status.pid
1778
+ assert_equal 42, status.exitstatus
1417
1779
  ensure
1418
- Process.wait(pid) rescue Errno::ECHILD
1780
+ Process.wait(pid) rescue nil
1419
1781
  end
1420
1782
 
1421
- def test_waitpid_bad_pid
1422
- skip if UM.kernel_version < 607
1783
+ def test_waitid_status_P_PGID
1784
+ skip if !machine.respond_to?(:waitid_status)
1423
1785
 
1424
- assert_raises(Errno::ECHILD) { machine.waitpid(1, UM::WEXITED) }
1786
+ msg = 'hello from child'
1787
+ _rfd, wfd = UM.pipe
1788
+ pid = fork do
1789
+ m = UM.new
1790
+ m.write(wfd, msg)
1791
+ m.close(wfd)
1792
+ exit 42
1793
+ end
1794
+
1795
+ status = machine.waitid_status(UM::P_PGID, Process.getpgrp, UM::WEXITED)
1796
+ assert_kind_of Process::Status, status
1797
+ assert_equal pid, status.pid
1798
+ assert_equal 42, status.exitstatus
1799
+ ensure
1800
+ Process.wait(pid) rescue nil
1425
1801
  end
1426
1802
  end
1427
1803
 
@@ -1509,7 +1885,7 @@ class ForkTest < UMBaseTest
1509
1885
  assert_equal 3, ret
1510
1886
  assert_equal 'foo', buf
1511
1887
  ensure
1512
- Process.wait(child_pid) rescue Errno::ECHILD
1888
+ Process.wait(child_pid) rescue nil
1513
1889
  end
1514
1890
  end
1515
1891
 
@@ -1573,3 +1949,20 @@ class SendBundleTest < UMBaseTest
1573
1949
  assert_equal strs.map(&:to_s).join, buf
1574
1950
  end
1575
1951
  end
1952
+
1953
+ class NonBlockTest < UMBaseTest
1954
+ def test_io_nonblock?
1955
+ assert_equal false, UM.io_nonblock?(STDIN)
1956
+ end
1957
+
1958
+ def test_io_set_nonblock
1959
+ r, _w = IO.pipe
1960
+ assert_equal true, UM.io_nonblock?(r)
1961
+
1962
+ UM.io_set_nonblock(r, false)
1963
+ assert_equal false, UM.io_nonblock?(r)
1964
+
1965
+ UM.io_set_nonblock(r, true)
1966
+ assert_equal true, UM.io_nonblock?(r)
1967
+ end
1968
+ end