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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Gemfile.lock +15 -29
  4. data/examples/core/message_based_supervision.rb +51 -0
  5. data/ext/polyphony/backend_common.c +108 -3
  6. data/ext/polyphony/backend_common.h +23 -0
  7. data/ext/polyphony/backend_io_uring.c +117 -39
  8. data/ext/polyphony/backend_io_uring_context.c +11 -3
  9. data/ext/polyphony/backend_io_uring_context.h +5 -3
  10. data/ext/polyphony/backend_libev.c +92 -30
  11. data/ext/polyphony/extconf.rb +2 -2
  12. data/ext/polyphony/fiber.c +1 -34
  13. data/ext/polyphony/polyphony.c +12 -19
  14. data/ext/polyphony/polyphony.h +10 -20
  15. data/ext/polyphony/polyphony_ext.c +0 -4
  16. data/ext/polyphony/queue.c +12 -12
  17. data/ext/polyphony/runqueue.c +17 -85
  18. data/ext/polyphony/runqueue.h +27 -0
  19. data/ext/polyphony/thread.c +10 -99
  20. data/lib/polyphony/core/timer.rb +2 -2
  21. data/lib/polyphony/extensions/fiber.rb +102 -82
  22. data/lib/polyphony/extensions/io.rb +10 -9
  23. data/lib/polyphony/extensions/openssl.rb +14 -4
  24. data/lib/polyphony/extensions/socket.rb +15 -15
  25. data/lib/polyphony/extensions/thread.rb +8 -0
  26. data/lib/polyphony/version.rb +1 -1
  27. data/polyphony.gemspec +0 -7
  28. data/test/test_backend.rb +71 -5
  29. data/test/test_ext.rb +1 -1
  30. data/test/test_fiber.rb +106 -18
  31. data/test/test_global_api.rb +1 -1
  32. data/test/test_io.rb +29 -0
  33. data/test/test_supervise.rb +100 -100
  34. data/test/test_thread.rb +57 -11
  35. data/test/test_thread_pool.rb +1 -1
  36. data/test/test_trace.rb +28 -49
  37. metadata +4 -108
  38. data/ext/polyphony/tracing.c +0 -11
  39. data/lib/polyphony/adapters/trace.rb +0 -138
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.57.0'
4
+ VERSION = '0.60'
5
5
  end
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
@@ -42,7 +42,7 @@ class ExceptionTest < MiniTest::Test
42
42
  end
43
43
 
44
44
  class ProcessTest < MiniTest::Test
45
- def test_detach
45
+ def test_process_detach
46
46
  pid = Polyphony.fork { sleep 0.05; exit! 42 }
47
47
  buffer = []
48
48
  spin { 3.times { |i| buffer << i; snooze } }
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
- CMD_TERMINATE_MAIN_FIBER = <<~BASH
352
- ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
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
- CMD_TERMINATE_CHILD_FIBER = <<~BASH
356
- ruby -rbundler/setup -rpolyphony -e"f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await" 2>&1
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 test_when_done
551
- flag = nil
552
- values = []
553
- f = spin do
554
- snooze until flag
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
- assert values.empty?
560
- snooze
561
- flag = true
562
- assert values.empty?
563
- assert f.alive?
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
- assert_equal [42], values
567
- assert !f.running?
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 :dead, f2.state
1055
+ assert_equal :waiting, f2.state
968
1056
  end
969
1057
 
970
1058
  def test_select_with_interruption
@@ -372,7 +372,7 @@ class SpinScopeTest < MiniTest::Test
372
372
  rescue => e
373
373
  buffer << e.message
374
374
  end
375
- 6.times { snooze }
375
+ 10.times { snooze }
376
376
  assert_equal 0, Fiber.current.children.size
377
377
  assert_equal ['foobar'], buffer
378
378
  end
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
@@ -2,103 +2,103 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
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
- snooze
25
-
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
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