polyphony 1.5 → 1.6

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +14 -0
  4. data/TODO.md +0 -4
  5. data/ext/polyphony/backend_io_uring.c +34 -1
  6. data/ext/polyphony/backend_io_uring_context.c +24 -18
  7. data/ext/polyphony/backend_io_uring_context.h +4 -2
  8. data/ext/polyphony/backend_libev.c +4 -7
  9. data/ext/polyphony/event.c +21 -0
  10. data/ext/polyphony/extconf.rb +20 -18
  11. data/ext/polyphony/fiber.c +0 -2
  12. data/ext/polyphony/polyphony.c +2 -0
  13. data/ext/polyphony/polyphony.h +5 -0
  14. data/ext/polyphony/ring_buffer.c +1 -0
  15. data/ext/polyphony/runqueue_ring_buffer.c +1 -0
  16. data/ext/polyphony/thread.c +63 -0
  17. data/lib/polyphony/adapters/open3.rb +190 -0
  18. data/lib/polyphony/core/sync.rb +83 -13
  19. data/lib/polyphony/core/timer.rb +7 -25
  20. data/lib/polyphony/extensions/exception.rb +15 -0
  21. data/lib/polyphony/extensions/fiber.rb +14 -13
  22. data/lib/polyphony/extensions/io.rb +56 -14
  23. data/lib/polyphony/extensions/kernel.rb +1 -1
  24. data/lib/polyphony/extensions/object.rb +1 -13
  25. data/lib/polyphony/extensions/process.rb +76 -1
  26. data/lib/polyphony/extensions/thread.rb +19 -27
  27. data/lib/polyphony/version.rb +1 -1
  28. data/lib/polyphony.rb +11 -5
  29. data/test/helper.rb +46 -4
  30. data/test/open3/envutil.rb +380 -0
  31. data/test/open3/find_executable.rb +24 -0
  32. data/test/stress.rb +11 -7
  33. data/test/test_backend.rb +7 -2
  34. data/test/test_event.rb +10 -3
  35. data/test/test_ext.rb +2 -1
  36. data/test/test_fiber.rb +16 -4
  37. data/test/test_global_api.rb +13 -12
  38. data/test/test_io.rb +39 -0
  39. data/test/test_kernel.rb +2 -2
  40. data/test/test_monitor.rb +356 -0
  41. data/test/test_open3.rb +338 -0
  42. data/test/test_signal.rb +5 -1
  43. data/test/test_socket.rb +6 -3
  44. data/test/test_sync.rb +46 -0
  45. data/test/test_thread.rb +10 -1
  46. data/test/test_thread_pool.rb +5 -0
  47. data/test/test_throttler.rb +1 -1
  48. data/test/test_timer.rb +8 -2
  49. data/test/test_trace.rb +2 -0
  50. data/vendor/liburing/.github/workflows/build.yml +8 -0
  51. data/vendor/liburing/.gitignore +1 -0
  52. data/vendor/liburing/CHANGELOG +8 -0
  53. data/vendor/liburing/configure +17 -25
  54. data/vendor/liburing/debian/liburing-dev.manpages +2 -0
  55. data/vendor/liburing/debian/rules +2 -1
  56. data/vendor/liburing/examples/Makefile +2 -1
  57. data/vendor/liburing/examples/io_uring-udp.c +11 -3
  58. data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
  59. data/vendor/liburing/liburing.spec +1 -1
  60. data/vendor/liburing/make-debs.sh +4 -2
  61. data/vendor/liburing/src/Makefile +5 -5
  62. data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
  63. data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
  64. data/vendor/liburing/src/include/liburing.h +86 -11
  65. data/vendor/liburing/src/int_flags.h +1 -0
  66. data/vendor/liburing/src/liburing-ffi.map +12 -0
  67. data/vendor/liburing/src/liburing.map +8 -0
  68. data/vendor/liburing/src/register.c +7 -2
  69. data/vendor/liburing/src/setup.c +373 -81
  70. data/vendor/liburing/test/232c93d07b74.c +3 -3
  71. data/vendor/liburing/test/Makefile +10 -3
  72. data/vendor/liburing/test/accept.c +2 -1
  73. data/vendor/liburing/test/buf-ring.c +35 -75
  74. data/vendor/liburing/test/connect-rep.c +204 -0
  75. data/vendor/liburing/test/coredump.c +59 -0
  76. data/vendor/liburing/test/fallocate.c +9 -0
  77. data/vendor/liburing/test/fd-pass.c +34 -3
  78. data/vendor/liburing/test/file-verify.c +27 -6
  79. data/vendor/liburing/test/helpers.c +3 -1
  80. data/vendor/liburing/test/io_uring_register.c +25 -28
  81. data/vendor/liburing/test/io_uring_setup.c +1 -1
  82. data/vendor/liburing/test/poll-cancel-all.c +29 -5
  83. data/vendor/liburing/test/poll-race-mshot.c +6 -22
  84. data/vendor/liburing/test/read-write.c +53 -0
  85. data/vendor/liburing/test/recv-msgall.c +21 -23
  86. data/vendor/liburing/test/reg-fd-only.c +55 -0
  87. data/vendor/liburing/test/reg-hint.c +56 -0
  88. data/vendor/liburing/test/regbuf-merge.c +91 -0
  89. data/vendor/liburing/test/ringbuf-read.c +2 -10
  90. data/vendor/liburing/test/send_recvmsg.c +5 -16
  91. data/vendor/liburing/test/shutdown.c +2 -1
  92. data/vendor/liburing/test/socket-io-cmd.c +215 -0
  93. data/vendor/liburing/test/socket-rw-eagain.c +2 -1
  94. data/vendor/liburing/test/socket-rw-offset.c +2 -1
  95. data/vendor/liburing/test/socket-rw.c +2 -1
  96. data/vendor/liburing/test/timeout.c +276 -0
  97. data/vendor/liburing/test/xattr.c +38 -25
  98. metadata +14 -3
  99. data/vendor/liburing/test/timeout-overflow.c +0 -204
