polyphony 0.58 → 0.61

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/Gemfile.lock +15 -29
  4. data/examples/core/message_based_supervision.rb +51 -0
  5. data/examples/io/echo_server.rb +16 -7
  6. data/ext/polyphony/backend_common.c +160 -7
  7. data/ext/polyphony/backend_common.h +34 -2
  8. data/ext/polyphony/backend_io_uring.c +119 -40
  9. data/ext/polyphony/backend_io_uring_context.c +10 -1
  10. data/ext/polyphony/backend_io_uring_context.h +5 -3
  11. data/ext/polyphony/backend_libev.c +109 -31
  12. data/ext/polyphony/extconf.rb +2 -2
  13. data/ext/polyphony/fiber.c +1 -34
  14. data/ext/polyphony/polyphony.c +12 -19
  15. data/ext/polyphony/polyphony.h +9 -20
  16. data/ext/polyphony/polyphony_ext.c +0 -4
  17. data/ext/polyphony/queue.c +12 -12
  18. data/ext/polyphony/runqueue.c +21 -98
  19. data/ext/polyphony/runqueue.h +26 -0
  20. data/ext/polyphony/thread.c +6 -113
  21. data/lib/polyphony/core/timer.rb +2 -2
  22. data/lib/polyphony/extensions/fiber.rb +102 -82
  23. data/lib/polyphony/extensions/io.rb +10 -9
  24. data/lib/polyphony/extensions/openssl.rb +14 -4
  25. data/lib/polyphony/extensions/socket.rb +15 -15
  26. data/lib/polyphony/extensions/thread.rb +1 -1
  27. data/lib/polyphony/version.rb +1 -1
  28. data/polyphony.gemspec +0 -7
  29. data/test/test_backend.rb +46 -9
  30. data/test/test_ext.rb +1 -1
  31. data/test/test_fiber.rb +106 -18
  32. data/test/test_global_api.rb +1 -1
  33. data/test/test_io.rb +29 -0
  34. data/test/test_supervise.rb +100 -100
  35. data/test/test_thread.rb +5 -11
  36. data/test/test_thread_pool.rb +1 -1
  37. data/test/test_trace.rb +28 -49
  38. metadata +5 -109
  39. data/ext/polyphony/tracing.c +0 -11
  40. data/lib/polyphony/adapters/trace.rb +0 -138
@@ -101,7 +101,7 @@ class ::IO
101
101
  return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
102
102
 
103
103
  @read_buffer ||= +''
104
- Polyphony.backend_read(self, @read_buffer, 8192, false)
104
+ Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
105
105
  return @read_buffer.slice!(0) if !@read_buffer.empty?
106
106
 
107
107
  nil
@@ -110,7 +110,7 @@ class ::IO
110
110
  alias_method :orig_read, :read
111
111
  def read(len = nil)
112
112
  @read_buffer ||= +''
113
- result = Polyphony.backend_read(self, @read_buffer, len, true)
113
+ result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
114
114
  return nil unless result
115
115
 
116
116
  already_read = @read_buffer
@@ -119,8 +119,8 @@ class ::IO
119
119
  end
120
120
 
121
121
  alias_method :orig_readpartial, :read
122
- def readpartial(len, str = +'')
123
- result = Polyphony.backend_read(self, str, len, false)
122
+ def readpartial(len, str = +'', buffer_pos = 0)
123
+ result = Polyphony.backend_read(self, str, len, false, buffer_pos)
124
124
  raise EOFError unless result
125
125
 
126
126
  result
@@ -151,9 +151,10 @@ class ::IO
151
151
  idx = @read_buffer.index(sep)
152
152
  return @read_buffer.slice!(0, idx + sep_size) if idx
153
153
 
154
- data = readpartial(8192, +'')
155
- return nil unless data
156
- @read_buffer << data
154
+ result = readpartial(8192, @read_buffer, -1)
155
+
156
+ #Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
157
+ return nil unless result
157
158
  end
158
159
  rescue EOFError
159
160
  return nil
@@ -216,8 +217,8 @@ class ::IO
216
217
  buf ? readpartial(maxlen, buf) : readpartial(maxlen)
217
218
  end
218
219
 
219
- def read_loop(&block)
220
- Polyphony.backend_read_loop(self, &block)
220
+ def read_loop(maxlen = 8192, &block)
221
+ Polyphony.backend_read_loop(self, maxlen, &block)
221
222
  end
222
223
 
223
224
  def feed_loop(receiver, method = :call, &block)
@@ -64,13 +64,23 @@ class ::OpenSSL::SSL::SSLSocket
64
64
  # @sync = osync
65
65
  end
66
66
 
67
- def readpartial(maxlen, buf = +'')
68
- result = sysread(maxlen, buf)
67
+ def readpartial(maxlen, buf = +'', buffer_pos = 0)
68
+ if buffer_pos != 0
69
+ if (result = sysread(maxlen, +''))
70
+ if buffer_pos == -1
71
+ result = buf + result
72
+ else
73
+ result = buf[0...buffer_pos] + result
74
+ end
75
+ end
76
+ else
77
+ result = sysread(maxlen, buf)
78
+ end
69
79
  result || (raise EOFError)
