polyphony 0.28 → 0.29
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 +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
|