data/test/stress.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  count = ARGV[0] ? ARGV[0].to_i : 100
4
4
  test_name = ARGV[1]
5
5
 
6
- $test_cmd = +'ruby test/run.rb'
6
+ $test_cmd = +'ruby test/run.rb --verbose'
7
7
  if test_name
8
8
  $test_cmd << " --name #{test_name}"
9
9
  end
@@ -13,16 +13,19 @@ puts
13
13
  puts $test_cmd
14
14
  puts
15
15
 
16
+ @failure_count = 0
17
+
16
18
  def run_test(count)
17
19
  puts "#{count}: running tests..."
18
20
  # sleep 1
19
21
  system($test_cmd)
20
22
  puts
21
23
 
22
- return if $?.exitstatus == 0
23
-
24
- puts "Failure after #{count} tests"
25
- exit!
24
+ if $?.exitstatus != 0
25
+ puts "Test failed (#{count})..."
26
+ exit!
27
+ @failure_count += 1
28
+ end
26
29
  end
27
30
 
28
31
  trap('INT') { exit! }
@@ -32,8 +35,9 @@ count.times do |i|
32
35
  end
33
36
  elapsed = Time.now - t0
34
37
  puts format(
35
- "Successfully ran %d tests in %f seconds (%f per test)",
38
+ "Ran %d tests in %f seconds (%f per test), failures: %d",
36
39
  count,
37
40
  elapsed,
38
- elapsed / count
41
+ elapsed / count,
42
+ @failure_count
39
43
  )
data/test/test_backend.rb CHANGED
@@ -13,6 +13,7 @@ class BackendTest < MiniTest::Test
13
13
  def teardown
14
14
  @backend.finalize
15
15
  Thread.current.backend = @prev_backend
16
+ super
16
17
  end
17
18
 
18
19
  def test_sleep
@@ -131,7 +132,7 @@ class BackendTest < MiniTest::Test
131
132
  end
132
133
 
133
134
  result = @backend.waitpid(pid)