70
80
  end
71
81
 
72
- def read_loop
73
- while (data = sysread(8192))
82
+ def read_loop(maxlen = 8192)
83
+ while (data = sysread(maxlen))
74
84
  yield data
75
85
  end
76
86
  end
@@ -23,11 +23,11 @@ class ::Socket
23
23
  end
24
24
 
25
25
  def recv(maxlen, flags = 0, outbuf = nil)
26
- Polyphony.backend_recv(self, outbuf || +'', maxlen)
26
+ Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
27
27
  end
28
28
 
29
- def recv_loop(&block)
30
- Polyphony.backend_recv_loop(self, &block)
29
+ def recv_loop(maxlen = 8192, &block)
30
+ Polyphony.backend_recv_loop(self, maxlen, &block)
31
31
  end
32
32
  alias_method :read_loop, :recv_loop
33
33
 
@@ -60,8 +60,8 @@ class ::Socket
60
60
  # Polyphony.backend_send(self, mesg, 0)
61
61
  # end
62
62
 
63
- def readpartial(maxlen, str = +'')
64
- Polyphony.backend_recv(self, str, maxlen)
63
+ def readpartial(maxlen, str = +'', buffer_pos = 0)
64
+ Polyphony.backend_recv(self, str, maxlen, buffer_pos)
65
65
  end
66
66
 
67
67
  ZERO_LINGER = [0, 0].pack('ii').freeze
@@ -141,11 +141,11 @@ class ::TCPSocket
141
141
  end
142
142
 
143
143
  def recv(maxlen, flags = 0, outbuf = nil)
144
- Polyphony.backend_recv(self, outbuf || +'', maxlen)
144
+ Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
145
145
  end
146
146
 
147
- def recv_loop(&block)
148
- Polyphony.backend_recv_loop(self, &block)
147
+ def recv_loop(maxlen = 8192, &block)
148
+ Polyphony.backend_recv_loop(self, maxlen, &block)
149
149
  end
150
150
  alias_method :read_loop, :recv_loop
151
151
 
@@ -165,8 +165,8 @@ class ::TCPSocket
165
165
  # Polyphony.backend_send(self, mesg, 0)
166
166
  # end
167
167
 
168
- def readpartial(maxlen, str = +'')
169
- result = Polyphony.backend_recv(self, str, maxlen)
168
+ def readpartial(maxlen, str = +'', buffer_pos = 0)
169
+ result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
170
170
  raise EOFError unless result
171
171
 
172
172
  str
@@ -218,11 +218,11 @@ end
218
218
 
219
219
  class ::UNIXSocket
220
220
  def recv(maxlen, flags = 0, outbuf = nil)
221
- Polyphony.backend_recv(self, outbuf || +'', maxlen)
221
+ Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
222
222
  end
223
223
 
224
- def recv_loop(&block)
225
- Polyphony.backend_recv_loop(self, &block)
224
+ def recv_loop(maxlen = 8192, &block)
225
+ Polyphony.backend_recv_loop(self, maxlen, &block)
226
226
  end
227
227
  alias_method :read_loop, :recv_loop
228
228
 
@@ -242,8 +242,8 @@ class ::UNIXSocket
242
242
  Polyphony.backend_send(self, mesg, 0)
243
243
  end
244
244
 
245
- def readpartial(maxlen, str = +'')
246
- result = Polyphony.backend_recv(self, str, maxlen)
245
+ def readpartial(maxlen, str = +'', buffer_pos = 0)
246
+ result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
247
247
  raise EOFError unless result
248
248
 
249
249
  str
@@ -111,6 +111,6 @@ class ::Thread
111
111
  end
112
112
 
113
113
  def on_idle(&block)
114
- backend.idle_block = block
114
+ backend.idle_proc = block
115
115
  end
116
116
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.58'
4
+ VERSION = '0.61'
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
@@ -26,14 +26,14 @@ class BackendTest < MiniTest::Test
26
26
  @backend.sleep 0.01
27
27
  count += 1
28
28
  }.await
29
- assert_in_delta 0.03, Time.now - t0, 0.01
29
+ assert_in_range 0.02..0.04, Time.now - t0
30
30
  assert_equal 3, count
31
31
  end
32
32
 
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
@@ -351,10 +388,10 @@ class BackendTest < MiniTest::Test
351
388
  GC.enable
352
389
  end
353
390
 
354
- def test_idle_block
391
+ def test_idle_proc
355
392
  counter = 0
356
393
 
357
- @backend.idle_block = proc { counter += 1 }
394
+ @backend.idle_proc = proc { counter += 1 }
358
395
 
359
396
  3.times { snooze }
360
397
  assert_equal 0, counter
@@ -368,7 +405,7 @@ class BackendTest < MiniTest::Test
368
405
  3.times { snooze }
369
406
  assert_equal 2, counter
370
407
 
371
- @backend.idle_block = nil
408
+ @backend.idle_proc = nil
372
409
  sleep 0.01
373
410
  assert_equal 2, counter
374
411
  end
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