polyphony 0.57.0 → 0.60
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/CHANGELOG.md +27 -0
- data/Gemfile.lock +15 -29
- data/examples/core/message_based_supervision.rb +51 -0
- data/ext/polyphony/backend_common.c +108 -3
- data/ext/polyphony/backend_common.h +23 -0
- data/ext/polyphony/backend_io_uring.c +117 -39
- data/ext/polyphony/backend_io_uring_context.c +11 -3
- data/ext/polyphony/backend_io_uring_context.h +5 -3
- data/ext/polyphony/backend_libev.c +92 -30
- data/ext/polyphony/extconf.rb +2 -2
- data/ext/polyphony/fiber.c +1 -34
- data/ext/polyphony/polyphony.c +12 -19
- data/ext/polyphony/polyphony.h +10 -20
- data/ext/polyphony/polyphony_ext.c +0 -4
- data/ext/polyphony/queue.c +12 -12
- data/ext/polyphony/runqueue.c +17 -85
- data/ext/polyphony/runqueue.h +27 -0
- data/ext/polyphony/thread.c +10 -99
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/extensions/fiber.rb +102 -82
- data/lib/polyphony/extensions/io.rb +10 -9
- data/lib/polyphony/extensions/openssl.rb +14 -4
- data/lib/polyphony/extensions/socket.rb +15 -15
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -7
- data/test/test_backend.rb +71 -5
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +106 -18
- data/test/test_global_api.rb +1 -1
- data/test/test_io.rb +29 -0
- data/test/test_supervise.rb +100 -100
- data/test/test_thread.rb +57 -11
- data/test/test_thread_pool.rb +1 -1
- data/test/test_trace.rb +28 -49
- metadata +4 -108
- data/ext/polyphony/tracing.c +0 -11
- data/lib/polyphony/adapters/trace.rb +0 -138
data/lib/polyphony/version.rb
CHANGED
data/polyphony.gemspec
CHANGED
@@ -29,13 +29,6 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency 'pry', '0.13.1'
|
30
30
|
|
31
31
|
s.add_development_dependency 'msgpack', '1.4.2'
|
32
|
-
s.add_development_dependency 'pg', '1.1.4'
|
33
|
-
s.add_development_dependency 'redis', '4.1.0'
|
34
|
-
s.add_development_dependency 'hiredis', '0.6.3'
|
35
|
-
s.add_development_dependency 'http_parser.rb', '~>0.6.0'
|
36
|
-
s.add_development_dependency 'rack', '>=2.0.8', '<2.3.0'
|
37
|
-
s.add_development_dependency 'mysql2', '0.5.3'
|
38
|
-
s.add_development_dependency 'sequel', '5.34.0'
|
39
32
|
s.add_development_dependency 'httparty', '0.17.1'
|
40
33
|
s.add_development_dependency 'localhost', '~>1.1.4'
|
41
34
|
|
data/test/test_backend.rb
CHANGED
@@ -33,7 +33,7 @@ class BackendTest < MiniTest::Test
|
|
33
33
|
def test_write_read_partial
|
34
34
|
i, o = IO.pipe
|
35
35
|
buf = +''
|
36
|
-
f = spin { @backend.read(i, buf, 5, false) }
|
36
|
+
f = spin { @backend.read(i, buf, 5, false, 0) }
|
37
37
|
@backend.write(o, 'Hello world')
|
38
38
|
return_value = f.await
|
39
39
|
|
@@ -44,7 +44,7 @@ class BackendTest < MiniTest::Test
|
|
44
44
|
def test_write_read_to_eof_limited_buffer
|
45
45
|
i, o = IO.pipe
|
46
46
|
buf = +''
|
47
|
-
f = spin { @backend.read(i, buf, 5, true) }
|
47
|
+
f = spin { @backend.read(i, buf, 5, true, 0) }
|
48
48
|
@backend.write(o, 'Hello')
|
49
49
|
snooze
|
50
50
|
@backend.write(o, ' world')
|
@@ -59,7 +59,7 @@ class BackendTest < MiniTest::Test
|
|
59
59
|
def test_write_read_to_eof
|
60
60
|
i, o = IO.pipe
|
61
61
|
buf = +''
|
62
|
-
f = spin { @backend.read(i, buf, 10**6, true) }
|
62
|
+
f = spin { @backend.read(i, buf, 10**6, true, 0) }
|
63
63
|
@backend.write(o, 'Hello')
|
64
64
|
snooze
|
65
65
|
@backend.write(o, ' world')
|
@@ -71,6 +71,33 @@ class BackendTest < MiniTest::Test
|
|
71
71
|
assert_equal return_value, buf
|
72
72
|
end
|
73
73
|
|
74
|
+
def test_write_read_with_buffer_position
|
75
|
+
i, o = IO.pipe
|
76
|
+
buf = +'abcdefghij'
|
77
|
+
f = spin { @backend.read(i, buf, 20, false, 0) }
|
78
|
+
@backend.write(o, 'blah')
|
79
|
+
return_value = f.await
|
80
|
+
|
81
|
+
assert_equal 'blah', buf
|
82
|
+
assert_equal return_value, buf
|
83
|
+
|
84
|
+
buf = +'abcdefghij'
|
85
|
+
f = spin { @backend.read(i, buf, 20, false, -1) }
|
86
|
+
@backend.write(o, 'klmn')
|
87
|
+
return_value = f.await
|
88
|
+
|
89
|
+
assert_equal 'abcdefghijklmn', buf
|
90
|
+
assert_equal return_value, buf
|
91
|
+
|
92
|
+
buf = +'abcdefghij'
|
93
|
+
f = spin { @backend.read(i, buf, 20, false, 3) }
|
94
|
+
@backend.write(o, 'DEF')
|
95
|
+
return_value = f.await
|
96
|
+
|
97
|
+
assert_equal 'abcDEF', buf
|
98
|
+
assert_equal return_value, buf
|
99
|
+
end
|
100
|
+
|
74
101
|
def test_waitpid
|
75
102
|
pid = fork do
|
76
103
|
@backend.post_fork
|
@@ -87,7 +114,7 @@ class BackendTest < MiniTest::Test
|
|
87
114
|
buf = []
|
88
115
|
f = spin do
|
89
116
|
buf << :ready
|
90
|
-
@backend.read_loop(i) { |d| buf << d }
|
117
|
+
@backend.read_loop(i, 8192) { |d| buf << d }
|
91
118
|
buf << :done
|
92
119
|
end
|
93
120
|
|
@@ -107,7 +134,7 @@ class BackendTest < MiniTest::Test
|
|
107
134
|
parent = spin do
|
108
135
|
f = spin do
|
109
136
|
buf << :ready
|
110
|
-
@backend.read_loop(i) { |d| buf << d }
|
137
|
+
@backend.read_loop(i, 8192) { |d| buf << d }
|
111
138
|
buf << :done
|
112
139
|
end
|
113
140
|
suspend
|
@@ -125,6 +152,16 @@ class BackendTest < MiniTest::Test
|
|
125
152
|
assert_equal [:ready, 'foo', 'bar'], buf
|
126
153
|
end
|
127
154
|
|
155
|
+
def test_read_loop_with_max_len
|
156
|
+
r, w = IO.pipe
|
157
|
+
|
158
|
+
w << 'foobar'
|
159
|
+
w.close
|
160
|
+
buf = []
|
161
|
+
@backend.read_loop(r, 3) { |data| buf << data }
|
162
|
+
assert_equal ['foo', 'bar'], buf
|
163
|
+
end
|
164
|
+
|
128
165
|
Net = Polyphony::Net
|
129
166
|
|
130
167
|
def test_accept
|
@@ -340,9 +377,38 @@ class BackendTest < MiniTest::Test
|
|
340
377
|
# GC period.
|
341
378
|
sleep 0.05
|
342
379
|
assert_equal count + 1, GC.count
|
380
|
+
|
381
|
+
@backend.idle_gc_period = 0
|
382
|
+
count = GC.count
|
383
|
+
sleep 0.001
|
384
|
+
sleep 0.002
|
385
|
+
sleep 0.003
|
386
|
+
assert_equal count, GC.count
|
343
387
|
ensure
|
344
388
|
GC.enable
|
345
389
|
end
|
390
|
+
|
391
|
+
def test_idle_proc
|
392
|
+
counter = 0
|
393
|
+
|
394
|
+
@backend.idle_proc = proc { counter += 1 }
|
395
|
+
|
396
|
+
3.times { snooze }
|
397
|
+
assert_equal 0, counter
|
398
|
+
|
399
|
+
sleep 0.01
|
400
|
+
assert_equal 1, counter
|
401
|
+
sleep 0.01
|
402
|
+
assert_equal 2, counter
|
403
|
+
|
404
|
+
assert_equal 2, counter
|
405
|
+
3.times { snooze }
|
406
|
+
assert_equal 2, counter
|
407
|
+
|
408
|
+
@backend.idle_proc = nil
|
409
|
+
sleep 0.01
|
410
|
+
assert_equal 2, counter
|
411
|
+
end
|
346
412
|
end
|
347
413
|
|
348
414
|
class BackendChainTest < MiniTest::Test
|
data/test/test_ext.rb
CHANGED
data/test/test_fiber.rb
CHANGED
@@ -43,6 +43,14 @@ class FiberTest < MiniTest::Test
|
|
43
43
|
f&.stop
|
44
44
|
end
|
45
45
|
|
46
|
+
def test_await_dead_children
|
47
|
+
f1 = spin { :foo }
|
48
|
+
f2 = spin { :bar }
|
49
|
+
2.times { snooze }
|
50
|
+
|
51
|
+
assert_equal [:foo, :bar], Fiber.await(f1, f2)
|
52
|
+
end
|
53
|
+
|
46
54
|
def test_await_from_multiple_fibers
|
47
55
|
buffer = []
|
48
56
|
f1 = spin {
|
@@ -348,12 +356,12 @@ class FiberTest < MiniTest::Test
|
|
348
356
|
assert_equal [:foo, :terminate], buffer
|
349
357
|
end
|
350
358
|
|
351
|
-
|
352
|
-
ruby -rbundler/setup -rpolyphony -e
|
359
|
+
CMD_TERMINATE_CHILD_FIBER = <<~BASH
|
360
|
+
ruby -rbundler/setup -rpolyphony -e'f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await' 2>&1
|
353
361
|
BASH
|
354
362
|
|
355
|
-
|
356
|
-
ruby -rbundler/setup -rpolyphony -e"
|
363
|
+
CMD_TERMINATE_MAIN_FIBER = <<~BASH
|
364
|
+
ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
|
357
365
|
BASH
|
358
366
|
|
359
367
|
def test_terminate_main_fiber
|
@@ -547,24 +555,38 @@ class FiberTest < MiniTest::Test
|
|
547
555
|
assert f.location =~ location
|
548
556
|
end
|
549
557
|
|
550
|
-
def
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
558
|
+
def test_monitor
|
559
|
+
child = nil
|
560
|
+
parent = spin do
|
561
|
+
child = spin { receive }
|
562
|
+
child.await
|
555
563
|
end
|
556
|
-
f.when_done { values << 42 }
|
557
564
|
|
558
565
|
snooze
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
566
|
+
child.monitor
|
567
|
+
spin { child << :foo }
|
568
|
+
|
569
|
+
msg = receive
|
570
|
+
assert_equal [child, :foo], msg
|
571
|
+
end
|
564
572
|
|
573
|
+
def test_unmonitor
|
574
|
+
child = nil
|
575
|
+
parent = spin(:parent) do
|
576
|
+
child = spin(:child) { receive }
|
577
|
+
child.await
|
578
|
+
end
|
579
|
+
|
580
|
+
snooze
|
581
|
+
child.monitor
|
582
|
+
spin { child << :foo }
|
565
583
|
snooze
|
566
|
-
|
567
|
-
|
584
|
+
|
585
|
+
child.unmonitor
|
586
|
+
|
587
|
+
Fiber.current << :bar
|
588
|
+
msg = receive
|
589
|
+
assert_equal :bar, msg
|
568
590
|
end
|
569
591
|
|
570
592
|
def test_children
|
@@ -732,6 +754,72 @@ class FiberTest < MiniTest::Test
|
|
732
754
|
assert_equal ['bar'], buffer
|
733
755
|
snooze
|
734
756
|
end
|
757
|
+
|
758
|
+
def test_detach
|
759
|
+
buf = []
|
760
|
+
child = nil
|
761
|
+
parent = spin(:parent) do
|
762
|
+
buf << :hi_from_parent
|
763
|
+
child = spin(:child) do
|
764
|
+
buf << :hi_from_child
|
765
|
+
# wait for message (from main fiber)
|
766
|
+
buf << receive
|
767
|
+
end
|
768
|
+
snooze
|
769
|
+
buf << :bye_from_parent
|
770
|
+
end
|
771
|
+
|
772
|
+
snooze
|
773
|
+
assert_equal parent, child.parent
|
774
|
+
child.detach
|
775
|
+
assert_equal Fiber.current, child.parent
|
776
|
+
parent.await
|
777
|
+
|
778
|
+
child << :bye
|
779
|
+
child.await
|
780
|
+
|
781
|
+
assert_equal [
|
782
|
+
:hi_from_parent,
|
783
|
+
:hi_from_child,
|
784
|
+
:bye_from_parent,
|
785
|
+
:bye
|
786
|
+
], buf
|
787
|
+
end
|
788
|
+
|
789
|
+
def test_attach
|
790
|
+
buf = []
|
791
|
+
child = nil
|
792
|
+
parent = spin(:parent) do
|
793
|
+
buf << :hi_from_parent
|
794
|
+
child = spin(:child) do
|
795
|
+
buf << :hi_from_child
|
796
|
+
# wait for message (from main fiber)
|
797
|
+
buf << receive
|
798
|
+
end
|
799
|
+
snooze
|
800
|
+
buf << :bye_from_parent
|
801
|
+
end
|
802
|
+
|
803
|
+
new_parent = spin(:new_parent) { buf << receive }
|
804
|
+
|
805
|
+
snooze
|
806
|
+
assert_equal parent, child.parent
|
807
|
+
child.attach(new_parent)
|
808
|
+
assert_equal new_parent, child.parent
|
809
|
+
parent.await
|
810
|
+
|
811
|
+
child << :bye
|
812
|
+
new_parent << :bye_new_parent
|
813
|
+
snooze
|
814
|
+
|
815
|
+
assert_equal [
|
816
|
+
:hi_from_parent,
|
817
|
+
:hi_from_child,
|
818
|
+
:bye_from_parent,
|
819
|
+
:bye,
|
820
|
+
:bye_new_parent
|
821
|
+
], buf
|
822
|
+
end
|
735
823
|
end
|
736
824
|
|
737
825
|
class MailboxTest < MiniTest::Test
|
@@ -964,7 +1052,7 @@ class FiberControlTest < MiniTest::Test
|
|
964
1052
|
assert_equal 'foo', result.message
|
965
1053
|
assert_equal f1, result.source_fiber
|
966
1054
|
assert_equal :dead, f1.state
|
967
|
-
assert_equal :
|
1055
|
+
assert_equal :waiting, f2.state
|
968
1056
|
end
|
969
1057
|
|
970
1058
|
def test_select_with_interruption
|
data/test/test_global_api.rb
CHANGED
data/test/test_io.rb
CHANGED
@@ -416,4 +416,33 @@ class IOClassMethodsTest < MiniTest::Test
|
|
416
416
|
assert_equal "foo\nbar\n", pipe_read { |f| f.puts 'foo', 'bar' }
|
417
417
|
assert_equal "foo\nbar\n", pipe_read { |f| f.puts 'foo', "bar\n" }
|
418
418
|
end
|
419
|
+
|
420
|
+
def test_read_loop
|
421
|
+
i, o = IO.pipe
|
422
|
+
|
423
|
+
buf = []
|
424
|
+
f = spin do
|
425
|
+
buf << :ready
|
426
|
+
i.read_loop { |d| buf << d }
|
427
|
+
buf << :done
|
428
|
+
end
|
429
|
+
|
430
|
+
# writing always causes snoozing
|
431
|
+
o << 'foo'
|
432
|
+
o << 'bar'
|
433
|
+
o.close
|
434
|
+
|
435
|
+
f.await
|
436
|
+
assert_equal [:ready, 'foo', 'bar', :done], buf
|
437
|
+
end
|
438
|
+
|
439
|
+
def test_read_loop_with_max_len
|
440
|
+
r, w = IO.pipe
|
441
|
+
|
442
|
+
w << 'foobar'
|
443
|
+
w.close
|
444
|
+
buf = []
|
445
|
+
r.read_loop(3) { |data| buf << data }
|
446
|
+
assert_equal ['foo', 'bar'], buf
|
447
|
+
end
|
419
448
|
end
|
data/test/test_supervise.rb
CHANGED
@@ -2,103 +2,103 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
|
-
class SuperviseTest < MiniTest::Test
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
5
|
+
# class SuperviseTest < MiniTest::Test
|
6
|
+
# def test_supervise
|
7
|
+
# p = spin { supervise }
|
8
|
+
# snooze
|
9
|
+
# f1 = p.spin { receive }
|
10
|
+
# f2 = p.spin { receive }
|
11
|
+
|
12
|
+
# snooze
|
13
|
+
# assert_equal p.state, :waiting
|
14
|
+
# f1 << 'foo'
|
15
|
+
# f1.await
|
16
|
+
# snooze
|
17
|
+
|
18
|
+
# assert_equal :waiting, p.state
|
19
|
+
# assert_equal :waiting, f2.state
|
20
|
+
|
21
|
+
# f2 << 'bar'
|
22
|
+
# f2.await
|
23
|
+
# assert_equal :runnable, p.state
|
24
|
+
|
25
|
+
# 3.times { snooze }
|
26
|
+
# assert_equal :dead, p.state
|
27
|
+
# end
|
28
|
+
|
29
|
+
# def test_supervise_with_restart
|
30
|
+
# watcher = spin { receive }
|
31
|
+
# parent = spin { supervise(restart: true, watcher: watcher) }
|
32
|
+
# snooze
|
33
|
+
|
34
|
+
# buffer = []
|
35
|
+
# f1 = parent.spin do
|
36
|
+
# buffer << 'f1'
|
37
|
+
# end
|
38
|
+
|
39
|
+
# f1.await
|
40
|
+
# assert_equal ['f1'], buffer
|
41
|
+
# watcher.await
|
42
|
+
# assert_equal ['f1', 'f1'], buffer
|
43
|
+
# end
|
44
|
+
|
45
|
+
# def test_supervise_with_restart_on_error
|
46
|
+
# parent = spin { supervise(restart: true) }
|
47
|
+
# snooze
|
48
|
+
|
49
|
+
# buffer = []
|
50
|
+
# f1 = parent.spin do
|
51
|
+
# buffer << 'f1'
|
52
|
+
# buffer << receive
|
53
|
+
# end
|
54
|
+
|
55
|
+
# snooze
|
56
|
+
# assert_equal ['f1'], buffer
|
57
|
+
|
58
|
+
# f1.raise 'foo'
|
59
|
+
|
60
|
+
# 3.times { snooze }
|
61
|
+
|
62
|
+
# assert_equal ['f1', 'f1'], buffer
|
63
|
+
# assert_equal :dead, f1.state
|
64
|
+
|
65
|
+
# # f1 should have been restarted by supervisor
|
66
|
+
# f1 = parent.children.first
|
67
|
+
# assert_kind_of Fiber, f1
|
68
|
+
|
69
|
+
# f1 << 'foo'
|
70
|
+
# f1.await
|
71
|
+
|
72
|
+
# assert_equal ['f1', 'f1', 'foo'], buffer
|
73
|
+
# end
|
74
|
+
|
75
|
+
# def test_supervisor_termination
|
76
|
+
# f = nil
|
77
|
+
# p = spin do
|
78
|
+
# f = spin { sleep 1 }
|
79
|
+
# supervise
|
80
|
+
# end
|
81
|
+
# sleep 0.01
|
82
|
+
|
83
|
+
# p.terminate
|
84
|
+
# p.await
|
85
|
+
|
86
|
+
# assert :dead, f.state
|
87
|
+
# assert :dead, p.state
|
88
|
+
# end
|
89
|
+
|
90
|
+
# def test_supervisor_termination_with_restart
|
91
|
+
# f = nil
|
92
|
+
# p = spin do
|
93
|
+
# f = spin { sleep 1 }
|
94
|
+
# supervise(restart: true)
|
95
|
+
# end
|
96
|
+
# sleep 0.01
|
97
|
+
|
98
|
+
# p.terminate
|
99
|
+
# p.await
|
100
|
+
|
101
|
+
# assert :dead, f.state
|
102
|
+
# assert :dead, p.state
|
103
|
+
# end
|
104
|
+
# end
|