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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/TODO.md +0 -4
- data/ext/polyphony/backend_io_uring.c +34 -1
- data/ext/polyphony/backend_io_uring_context.c +24 -18
- data/ext/polyphony/backend_io_uring_context.h +4 -2
- data/ext/polyphony/backend_libev.c +4 -7
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +20 -18
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -0
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +1 -0
- data/ext/polyphony/thread.c +63 -0
- data/lib/polyphony/adapters/open3.rb +190 -0
- data/lib/polyphony/core/sync.rb +83 -13
- data/lib/polyphony/core/timer.rb +7 -25
- data/lib/polyphony/extensions/exception.rb +15 -0
- data/lib/polyphony/extensions/fiber.rb +14 -13
- data/lib/polyphony/extensions/io.rb +56 -14
- data/lib/polyphony/extensions/kernel.rb +1 -1
- data/lib/polyphony/extensions/object.rb +1 -13
- data/lib/polyphony/extensions/process.rb +76 -1
- data/lib/polyphony/extensions/thread.rb +19 -27
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +11 -5
- data/test/helper.rb +46 -4
- data/test/open3/envutil.rb +380 -0
- data/test/open3/find_executable.rb +24 -0
- data/test/stress.rb +11 -7
- data/test/test_backend.rb +7 -2
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +2 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +13 -12
- data/test/test_io.rb +39 -0
- data/test/test_kernel.rb +2 -2
- data/test/test_monitor.rb +356 -0
- data/test/test_open3.rb +338 -0
- data/test/test_signal.rb +5 -1
- data/test/test_socket.rb +6 -3
- data/test/test_sync.rb +46 -0
- data/test/test_thread.rb +10 -1
- data/test/test_thread_pool.rb +5 -0
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +8 -2
- data/test/test_trace.rb +2 -0
- data/vendor/liburing/.github/workflows/build.yml +8 -0
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +8 -0
- data/vendor/liburing/configure +17 -25
- data/vendor/liburing/debian/liburing-dev.manpages +2 -0
- data/vendor/liburing/debian/rules +2 -1
- data/vendor/liburing/examples/Makefile +2 -1
- data/vendor/liburing/examples/io_uring-udp.c +11 -3
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/make-debs.sh +4 -2
- data/vendor/liburing/src/Makefile +5 -5
- data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
- data/vendor/liburing/src/include/liburing.h +86 -11
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/liburing-ffi.map +12 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/register.c +7 -2
- data/vendor/liburing/src/setup.c +373 -81
- data/vendor/liburing/test/232c93d07b74.c +3 -3
- data/vendor/liburing/test/Makefile +10 -3
- data/vendor/liburing/test/accept.c +2 -1
- data/vendor/liburing/test/buf-ring.c +35 -75
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/coredump.c +59 -0
- data/vendor/liburing/test/fallocate.c +9 -0
- data/vendor/liburing/test/fd-pass.c +34 -3
- data/vendor/liburing/test/file-verify.c +27 -6
- data/vendor/liburing/test/helpers.c +3 -1
- data/vendor/liburing/test/io_uring_register.c +25 -28
- data/vendor/liburing/test/io_uring_setup.c +1 -1
- data/vendor/liburing/test/poll-cancel-all.c +29 -5
- data/vendor/liburing/test/poll-race-mshot.c +6 -22
- data/vendor/liburing/test/read-write.c +53 -0
- data/vendor/liburing/test/recv-msgall.c +21 -23
- data/vendor/liburing/test/reg-fd-only.c +55 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/ringbuf-read.c +2 -10
- data/vendor/liburing/test/send_recvmsg.c +5 -16
- data/vendor/liburing/test/shutdown.c +2 -1
- data/vendor/liburing/test/socket-io-cmd.c +215 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -1
- data/vendor/liburing/test/socket-rw-offset.c +2 -1
- data/vendor/liburing/test/socket-rw.c +2 -1
- data/vendor/liburing/test/timeout.c +276 -0
- data/vendor/liburing/test/xattr.c +38 -25
- metadata +14 -3
- 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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
"
|
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.
|
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
|
-
|
29
|
+
f = spin {
|
30
30
|
loop {
|
31
31
|
a.await
|
32
32
|
count += 1
|
33
|
-
spin {
|
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
|
-
|
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
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.
|
1160
|
+
f1 = spin { sleep 0.1; :foo }
|
1151
1161
|
f2 = spin { sleep 1; :bar }
|
1152
|
-
|
1162
|
+
snooze
|
1163
|
+
f2.interrupt(:baz)
|
1164
|
+
|
1153
1165
|
result = Fiber.select(f1, f2)
|
1154
1166
|
assert_equal [f2, :baz], result
|
1155
1167
|
end
|
data/test/test_global_api.rb
CHANGED
@@ -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.
|
148
|
-
move_on_after(0.
|
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.
|
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.
|
158
|
-
move_on_after(0.
|
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.
|
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.
|
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
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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(
|
11
|
+
timer = spin { throttled_loop(20) { counter += 1 } }
|
12
12
|
|
13
|
-
system('sleep 0.
|
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
|