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