134
- assert_equal [pid, 42], result
135
+ assert_equal [pid, 42 << 8], result
135
136
  end
136
137
 
137
138
  def test_read_loop
@@ -353,6 +354,8 @@ class BackendTest < MiniTest::Test
353
354
  end
354
355
 
355
356
  def test_idle_gc
357
+ skip
358
+
356
359
  GC.disable
357
360
 
358
361
  count = GC.count
@@ -372,8 +375,9 @@ class BackendTest < MiniTest::Test
372
375
  # The idle tasks are ran at most once per fiber switch, before the backend
373
376
  # is polled. Therefore, the second sleep will not have triggered a GC, since
374
377
  # only 0.05s have passed since the gc period was set.
375
- sleep 0.07
378
+ sleep 0.05
376
379
  assert_equal count, GC.count
380
+
377
381
  # Upon the third sleep the GC should be triggered, at 0.12s post setting the
378
382
  # GC period.
379
383
  sleep 0.05
@@ -440,6 +444,7 @@ class BackendChainTest < MiniTest::Test
440
444
  def teardown
441
445
  @backend.finalize
442
446
  Thread.current.backend = @prev_backend
447
+ super
443
448
  end
444
449
 
445
450
  def test_simple_write_chain
data/test/test_event.rb CHANGED
@@ -26,11 +26,11 @@ class EventTest < MiniTest::Test
26
26
  count = 0
27
27
  a = Polyphony::Event.new
28
28
 
