polyphony 0.28 → 0.29
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/README.md +23 -21
- data/Rakefile +2 -0
- data/TODO.md +0 -3
- data/docs/_includes/prevnext.html +17 -0
- data/docs/_layouts/default.html +106 -0
- data/docs/_sass/custom/custom.scss +21 -0
- data/docs/faq.md +13 -10
- data/docs/getting-started/installing.md +2 -0
- data/docs/getting-started/tutorial.md +5 -3
- data/docs/index.md +4 -5
- data/docs/technical-overview/concurrency.md +21 -19
- data/docs/technical-overview/design-principles.md +12 -20
- data/docs/technical-overview/exception-handling.md +70 -1
- data/docs/technical-overview/extending.md +1 -0
- data/docs/technical-overview/fiber-scheduling.md +109 -88
- data/docs/user-guide/all-about-timers.md +126 -0
- data/docs/user-guide/web-server.md +2 -2
- data/docs/user-guide.md +1 -1
- data/examples/core/xx-deferring-an-operation.rb +2 -2
- data/examples/core/xx-sleep-forever.rb +9 -0
- data/examples/core/xx-snooze-starve.rb +16 -0
- data/examples/core/xx-spin_error_backtrace.rb +1 -1
- data/examples/core/xx-trace.rb +1 -2
- data/examples/core/xx-worker-thread.rb +30 -0
- data/examples/io/xx-happy-eyeballs.rb +37 -0
- data/ext/gyro/gyro.c +8 -3
- data/ext/gyro/gyro.h +7 -1
- data/ext/gyro/queue.c +35 -3
- data/ext/gyro/selector.c +31 -2
- data/ext/gyro/thread.c +18 -16
- data/lib/polyphony/core/global_api.rb +0 -1
- data/lib/polyphony/core/thread_pool.rb +5 -0
- data/lib/polyphony/core/throttler.rb +0 -1
- data/lib/polyphony/extensions/fiber.rb +14 -3
- data/lib/polyphony/extensions/thread.rb +16 -4
- data/lib/polyphony/irb.rb +7 -1
- data/lib/polyphony/trace.rb +44 -11
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +1 -0
- data/test/helper.rb +1 -3
- data/test/test_async.rb +1 -1
- data/test/test_cancel_scope.rb +3 -3
- data/test/test_fiber.rb +157 -54
- data/test/test_global_api.rb +51 -1
- data/test/test_gyro.rb +4 -156
- data/test/test_io.rb +1 -1
- data/test/test_supervisor.rb +2 -2
- data/test/test_thread.rb +72 -1
- data/test/test_thread_pool.rb +6 -2
- data/test/test_throttler.rb +7 -5
- data/test/test_trace.rb +6 -6
- metadata +10 -5
- data/examples/core/xx-extended_fibers.rb +0 -150
- data/examples/core/xx-mt-scheduler.rb +0 -349
data/test/test_fiber.rb
CHANGED
@@ -25,6 +25,62 @@ class FiberTest < MiniTest::Test
|
|
25
25
|
f&.stop
|
26
26
|
end
|
27
27
|
|
28
|
+
def test_schedule
|
29
|
+
values = []
|
30
|
+
fibers = (0..2).map { |i| spin { suspend; values << i } }
|
31
|
+
snooze
|
32
|
+
|
33
|
+
fibers[0].schedule
|
34
|
+
assert_equal [], values
|
35
|
+
|
36
|
+
snooze
|
37
|
+
|
38
|
+
assert_equal [0], values
|
39
|
+
assert_equal :dead, fibers[0].state
|
40
|
+
|
41
|
+
fibers[1].schedule
|
42
|
+
fibers[2].schedule
|
43
|
+
|
44
|
+
assert_equal [0], values
|
45
|
+
snooze
|
46
|
+
assert_equal [0, 1, 2], values
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_cross_thread_schedule
|
50
|
+
buffer = []
|
51
|
+
worker_fiber = nil
|
52
|
+
async = Gyro::Async.new
|
53
|
+
worker = Thread.new do
|
54
|
+
worker_fiber = Fiber.current
|
55
|
+
async.signal!
|
56
|
+
suspend
|
57
|
+
buffer << :foo
|
58
|
+
end
|
59
|
+
|
60
|
+
async.await
|
61
|
+
assert worker_fiber
|
62
|
+
worker_fiber.schedule
|
63
|
+
worker.join
|
64
|
+
assert_equal [:foo], buffer
|
65
|
+
ensure
|
66
|
+
worker&.kill
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_ev_loop_anti_starve_mechanism
|
70
|
+
async = Gyro::Async.new
|
71
|
+
t = Thread.new do
|
72
|
+
f = spin_loop { snooze }
|
73
|
+
sleep 0.001
|
74
|
+
async.signal!(:foo)
|
75
|
+
end
|
76
|
+
|
77
|
+
result = move_on_after(0.05) { async.await }
|
78
|
+
|
79
|
+
assert_equal :foo, result
|
80
|
+
ensure
|
81
|
+
t.kill if t.alive?
|
82
|
+
end
|
83
|
+
|
28
84
|
def test_tag
|
29
85
|
assert_equal :main, Fiber.current.tag
|
30
86
|
Fiber.current.tag = :foo
|
@@ -63,7 +119,7 @@ class FiberTest < MiniTest::Test
|
|
63
119
|
2.times { snooze }
|
64
120
|
result << 2
|
65
121
|
end
|
66
|
-
|
122
|
+
spin { f.raise }
|
67
123
|
assert_equal 0, result.size
|
68
124
|
begin
|
69
125
|
f.await
|
@@ -88,7 +144,7 @@ class FiberTest < MiniTest::Test
|
|
88
144
|
2.times { snooze }
|
89
145
|
result << 2
|
90
146
|
end
|
91
|
-
|
147
|
+
spin { f.raise MyError }
|
92
148
|
assert_equal 0, result.size
|
93
149
|
begin
|
94
150
|
f.await
|
@@ -110,7 +166,7 @@ class FiberTest < MiniTest::Test
|
|
110
166
|
2.times { snooze }
|
111
167
|
result << 2
|
112
168
|
end
|
113
|
-
|
169
|
+
spin { f.raise(MyError, 'foo') }
|
114
170
|
assert_equal 0, result.size
|
115
171
|
begin
|
116
172
|
f.await
|
@@ -133,7 +189,7 @@ class FiberTest < MiniTest::Test
|
|
133
189
|
2.times { snooze }
|
134
190
|
result << 2
|
135
191
|
end
|
136
|
-
|
192
|
+
spin { f.raise 'foo' }
|
137
193
|
assert_equal 0, result.size
|
138
194
|
begin
|
139
195
|
f.await
|
@@ -156,7 +212,7 @@ class FiberTest < MiniTest::Test
|
|
156
212
|
2.times { snooze }
|
157
213
|
result << 2
|
158
214
|
end
|
159
|
-
|
215
|
+
spin { f.raise MyError.new('bar') }
|
160
216
|
assert_equal 0, result.size
|
161
217
|
begin
|
162
218
|
f.await
|
@@ -179,7 +235,7 @@ class FiberTest < MiniTest::Test
|
|
179
235
|
2.times { snooze }
|
180
236
|
result << 2
|
181
237
|
end
|
182
|
-
|
238
|
+
spin { f.cancel! }
|
183
239
|
assert_equal 0, result.size
|
184
240
|
begin
|
185
241
|
f.await
|
@@ -202,7 +258,7 @@ class FiberTest < MiniTest::Test
|
|
202
258
|
result << 2
|
203
259
|
3
|
204
260
|
end
|
205
|
-
|
261
|
+
spin { f.interrupt(42) }
|
206
262
|
|
207
263
|
await_result = f.await
|
208
264
|
assert_equal 1, result.size
|
@@ -220,7 +276,7 @@ class FiberTest < MiniTest::Test
|
|
220
276
|
result << 2
|
221
277
|
3
|
222
278
|
end
|
223
|
-
|
279
|
+
spin { f.stop(42) }
|
224
280
|
|
225
281
|
await_result = f.await
|
226
282
|
assert_equal 1, result.size
|
@@ -253,7 +309,7 @@ class FiberTest < MiniTest::Test
|
|
253
309
|
f2.await
|
254
310
|
result && result += 1
|
255
311
|
end
|
256
|
-
|
312
|
+
spin { f2.interrupt }
|
257
313
|
suspend
|
258
314
|
assert_nil result
|
259
315
|
assert_equal :dead, f1.state
|
@@ -337,6 +393,7 @@ class FiberTest < MiniTest::Test
|
|
337
393
|
end
|
338
394
|
|
339
395
|
def test_select_from_multiple_fibers
|
396
|
+
sleep 0
|
340
397
|
buffer = []
|
341
398
|
f1 = spin { sleep 0.01; buffer << :foo; :foo }
|
342
399
|
f2 = spin { sleep 0.03; buffer << :bar; :bar }
|
@@ -388,51 +445,6 @@ class FiberTest < MiniTest::Test
|
|
388
445
|
assert_equal [42], values
|
389
446
|
assert !f.running?
|
390
447
|
end
|
391
|
-
end
|
392
|
-
|
393
|
-
class MailboxTest < MiniTest::Test
|
394
|
-
def test_that_fiber_can_receive_messages
|
395
|
-
msgs = []
|
396
|
-
f = spin { loop { msgs << receive } }
|
397
|
-
|
398
|
-
snooze # allow fiber to start
|
399
|
-
|
400
|
-
3.times do |i|
|
401
|
-
f << i
|
402
|
-
snooze
|
403
|
-
end
|
404
|
-
|
405
|
-
assert_equal [0, 1, 2], msgs
|
406
|
-
ensure
|
407
|
-
f&.stop
|
408
|
-
end
|
409
|
-
|
410
|
-
def test_that_multiple_messages_sent_at_once_arrive_in_order
|
411
|
-
msgs = []
|
412
|
-
f = spin { loop { msgs << receive } }
|
413
|
-
|
414
|
-
snooze # allow coproc to start
|
415
|
-
|
416
|
-
3.times { |i| f << i }
|
417
|
-
|
418
|
-
snooze
|
419
|
-
|
420
|
-
assert_equal [0, 1, 2], msgs
|
421
|
-
ensure
|
422
|
-
f&.stop
|
423
|
-
end
|
424
|
-
|
425
|
-
def test_that_sent_message_are_queued_before_calling_receive
|
426
|
-
buffer = []
|
427
|
-
receiver = spin { suspend; 3.times { buffer << receive } }
|
428
|
-
sender = spin { 3.times { |i| receiver << (i * 10) } }
|
429
|
-
|
430
|
-
sender.await
|
431
|
-
receiver.schedule
|
432
|
-
receiver.await
|
433
|
-
|
434
|
-
assert_equal [0, 10, 20], buffer
|
435
|
-
end
|
436
448
|
|
437
449
|
def test_list_and_count
|
438
450
|
assert_equal 1, Fiber.count
|
@@ -510,4 +522,95 @@ class MailboxTest < MiniTest::Test
|
|
510
522
|
assert_nil parent_error
|
511
523
|
assert_kind_of Interrupt, main_fiber_error
|
512
524
|
end
|
525
|
+
|
526
|
+
def test_signal_exception_in_fiber
|
527
|
+
parent_error = nil
|
528
|
+
main_fiber_error = nil
|
529
|
+
f2 = nil
|
530
|
+
f1 = spin do
|
531
|
+
f2 = spin { raise SignalException.new('HUP') }
|
532
|
+
suspend
|
533
|
+
rescue Exception => parent_error
|
534
|
+
end
|
535
|
+
|
536
|
+
begin
|
537
|
+
suspend
|
538
|
+
rescue Exception => main_fiber_error
|
539
|
+
end
|
540
|
+
|
541
|
+
assert_nil parent_error
|
542
|
+
assert_kind_of SignalException, main_fiber_error
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
class MailboxTest < MiniTest::Test
|
547
|
+
def test_that_fiber_can_receive_messages
|
548
|
+
msgs = []
|
549
|
+
f = spin { loop { msgs << receive } }
|
550
|
+
|
551
|
+
snooze # allow fiber to start
|
552
|
+
|
553
|
+
3.times do |i|
|
554
|
+
f << i
|
555
|
+
snooze
|
556
|
+
end
|
557
|
+
|
558
|
+
assert_equal [0, 1, 2], msgs
|
559
|
+
ensure
|
560
|
+
f&.stop
|
561
|
+
end
|
562
|
+
|
563
|
+
def test_that_multiple_messages_sent_at_once_arrive_in_order
|
564
|
+
msgs = []
|
565
|
+
f = spin { loop { msgs << receive } }
|
566
|
+
|
567
|
+
snooze # allow coproc to start
|
568
|
+
|
569
|
+
3.times { |i| f << i }
|
570
|
+
|
571
|
+
snooze
|
572
|
+
|
573
|
+
assert_equal [0, 1, 2], msgs
|
574
|
+
ensure
|
575
|
+
f&.stop
|
576
|
+
end
|
577
|
+
|
578
|
+
def test_that_sent_message_are_queued_before_calling_receive
|
579
|
+
buffer = []
|
580
|
+
receiver = spin { suspend; 3.times { buffer << receive } }
|
581
|
+
sender = spin { 3.times { |i| receiver << (i * 10) } }
|
582
|
+
|
583
|
+
sender.await
|
584
|
+
receiver.schedule
|
585
|
+
receiver.await
|
586
|
+
|
587
|
+
assert_equal [0, 10, 20], buffer
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_cross_thread_send_receive
|
591
|
+
skip "There's currently a race condition in cross-thread send/receive. We're going to rewrite it in C"
|
592
|
+
ping_receive_buffer = []
|
593
|
+
pong_receive_buffer = []
|
594
|
+
pong = Thread.new do
|
595
|
+
loop do
|
596
|
+
peer, data = receive
|
597
|
+
pong_receive_buffer << data
|
598
|
+
peer << 'pong'
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
ping = Thread.new do
|
603
|
+
3.times do
|
604
|
+
pong << [Fiber.current, 'ping']
|
605
|
+
data = receive
|
606
|
+
ping_receive_buffer << data
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
ping.join
|
611
|
+
pong.kill
|
612
|
+
|
613
|
+
assert_equal %w{pong pong pong}, ping_receive_buffer
|
614
|
+
assert_equal %w{ping ping ping}, pong_receive_buffer
|
615
|
+
end
|
513
616
|
end
|
data/test/test_global_api.rb
CHANGED
@@ -36,7 +36,7 @@ class SpinTest < MiniTest::Test
|
|
36
36
|
sleep(1)
|
37
37
|
42
|
38
38
|
end
|
39
|
-
|
39
|
+
spin { fiber.interrupt }
|
40
40
|
suspend
|
41
41
|
assert_nil fiber.result
|
42
42
|
end
|
@@ -321,4 +321,54 @@ class MoveOnAfterTest < MiniTest::Test
|
|
321
321
|
f.stop
|
322
322
|
assert !f.running?
|
323
323
|
end
|
324
|
+
|
325
|
+
def test_snooze
|
326
|
+
values = []
|
327
|
+
3.times.map do |i|
|
328
|
+
spin do
|
329
|
+
3.times do
|
330
|
+
snooze
|
331
|
+
values << i
|
332
|
+
end
|
333
|
+
suspend
|
334
|
+
end
|
335
|
+
end
|
336
|
+
suspend
|
337
|
+
|
338
|
+
assert_equal [0, 1, 2, 0, 1, 2, 0, 1, 2], values
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_defer
|
342
|
+
values = []
|
343
|
+
spin { values << 1 }
|
344
|
+
spin { values << 2 }
|
345
|
+
spin { values << 3 }
|
346
|
+
suspend
|
347
|
+
|
348
|
+
assert_equal [1, 2, 3], values
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_suspend
|
352
|
+
values = []
|
353
|
+
spin do
|
354
|
+
values << :foo
|
355
|
+
suspend
|
356
|
+
end
|
357
|
+
suspend
|
358
|
+
|
359
|
+
assert_equal [:foo], values
|
360
|
+
end
|
361
|
+
|
362
|
+
def test_schedule_and_suspend
|
363
|
+
values = []
|
364
|
+
3.times.map do |i|
|
365
|
+
spin do
|
366
|
+
values << i
|
367
|
+
suspend
|
368
|
+
end
|
369
|
+
end
|
370
|
+
suspend
|
371
|
+
|
372
|
+
assert_equal [0, 1, 2], values
|
373
|
+
end
|
324
374
|
end
|
data/test/test_gyro.rb
CHANGED
@@ -3,175 +3,23 @@
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
5
|
class GyroTest < MiniTest::Test
|
6
|
-
def test_fiber_state
|
7
|
-
assert_equal :running, Fiber.current.state
|
8
|
-
|
9
|
-
f = Fiber.new {}
|
10
|
-
|
11
|
-
assert_equal :waiting, f.state
|
12
|
-
f.resume
|
13
|
-
assert_equal :dead, f.state
|
14
|
-
|
15
|
-
f = Fiber.new { }
|
16
|
-
f.schedule
|
17
|
-
assert_equal :runnable, f.state
|
18
|
-
snooze
|
19
|
-
assert_equal :dead, f.state
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_schedule
|
23
|
-
values = []
|
24
|
-
fibers = 3.times.map { |i| Fiber.new { values << i } }
|
25
|
-
fibers[0].schedule
|
26
|
-
|
27
|
-
assert_equal [], values
|
28
|
-
snooze
|
29
|
-
assert_equal [0], values
|
30
|
-
|
31
|
-
fibers[1].schedule
|
32
|
-
fibers[2].schedule
|
33
|
-
|
34
|
-
assert_equal [0], values
|
35
|
-
snooze
|
36
|
-
assert_equal [0, 1, 2], values
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_that_run_loop_returns_immediately_if_no_watchers
|
40
|
-
t0 = Time.now
|
41
|
-
suspend
|
42
|
-
t1 = Time.now
|
43
|
-
assert((t1 - t0) < 0.01)
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_defer
|
47
|
-
values = []
|
48
|
-
defer { values << 1 }
|
49
|
-
defer { values << 2 }
|
50
|
-
defer { values << 3 }
|
51
|
-
suspend
|
52
|
-
|
53
|
-
assert_equal [1, 2, 3], values
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_schedule
|
57
|
-
values = []
|
58
|
-
f = Fiber.new do
|
59
|
-
values << :foo
|
60
|
-
# We *have* to suspend the fiber in order to yield to the reactor,
|
61
|
-
# otherwise control will transfer back to root fiber.
|
62
|
-
suspend
|
63
|
-
end
|
64
|
-
assert_equal [], values
|
65
|
-
f.schedule
|
66
|
-
suspend
|
67
|
-
|
68
|
-
assert_equal [:foo], values
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_suspend
|
72
|
-
values = []
|
73
|
-
Fiber.new do
|
74
|
-
values << :foo
|
75
|
-
suspend
|
76
|
-
end.schedule
|
77
|
-
suspend
|
78
|
-
|
79
|
-
assert_equal [:foo], values
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_schedule_and_suspend
|
83
|
-
values = []
|
84
|
-
3.times.map do |i|
|
85
|
-
Fiber.new do
|
86
|
-
values << i
|
87
|
-
suspend
|
88
|
-
end.schedule
|
89
|
-
end
|
90
|
-
suspend
|
91
|
-
|
92
|
-
assert_equal [0, 1, 2], values
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_snooze
|
96
|
-
values = []
|
97
|
-
3.times.map do |i|
|
98
|
-
Fiber.new do
|
99
|
-
3.times do
|
100
|
-
snooze
|
101
|
-
values << i
|
102
|
-
end
|
103
|
-
suspend
|
104
|
-
end.schedule
|
105
|
-
end
|
106
|
-
suspend
|
107
|
-
|
108
|
-
assert_equal [0, 1, 2, 0, 1, 2, 0, 1, 2], values
|
109
|
-
end
|
110
|
-
|
111
6
|
def test_break
|
112
7
|
skip "break is still not implemented for new scheduler"
|
113
8
|
values = []
|
114
|
-
Fiber.
|
9
|
+
Fiber.spin do
|
115
10
|
values << :foo
|
116
11
|
snooze
|
117
12
|
# here will never be reached
|
118
13
|
values << :bar
|
119
14
|
suspend
|
120
|
-
end
|
15
|
+
end
|
121
16
|
|
122
|
-
Fiber.
|
17
|
+
Fiber.spin do
|
123
18
|
Gyro.break!
|
124
|
-
end
|
19
|
+
end
|
125
20
|
|
126
21
|
suspend
|
127
22
|
|
128
23
|
assert_equal [:foo], values
|
129
24
|
end
|
130
|
-
|
131
|
-
def test_reset
|
132
|
-
values = []
|
133
|
-
f1 = Fiber.new do
|
134
|
-
values << :foo
|
135
|
-
snooze
|
136
|
-
values << :bar
|
137
|
-
suspend
|
138
|
-
end.schedule
|
139
|
-
|
140
|
-
f2 = Fiber.new do
|
141
|
-
Thread.current.reset_fiber_scheduling
|
142
|
-
values << :restarted
|
143
|
-
snooze
|
144
|
-
values << :baz
|
145
|
-
end.schedule
|
146
|
-
|
147
|
-
suspend
|
148
|
-
|
149
|
-
f1.schedule
|
150
|
-
suspend
|
151
|
-
assert_equal %i[foo restarted baz], values
|
152
|
-
end
|
153
|
-
|
154
|
-
def test_restart
|
155
|
-
values = []
|
156
|
-
Fiber.new do
|
157
|
-
values << :foo
|
158
|
-
snooze
|
159
|
-
# this part will not be reached, as Gyro state is reset
|
160
|
-
values << :bar
|
161
|
-
suspend
|
162
|
-
end.schedule
|
163
|
-
|
164
|
-
Fiber.new do
|
165
|
-
Thread.current.reset_fiber_scheduling
|
166
|
-
|
167
|
-
# control is transfer to the fiber that called Gyro.restart
|
168
|
-
values << :restarted
|
169
|
-
snooze
|
170
|
-
values << :baz
|
171
|
-
end.schedule
|
172
|
-
|
173
|
-
suspend
|
174
|
-
|
175
|
-
assert_equal %i[foo restarted baz], values
|
176
|
-
end
|
177
25
|
end
|
data/test/test_io.rb
CHANGED
data/test/test_supervisor.rb
CHANGED
@@ -106,7 +106,7 @@ class SupervisorTest < MiniTest::Test
|
|
106
106
|
buffer = []
|
107
107
|
supervisor = nil
|
108
108
|
supervisor = Polyphony::Supervisor.new
|
109
|
-
|
109
|
+
spin { supervisor.interrupt(42) }
|
110
110
|
buffer << supervisor.await { |s|
|
111
111
|
(1..3).each { |i|
|
112
112
|
s.spin {
|
@@ -125,7 +125,7 @@ class SupervisorTest < MiniTest::Test
|
|
125
125
|
buffer = []
|
126
126
|
supervisor = nil
|
127
127
|
supervisor = Polyphony::Supervisor.new
|
128
|
-
|
128
|
+
spin { supervisor.interrupt(42) }
|
129
129
|
buffer << supervisor.select { |s|
|
130
130
|
(1..3).each { |i|
|
131
131
|
s.spin {
|
data/test/test_thread.rb
CHANGED
@@ -5,25 +5,35 @@ require_relative 'helper'
|
|
5
5
|
class ThreadTest < MiniTest::Test
|
6
6
|
def test_thread_spin
|
7
7
|
buffer = []
|
8
|
-
spin { (1..3).each { |i| snooze; buffer << i } }
|
8
|
+
f = spin { (1..3).each { |i| snooze; buffer << i } }
|
9
9
|
t = Thread.new do
|
10
10
|
s1 = spin { (11..13).each { |i| snooze; buffer << i } }
|
11
11
|
s2 = spin { (21..23).each { |i| snooze; buffer << i } }
|
12
12
|
Fiber.join(s1, s2)
|
13
13
|
end
|
14
|
+
f.join
|
14
15
|
t.join
|
15
16
|
|
16
17
|
assert_equal [1, 2, 3, 11, 12, 13, 21, 22, 23], buffer.sort
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_thread_join
|
21
|
+
tr = nil
|
22
|
+
# tr = Polyphony::Trace.new(:fiber_all) { |r| p r[:event] }
|
23
|
+
# Gyro.trace(true)
|
24
|
+
# tr.enable
|
25
|
+
|
20
26
|
buffer = []
|
21
27
|
spin { (1..3).each { |i| snooze; buffer << i } }
|
22
28
|
t = Thread.new { sleep 0.01; buffer << 4 }
|
29
|
+
|
23
30
|
r = t.join
|
24
31
|
|
25
32
|
assert_equal [1, 2, 3, 4], buffer
|
26
33
|
assert_equal t, r
|
34
|
+
ensure
|
35
|
+
tr&.disable
|
36
|
+
Gyro.trace(nil)
|
27
37
|
end
|
28
38
|
|
29
39
|
def test_thread_join_with_timeout
|
@@ -53,4 +63,65 @@ class ThreadTest < MiniTest::Test
|
|
53
63
|
)
|
54
64
|
assert_equal str, t.inspect
|
55
65
|
end
|
66
|
+
|
67
|
+
def test_that_suspend_returns_immediately_if_no_watchers
|
68
|
+
records = []
|
69
|
+
t = Polyphony::Trace.new(:fiber_all) { |r| records << r if r[:event] =~ /^fiber_/ }
|
70
|
+
t.enable
|
71
|
+
Gyro.trace(true)
|
72
|
+
|
73
|
+
suspend
|
74
|
+
t.disable
|
75
|
+
assert_equal [:fiber_switchpoint], records.map { |r| r[:event] }
|
76
|
+
ensure
|
77
|
+
t&.disable
|
78
|
+
Gyro.trace(false)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_reset
|
82
|
+
values = []
|
83
|
+
f1 = spin do
|
84
|
+
values << :foo
|
85
|
+
snooze
|
86
|
+
values << :bar
|
87
|
+
suspend
|
88
|
+
end
|
89
|
+
|
90
|
+
f2 = spin do
|
91
|
+
Thread.current.reset_fiber_scheduling
|
92
|
+
values << :restarted
|
93
|
+
snooze
|
94
|
+
values << :baz
|
95
|
+
end
|
96
|
+
|
97
|
+
suspend
|
98
|
+
|
99
|
+
f1.schedule
|
100
|
+
suspend
|
101
|
+
assert_equal %i[foo restarted baz], values
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_restart
|
105
|
+
values = []
|
106
|
+
spin do
|
107
|
+
values << :foo
|
108
|
+
snooze
|
109
|
+
# this part will not be reached, as Gyro state is reset
|
110
|
+
values << :bar
|
111
|
+
suspend
|
112
|
+
end
|
113
|
+
|
114
|
+
spin do
|
115
|
+
Thread.current.reset_fiber_scheduling
|
116
|
+
|
117
|
+
# control is transfer to the fiber that called Gyro.restart
|
118
|
+
values << :restarted
|
119
|
+
snooze
|
120
|
+
values << :baz
|
121
|
+
end
|
122
|
+
|
123
|
+
suspend
|
124
|
+
|
125
|
+
assert_equal %i[foo restarted baz], values
|
126
|
+
end
|
56
127
|
end
|
data/test/test_thread_pool.rb
CHANGED
@@ -5,10 +5,11 @@ require_relative 'helper'
|
|
5
5
|
class ThreadPoolTest < MiniTest::Test
|
6
6
|
def setup
|
7
7
|
super
|
8
|
-
@pool = Polyphony::ThreadPool.new
|
8
|
+
# @pool = Polyphony::ThreadPool.new
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_process
|
12
|
+
skip
|
12
13
|
current_thread = Thread.current
|
13
14
|
|
14
15
|
processing_thread = nil
|
@@ -21,6 +22,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def test_multi_process
|
25
|
+
skip
|
24
26
|
current_thread = Thread.current
|
25
27
|
threads = []
|
26
28
|
results = []
|
@@ -42,6 +44,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def test_process_with_exception
|
47
|
+
skip
|
45
48
|
result = nil
|
46
49
|
begin
|
47
50
|
result = @pool.process { raise 'foo' }
|
@@ -53,6 +56,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
53
56
|
end
|
54
57
|
|
55
58
|
def test_cast
|
59
|
+
skip
|
56
60
|
t0 = Time.now
|
57
61
|
threads = []
|
58
62
|
buffer = []
|
@@ -68,7 +72,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
68
72
|
assert elapsed < 0.005
|
69
73
|
assert buffer.size < 2
|
70
74
|
|
71
|
-
sleep 0.
|
75
|
+
sleep 0.05
|
72
76
|
assert_equal @pool.size, threads.uniq.size
|
73
77
|
assert_equal (0..9).to_a, buffer.sort
|
74
78
|
end
|