polyphony 1.5 → 1.6

Sign up to get free protection for your applications and to get access to all the features.
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