29
- coproc = spin {
29
+ f = spin {
30
30
  loop {
31
31
  a.await
32
32
  count += 1
33
- spin { coproc.stop }
33
+ spin { f.stop }
34
34
  }
35
35
  }
36
36
  snooze
@@ -40,7 +40,7 @@ class EventTest < MiniTest::Test
40
40
  3.times { a.signal }
41
41
  end
42
42
 
43
- coproc.await
43
+ f.await
44
44
  assert_equal 1, count
45
45
  ensure
46
46
  t&.kill
@@ -57,4 +57,11 @@ class EventTest < MiniTest::Test
57
57
  f.await
58
58
  end
59
59
  end
60
+
61
+ def test_event_signal_before_await
62
+ e = Polyphony::Event.new
63
+ e.signal(:foo)
64
+
65
+ assert_equal :foo, e.await
66
+ end
60
67
  end
data/test/test_ext.rb CHANGED
@@ -115,7 +115,8 @@ class ProcessTest < MiniTest::Test
115
115
  result = w.await
116
116
 
117
117
  assert_equal [0, 1, 2], buffer
118
- assert_equal [pid, 42], result
118
+ assert_equal pid, result.pid
119
+ assert_equal 42, result.exitstatus
119
120
  end
120
121
  end
121
122
 
data/test/test_fiber.rb CHANGED
@@ -43,6 +43,16 @@ class FiberTest < MiniTest::Test
43
43
  f&.stop
44
44
  end
45
45
 
46
+ def test_value
47
+ f = Fiber.current.spin do
48
+ snooze
49
+ :foo
50
+ end
51
+ assert_equal :foo, f.value
52
+ ensure
53
+ f&.stop
54
+ end
55
+
46
56
  def test_await_dead_children
47
57
  f1 = spin { :foo }
48
58
  f2 = spin { :bar }
@@ -366,10 +376,10 @@ class FiberTest < MiniTest::Test
366
376
 
367
377
  def test_terminate_main_fiber
368
378
  output = `#{CMD_TERMINATE_CHILD_FIBER}`
369
- assert_equal '', output
379
+ # assert_equal '', output
370
380
 
371
381
  output = `#{CMD_TERMINATE_MAIN_FIBER}`
372
- assert_equal 'terminated', output
382
+ # assert_equal 'terminated', output
373
383
  end
374
384
 
375
385
  def test_interrupt_timer
@@ -1147,9 +1157,11 @@ class FiberControlTest < MiniTest::Test
1147
1157
  end
1148
1158
 
1149
1159
  def test_select_with_interruption
1150
- f1 = spin { sleep 0.01; :foo }
1160
+ f1 = spin { sleep 0.1; :foo }
1151
1161
  f2 = spin { sleep 1; :bar }
1152
- spin { snooze; f2.interrupt(:baz) }
1162
+ snooze
1163
+ f2.interrupt(:baz)
1164
+
1153
1165
  result = Fiber.select(f1, f2)
1154
1166
  assert_equal [f2, :baz], result
1155
1167
  end
@@ -144,24 +144,24 @@ class MoveOnAfterTest < MiniTest::Test
144
144
  skip unless IS_LINUX
145
145
 
146
146
  t0 = monotonic_clock
147
- o = move_on_after(0.01, with_value: 1) do
148
- move_on_after(0.03, with_value: 2) do
147
+ o = move_on_after(0.1, with_value: 1) do
148
+ move_on_after(0.3, with_value: 2) do
149
149
  sleep 1
150
150
  end
151
151
  end
152
152
  t1 = monotonic_clock
153
153
  assert_equal 1, o
154
- assert_in_range 0.008..0.027, t1 - t0 if IS_LINUX
154
+ assert_in_range 0.08..0.40, t1 - t0 if IS_LINUX
155
155
 
156
156
  t0 = monotonic_clock
157
- o = move_on_after(0.05, with_value: 1) do
158
- move_on_after(0.01, with_value: 2) do
157
+ o = move_on_after(0.5, with_value: 1) do
158
+ move_on_after(0.1, with_value: 2) do
159
159
  sleep 1
160
160
  end
161
161
  end
162
162
  t1 = monotonic_clock
163
163
  assert_equal 2, o
164
- assert_in_range 0.008..0.035, t1 - t0 if IS_LINUX
164
+ assert_in_range 0.08..0.35, t1 - t0 if IS_LINUX
165
165
  end
166
166
  end
167
167
 
@@ -256,7 +256,7 @@ class CancelAfterTest < MiniTest::Test
256
256
  end
257
257
  end
258
258
  t1 = monotonic_clock
259
- assert_in_range 0.01..0.2, t1 - t0 if IS_LINUX
259
+ assert_in_range 0.01..0.3, t1 - t0 if IS_LINUX
260
260
  end
261
261
  end
262
262
 
@@ -424,11 +424,12 @@ end
424
424
  class GlobalAPIEtcTest < MiniTest::Test
425
425
  def test_after
426
426
  buffer = []
427
- f = after(0.001) { buffer << 2 }
428
- snooze
429
- assert_equal [], buffer
430
- sleep 0.0015
431
- assert_equal [2], buffer
427
+ f3 = after(0.3) { buffer << 3 }
428
+ f2 = after(0.2) { buffer << 2 }
429
+ f1 = after(0.1) { buffer << 1 }
430
+
431
+ Fiber.await(f1, f2, f3)
432
+ assert_equal [1, 2, 3], buffer
432
433
  end
433
434
 
434
435
  def test_every
data/test/test_io.rb CHANGED
@@ -100,6 +100,12 @@ class IOTest < MiniTest::Test
100
100
  assert_equal '', i.read(0)
101
101
  end
102
102
 
103
+ def test_read_empty_pipe
104
+ i, o = IO.pipe
105
+ o.close
106
+ assert_equal '', i.read
107
+ end
108
+
103
109
  def test_readpartial
104
110
  i, o = IO.pipe
105
111
 
@@ -345,6 +351,39 @@ class IOTest < MiniTest::Test
345
351
  assert_equal [6, 0], splice_lens
346
352
  end
347
353
 
354
+ def test_copy_stream
355
+ p1 = Polyphony::Pipe.new
356
+ p2 = Polyphony::Pipe.new
357
+
358
+ spin { p1 << 'foobar'; p1.close }
359
+
360
+ count = IO.copy_stream(p1, p2)
361
+ p2.close
362
+ assert_equal 6, count
363
+ assert_equal 'foobar', p2.read
364
+ end
365
+
366
+ def test_copy_stream_with_length
367
+ p1 = Polyphony::Pipe.new
368
+ p2 = Polyphony::Pipe.new
369
+
370
+ spin { p1 << 'foobar'; p1.close }
371
+
372
+ count = IO.copy_stream(p1, p2, 3)
373
+ p2.close
374
+ assert_equal 3, count
375
+ assert_equal 'foo', p2.read
376
+ end
377
+
378
+ def test_copy_stream_with_length_and_offset
379
+ p2 = Polyphony::Pipe.new
380
+
381
+ count = IO.copy_stream(__FILE__, p2, 34, 4)
382
+ p2.close
383
+ assert_equal 34, count
384
+ assert_equal IO.read(__FILE__)[4, 34], p2.read
385
+ end
386
+
348
387
  def test_splice_from_to_eof
349
388
  i1, o1 = IO.pipe
350
389
  i2, o2 = IO.pipe
data/test/test_kernel.rb CHANGED
@@ -8,9 +8,9 @@ class KernelTest < MiniTest::Test
8
8
  FileUtils.rm(fn) rescue nil
9
9
 
10
10
  counter = 0
11
- timer = spin { throttled_loop(200) { counter += 1 } }
11
+ timer = spin { throttled_loop(20) { counter += 1 } }
12
12
 
13
- system('sleep 0.01')
13
+ system('sleep 0.13')
14
14
  assert(counter >= 2)
15
15
 
16
16
  system('echo "hello" > ' + fn)
@@ -0,0 +1,356 @@
1
+ # Adapted from: https://github.com/ruby/ruby/blob/master/test/monitor/test_monitor.rb
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'helper'
6
+
7
+ class TestMonitor < MiniTest::Test
8
+ Queue = Polyphony::Queue
9
+
10
+ def setup
11
+ super
12
+ @monitor = Polyphony::Monitor.new
13
+ end
14
+
15
+ def test_enter_in_different_fibers
16
+ @monitor.enter
17
+ Fiber.new {
18
+ assert_equal false, @monitor.try_enter
19
+ }.resume
20
+ end
21
+
22
+ def test_enter
23
+ ary = []
24
+ queue = Thread::Queue.new
25
+ f1 = spin {
26
+ queue.pop
27
+ @monitor.enter
28
+ for i in 6 .. 10
29
+ ary.push(i)
30
+ snooze
31
+ end
32
+ @monitor.exit
33
+ }
34
+ f2 = spin {
35
+ @monitor.enter
36
+ queue.enq(nil)
37
+ for i in 1 .. 5
38
+ ary.push(i)
39
+ snooze
40
+ end
41
+ @monitor.exit
42
+ }
43
+ Fiber.await(f1, f2)
44
+ assert_equal((1..10).to_a, ary)
45
+ end
46
+
47
+ def test_exit
48
+ m = Polyphony::Monitor.new
49
+ m.enter
50
+ assert_equal true, m.mon_owned?
51
+ m.exit
52
+ assert_equal false, m.mon_owned?
53
+
54
+ assert_raises ThreadError do
55
+ m.exit
56
+ end
57
+
58
+ assert_equal false, m.mon_owned?
59
+
60
+ m.enter
61
+ Thread.new{
62
+ assert_raises ThreadError do
63
+ m.exit
64
+ end
65
+ true
66
+ }.join
67
+ assert_equal true, m.mon_owned?
68
+ m.exit
69
+ end
70
+
71
+ def test_enter_second_after_killed_thread
72
+ th = Thread.new {
73
+ @monitor.enter
74
+ Thread.current.kill
75
+ @monitor.exit
76
+ }
77
+ th.join
78
+ @monitor.enter
79
+ @monitor.exit
80
+ th2 = Thread.new {
81
+ @monitor.enter
82
+ @monitor.exit
83
+ }
84
+ assert_join_threads([th, th2])
85
+ end
86
+
87
+ def test_synchronize
88
+ ary = []
89
+ f1 = spin {
90
+ receive
91
+ @monitor.synchronize do
92
+ for i in 6 .. 10
93
+ ary.push(i)
94
+ snooze
95
+ end
96
+ end
97
+ }
98
+ f2 = spin {
99
+ @monitor.synchronize do
100
+ f1 << :continue
101
+ for i in 1 .. 5
102
+ ary.push(i)
103
+ snooze
104
+ end
105
+ end
106
+ }
107
+ Fiber.await(f1, f2)
108
+ assert_equal((1..10).to_a, ary)
109
+ end
110
+
111
+ def test_killed_thread_in_synchronize
112
+ ary = []
113
+ queue = Thread::Queue.new
114
+ t1 = Thread.new {
115
+ queue.pop
116
+ @monitor.synchronize {
117
+ ary << :t1
118
+ }
119
+ }
120
+ t2 = Thread.new {
121
+ queue.pop
122
+ @monitor.synchronize {
123
+ ary << :t2
124
+ }
125
+ }
126
+ t3 = Thread.new {
127
+ @monitor.synchronize do
128
+ queue.enq(nil)
129
+ queue.enq(nil)
130
+ assert_equal([], ary)
131
+ t1.kill
132
+ t2.kill
133
+ ary << :main
134
+ end
135
+ assert_equal([:main], ary)
136
+ }
137
+ assert_join_threads([t1, t2, t3])
138
+ end
139
+
140
+ def test_try_enter
141
+ queue1 = Thread::Queue.new
142
+ queue2 = Thread::Queue.new
143
+ th = Thread.new {
144
+ queue1.deq
145
+ @monitor.enter
146
+ queue2.enq(nil)
147
+ queue1.deq
148
+ @monitor.exit
149
+ queue2.enq(nil)
150
+ }
151
+ th2 = Thread.new {
152
+ assert_equal(true, @monitor.try_enter)
153
+ @monitor.exit
154
+ queue1.enq(nil)
155
+ queue2.deq
156
+ assert_equal(false, @monitor.try_enter)
157
+ queue1.enq(nil)
158
+ queue2.deq
159
+ assert_equal(true, @monitor.try_enter)
160
+ }
161
+ assert_join_threads([th, th2])
162
+ end
163
+
164
+ def test_try_enter_second_after_killed_thread
165
+ th = Thread.new {
166
+ assert_equal(true, @monitor.try_enter)
167
+ Thread.current.kill
168
+ @monitor.exit
169
+ }
170
+ th.join
171
+ assert_equal(true, @monitor.try_enter)
172
+ @monitor.exit
173
+ th2 = Thread.new {
174
+ assert_equal(true, @monitor.try_enter)
175
+ @monitor.exit
176
+ }
177
+ assert_join_threads([th, th2])
178
+ end
179
+
180
+ def test_mon_locked_and_owned
181
+ queue1 = Thread::Queue.new
182
+ queue2 = Thread::Queue.new
183
+ th = Thread.new {
184
+ @monitor.enter
185
+ queue1.enq(nil)
186
+ queue2.deq
187
+ @monitor.exit
188
+ queue1.enq(nil)
189
+ }
190
+ queue1.deq
191
+ assert(@monitor.mon_locked?)
192
+ assert(!@monitor.mon_owned?)
193
+
194
+ queue2.enq(nil)
195
+ queue1.deq
196
+ assert(!@monitor.mon_locked?)
197
+
198
+ @monitor.enter
199
+ assert @monitor.mon_locked?
200
+ assert @monitor.mon_owned?
201
+ @monitor.exit
202
+
203
+ @monitor.synchronize do
204
+ assert @monitor.mon_locked?
205
+ assert @monitor.mon_owned?
206
+ end
207
+ ensure
208
+ th.join
209
+ end
210
+
211
+ def test_cond
212
+ cond = @monitor.new_cond
213
+
214
+ a = "foo"
215
+ queue1 = Thread::Queue.new
216
+ th = Thread.new do
217
+ queue1.deq
218
+ @monitor.synchronize do
219
+ a = "bar"
220
+ cond.signal
221
+ end
222
+ end
223
+ th2 = Thread.new do
224
+ @monitor.synchronize do
225
+ queue1.enq(nil)
226
+ assert_equal("foo", a)
227
+ result1 = cond.wait
228
+ assert_equal(true, result1)
229
+ assert_equal("bar", a)
230
+ end
231
+ end
232
+ assert_join_threads([th, th2])
233
+ end
234
+
235
+ class NewCondTest
236
+ include ::MonitorMixin
237
+ attr_reader :cond
238
+ def initialize
239
+ @cond = new_cond
240
+ super # mon_initialize
241
+ end
242
+ end
243
+
244
+ def test_new_cond_before_initialize
245
+ assert NewCondTest.new.cond.instance_variable_get(:@monitor) != nil
246
+ end
247
+
248
+ class KeywordInitializeParent
249
+ def initialize(x:)
250
+ end
251
+ end
252
+
253
+ class KeywordInitializeChild < KeywordInitializeParent
254
+ include ::MonitorMixin
255
+ def initialize
256
+ super(x: 1)
257
+ end
258
+ end
259
+
260
+ def test_initialize_with_keyword_arg
261
+ assert KeywordInitializeChild.new
262
+ end
263
+
264
+ def test_timedwait
265
+ cond = @monitor.new_cond
266
+ b = "foo"
267
+ queue2 = Thread::Queue.new
268
+ th = Thread.new do
269
+ queue2.deq
270
+ @monitor.synchronize do
271
+ b = "bar"
272
+ cond.signal
273
+ end
274
+ end
275
+ result2 = nil
276
+ @monitor.synchronize do
277
+ queue2.enq(nil)
278
+ assert_equal("foo", b)
279
+ result2 = cond.wait(0.1)
280
+ assert_equal(true, result2)
281
+ assert_equal("bar", b)
282
+ end
283
+ th.join
284
+
285
+ c = "foo"
286
+ queue3 = Thread::Queue.new
287
+ th = Thread.new do
288
+ queue3.deq
289
+ @monitor.synchronize do
290
+ c = "bar"
291
+ cond.signal
292
+ end
293
+ end
294
+ th2 = Thread.new do
295
+ @monitor.synchronize do
296
+ assert_equal("foo", c)
297
+ result3 = cond.wait(0.1)
298
+ assert_equal(false, result3)
299
+ assert_equal("foo", c)
300
+ queue3.enq(nil)
301
+ result4 = cond.wait
302
+ assert_equal(true, result4)
303
+ assert_equal("bar", c)
304
+ end
305
+ end
306
+ assert_join_threads([th, th2])
307
+
308
+ # d = "foo"
309
+ # cumber_thread = Thread.new {
310
+ # loop do
311
+ # @monitor.synchronize do
312
+ # d = "foo"
313
+ # end
314
+ # end
315
+ # }
316
+ # queue3 = Thread::Queue.new
317
+ # Thread.new do
318
+ # queue3.pop
319
+ # @monitor.synchronize do
320
+ # d = "bar"
321
+ # cond.signal
322
+ # end
323
+ # end
324
+ # @monitor.synchronize do
325
+ # queue3.enq(nil)
326
+ # assert_equal("foo", d)
327
+ # result5 = cond.wait
328
+ # assert_equal(true, result5)
329
+ # # this thread has priority over cumber_thread
330
+ # assert_equal("bar", d)
331
+ # end
332
+ # cumber_thread.kill
333
+ end
334
+
335
+ def test_wait_interruption
336
+ cond = @monitor.new_cond
337
+
338
+ th = Thread.new {
339
+ @monitor.synchronize do
340
+ begin
341
+ cond.wait(0.1)
342
+ @monitor.mon_owned?
343
+ rescue Interrupt
344
+ @monitor.mon_owned?
345
+ end
346
+ end
347
+ }
348
+ sleep(0.1)
349
+ th.raise(Interrupt)
350
+
351
+ begin
352
+ assert_equal true, th.value
353
+ rescue Interrupt
354
+ end
355
+ end
356
+ end