polyphony 0.43.9 → 0.45.1

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -1
  3. data/CHANGELOG.md +40 -0
  4. data/Gemfile.lock +16 -6
  5. data/Rakefile +1 -1
  6. data/TODO.md +14 -13
  7. data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
  8. data/docs/api-reference/thread.md +1 -1
  9. data/docs/getting-started/overview.md +14 -14
  10. data/docs/getting-started/tutorial.md +1 -1
  11. data/examples/adapters/redis_client.rb +3 -1
  12. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  13. data/examples/adapters/sequel_mysql.rb +23 -0
  14. data/examples/adapters/sequel_mysql_pool.rb +33 -0
  15. data/examples/adapters/sequel_pg.rb +24 -0
  16. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  17. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  18. data/examples/core/deferring-an-operation.rb +16 -0
  19. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  20. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  21. data/examples/core/handling-signals.rb +11 -0
  22. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  23. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  24. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  25. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  26. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  27. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  28. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  29. data/examples/core/supervisor.rb +20 -0
  30. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  31. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  32. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  33. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  34. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  35. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  36. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  37. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  38. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  39. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  40. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  41. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  42. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  43. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  44. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  45. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  46. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  47. data/examples/io/{xx-open.rb → open.rb} +0 -0
  48. data/examples/io/pry.rb +18 -0
  49. data/examples/io/rack_server.rb +71 -0
  50. data/examples/io/{xx-system.rb → system.rb} +1 -1
  51. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  52. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  53. data/examples/io/tunnel.rb +6 -1
  54. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  55. data/examples/performance/fiber_transfer.rb +2 -1
  56. data/examples/performance/fs_read.rb +5 -6
  57. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  58. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  59. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  60. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  61. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  62. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
  63. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  64. data/examples/performance/thread_pool_perf.rb +6 -7
  65. data/ext/polyphony/backend.h +40 -0
  66. data/ext/polyphony/event.c +3 -3
  67. data/ext/polyphony/extconf.rb +1 -1
  68. data/ext/polyphony/{libev_agent.c → libev_backend.c} +272 -265
  69. data/ext/polyphony/polyphony.c +4 -2
  70. data/ext/polyphony/polyphony.h +15 -28
  71. data/ext/polyphony/polyphony_ext.c +3 -4
  72. data/ext/polyphony/queue.c +32 -12
  73. data/ext/polyphony/ring_buffer.c +0 -1
  74. data/ext/polyphony/thread.c +58 -44
  75. data/lib/polyphony.rb +25 -38
  76. data/lib/polyphony/adapters/fs.rb +1 -1
  77. data/lib/polyphony/adapters/irb.rb +2 -17
  78. data/lib/polyphony/adapters/mysql2.rb +19 -0
  79. data/lib/polyphony/adapters/postgres.rb +5 -5
  80. data/lib/polyphony/adapters/process.rb +2 -2
  81. data/lib/polyphony/adapters/readline.rb +17 -0
  82. data/lib/polyphony/adapters/redis.rb +1 -1
  83. data/lib/polyphony/adapters/sequel.rb +45 -0
  84. data/lib/polyphony/core/exceptions.rb +11 -0
  85. data/lib/polyphony/core/global_api.rb +15 -10
  86. data/lib/polyphony/core/resource_pool.rb +20 -7
  87. data/lib/polyphony/core/sync.rb +46 -8
  88. data/lib/polyphony/core/throttler.rb +1 -1
  89. data/lib/polyphony/extensions/core.rb +38 -25
  90. data/lib/polyphony/extensions/fiber.rb +5 -1
  91. data/lib/polyphony/extensions/io.rb +45 -12
  92. data/lib/polyphony/extensions/openssl.rb +6 -6
  93. data/lib/polyphony/extensions/socket.rb +22 -23
  94. data/lib/polyphony/extensions/thread.rb +6 -5
  95. data/lib/polyphony/net.rb +2 -1
  96. data/lib/polyphony/version.rb +1 -1
  97. data/polyphony.gemspec +7 -3
  98. data/test/helper.rb +1 -1
  99. data/test/{test_agent.rb → test_backend.rb} +22 -22
  100. data/test/test_fiber.rb +21 -5
  101. data/test/test_io.rb +17 -1
  102. data/test/test_kernel.rb +5 -0
  103. data/test/test_resource_pool.rb +50 -16
  104. data/test/test_signal.rb +5 -29
  105. data/test/test_socket.rb +17 -0
  106. data/test/test_sync.rb +52 -0
  107. data/test/test_throttler.rb +1 -0
  108. metadata +125 -96
  109. data/.gitbook.yaml +0 -4
  110. data/examples/adapters/concurrent-ruby.rb +0 -9
  111. data/examples/core/04-handling-signals.rb +0 -19
  112. data/examples/core/xx-agent.rb +0 -102
  113. data/examples/core/xx-at_exit.rb +0 -29
  114. data/examples/core/xx-caller.rb +0 -12
  115. data/examples/core/xx-daemon.rb +0 -14
  116. data/examples/core/xx-deadlock.rb +0 -8
  117. data/examples/core/xx-deferring-an-operation.rb +0 -14
  118. data/examples/core/xx-exception-backtrace.rb +0 -40
  119. data/examples/core/xx-fork-cleanup.rb +0 -22
  120. data/examples/core/xx-fork-spin.rb +0 -42
  121. data/examples/core/xx-fork-terminate.rb +0 -27
  122. data/examples/core/xx-move_on.rb +0 -23
  123. data/examples/core/xx-queue-async.rb +0 -120
  124. data/examples/core/xx-readpartial.rb +0 -18
  125. data/examples/core/xx-signals.rb +0 -16
  126. data/examples/core/xx-sleep-forever.rb +0 -9
  127. data/examples/core/xx-sleeping.rb +0 -25
  128. data/examples/core/xx-snooze-starve.rb +0 -16
  129. data/examples/core/xx-spin-fork.rb +0 -49
  130. data/examples/core/xx-state-machine.rb +0 -51
  131. data/examples/core/xx-stop.rb +0 -20
  132. data/examples/core/xx-supervisors.rb +0 -21
  133. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  134. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  135. data/examples/core/xx-thread-snooze.rb +0 -34
  136. data/examples/core/xx-timer-gc.rb +0 -17
  137. data/examples/core/xx-trace.rb +0 -79
  138. data/examples/performance/xx-array.rb +0 -11
  139. data/examples/performance/xx-fiber-switch.rb +0 -9
  140. data/examples/performance/xx-snooze.rb +0 -15
  141. data/examples/xx-spin.rb +0 -32
@@ -67,6 +67,10 @@ module Polyphony
67
67
  else RuntimeError.new
68
68
  end
69
69
  end
70
+
71
+ def interject(&block)
72
+ raise Polyphony::Interjection.new(block)
73
+ end
70
74
  end
71
75
 
72
76
  # Fiber supervision
@@ -224,7 +228,7 @@ module Polyphony
224
228
  @results = @children.dup
225
229
  @on_child_done = proc do |c, r|
226
230
  @results[c] = r
227
- self.schedule if @children.empty?
231
+ schedule if @children.empty?
228
232
  end
229
233
  suspend
230
234
  @on_child_done = nil
@@ -99,7 +99,7 @@ class ::IO
99
99
  alias_method :orig_read, :read
100
100
  def read(len = nil)
101
101
  @read_buffer ||= +''
102
- result = Thread.current.agent.read(self, @read_buffer, len, true)
102
+ result = Thread.current.backend.read(self, @read_buffer, len, true)
103
103
  return nil unless result
104
104
 
105
105
  already_read = @read_buffer
@@ -110,7 +110,7 @@ class ::IO
110
110
  alias_method :orig_readpartial, :read
111
111
  def readpartial(len, str = nil)
112
112
  @read_buffer ||= +''
113
- result = Thread.current.agent.read(self, @read_buffer, len, false)
113
+ result = Thread.current.backend.read(self, @read_buffer, len, false)
114
114
  raise EOFError unless result
115
115
 
116
116
  if str
@@ -124,12 +124,12 @@ class ::IO
124
124
 
125
125
  alias_method :orig_write, :write
126
126
  def write(str, *args)
127
- Thread.current.agent.write(self, str, *args)
127
+ Thread.current.backend.write(self, str, *args)
128
128
  end
129
129
 
130
130
  alias_method :orig_write_chevron, :<<
131
131
  def <<(str)
132
- Thread.current.agent.write(self, str)
132
+ Thread.current.backend.write(self, str)
133
133
  self
134
134
  end
135
135
 
@@ -163,20 +163,29 @@ class ::IO
163
163
  # def putc(obj)
164
164
  # end
165
165
 
166
+ LINEFEED = "\n"
167
+ LINEFEED_RE = /\n$/.freeze
168
+
166
169
  alias_method :orig_puts, :puts
167
170
  def puts(*args)
168
171
  if args.empty?
169
- write "\n"
172
+ write LINEFEED
170
173
  return
171
174
  end
172
175
 
173
- strs = args.inject([]) do |m, a|
174
- a = a.to_s
175
- m << a
176
- m << "\n" unless a =~ /\n$/
177
- m
176
+ idx = 0
177
+ while idx < args.size
178
+ arg = args[idx]
179
+ args[idx] = arg = arg.to_s unless arg.is_a?(String)
180
+ if arg =~ LINEFEED_RE
181
+ idx += 1
182
+ else
183
+ args.insert(idx + 1, LINEFEED)
184
+ idx += 2
185
+ end
178
186
  end
179
- write *strs
187
+
188
+ write(*args)
180
189
  nil
181
190
  end
182
191
 
@@ -203,7 +212,7 @@ class ::IO
203
212
  end
204
213
 
205
214
  def read_loop(&block)
206
- Thread.current.agent.read_loop(self, &block)
215
+ Thread.current.backend.read_loop(self, &block)
207
216
  end
208
217
 
209
218
  # alias_method :orig_read, :read
@@ -218,4 +227,28 @@ class ::IO
218
227
  # end
219
228
  # outbuf
220
229
  # end
230
+
231
+ def wait_readable(timeout = nil)
232
+ if timeout
233
+ move_on_after(timeout) do
234
+ Thread.current.backend.wait_io(self, false)
235
+ self
236
+ end
237
+ else
238
+ Thread.current.backend.wait_io(self, false)
239
+ self
240
+ end
241
+ end
242
+
243
+ def wait_writable(timeout = nil)
244
+ if timeout
245
+ move_on_after(timeout) do
246
+ Thread.current.backend.wait_io(self, true)
247
+ self
248
+ end
249
+ else
250
+ Thread.current.backend.wait_io(self, true)
251
+ self
252
+ end
253
+ end
221
254
  end
@@ -28,8 +28,8 @@ class ::OpenSSL::SSL::SSLSocket
28
28
  loop do
29
29
  result = accept_nonblock(exception: false)
30
30
  case result
31
- when :wait_readable then Thread.current.agent.wait_io(io, false)
32
- when :wait_writable then Thread.current.agent.wait_io(io, true)
31
+ when :wait_readable then Thread.current.backend.wait_io(io, false)
32
+ when :wait_writable then Thread.current.backend.wait_io(io, true)
33
33
  else
34
34
  return result
35
35
  end
@@ -40,8 +40,8 @@ class ::OpenSSL::SSL::SSLSocket
40
40
  def sysread(maxlen, buf = +'')
41
41
  loop do
42
42
  case (result = read_nonblock(maxlen, buf, exception: false))
43
- when :wait_readable then Thread.current.agent.wait_io(io, false)
44
- when :wait_writable then Thread.current.agent.wait_io(io, true)
43
+ when :wait_readable then Thread.current.backend.wait_io(io, false)
44
+ when :wait_writable then Thread.current.backend.wait_io(io, true)
45
45
  else return result
46
46
  end
47
47
  end
@@ -51,8 +51,8 @@ class ::OpenSSL::SSL::SSLSocket
51
51
  def syswrite(buf)
52
52
  loop do
53
53
  case (result = write_nonblock(buf, exception: false))
54
- when :wait_readable then Thread.current.agent.wait_io(io, false)
55
- when :wait_writable then Thread.current.agent.wait_io(io, true)
54
+ when :wait_readable then Thread.current.backend.wait_io(io, false)
55
+ when :wait_writable then Thread.current.backend.wait_io(io, true)
56
56
  else
57
57
  return result
58
58
  end
@@ -5,34 +5,17 @@ require 'socket'
5
5
  require_relative './io'
6
6
  require_relative '../core/thread_pool'
7
7
 
8
- class ::BasicSocket
9
- def write_nonblock(string, _options = {})
10
- write(string)
11
- end
12
-
13
- def read_nonblock(maxlen, str = nil, _options = {})
14
- readpartial(maxlen, str)
15
- end
16
- end
17
-
18
8
  # Socket overrides (eventually rewritten in C)
19
9
  class ::Socket
20
10
  def accept
21
- Thread.current.agent.accept(self)
11
+ Thread.current.backend.accept(self)
22
12
  end
23
13
 
24
14
  NO_EXCEPTION = { exception: false }.freeze
25
15
 
26
- def connect(remotesockaddr)
27
- loop do
28
- result = connect_nonblock(remotesockaddr, **NO_EXCEPTION)
29
- case result
30
- when 0 then return
31
- when :wait_writable then Thread.current.agent.wait_io(self, true)
32
- else
33
- raise IOError
34
- end
35
- end
16
+ def connect(addr)
17
+ addr = Addrinfo.new(addr) if addr.is_a?(String)
18
+ Thread.current.backend.connect(self, addr.ip_address, addr.ip_port)
36
19
  end
37
20
 
38
21
  def recv(maxlen, flags = 0, outbuf = nil)
@@ -41,7 +24,7 @@ class ::Socket
41
24
  result = recv_nonblock(maxlen, flags, outbuf, **NO_EXCEPTION)
42
25
  case result
43
26
  when nil then raise IOError
44
- when :wait_readable then Thread.current.agent.wait_io(self, false)
27
+ when :wait_readable then Thread.current.backend.wait_io(self, false)
45
28
  else
46
29
  return result
47
30
  end
@@ -54,7 +37,7 @@ class ::Socket
54
37
  result = recvfrom_nonblock(maxlen, flags, @read_buffer, **NO_EXCEPTION)
55
38
  case result
56
39
  when nil then raise IOError
57
- when :wait_readable then Thread.current.agent.wait_io(self, false)
40
+ when :wait_readable then Thread.current.backend.wait_io(self, false)
58
41
  else
59
42
  return result
60
43
  end
@@ -75,6 +58,10 @@ class ::Socket
75
58
  setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
76
59
  end
77
60
 
61
+ def reuse_port
62
+ setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
63
+ end
64
+
78
65
  class << self
79
66
  alias_method :orig_getaddrinfo, :getaddrinfo
80
67
  def getaddrinfo(*args)
@@ -128,6 +115,18 @@ class ::TCPSocket
128
115
  def reuse_addr
129
116
  setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
130
117
  end
118
+
119
+ def reuse_port
120
+ setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
121
+ end
122
+
123
+ def read_nonblock(len, str = nil, exception: true)
124
+ @io.read_nonblock(len, str, exception: exception)
125
+ end
126
+
127
+ def write_nonblock(buf, exception: true)
128
+ @io.write_nonblock(buf, exception: exception)
129
+ end
131
130
  end
132
131
 
133
132
  # Override stock TCPServer code by encapsulating a Socket instance.
@@ -16,21 +16,22 @@ class ::Thread
16
16
  end
17
17
 
18
18
  def execute
19
- # agent must be created in the context of the new thread, therefore it
19
+ # backend must be created in the context of the new thread, therefore it
20
20
  # cannot be created in Thread#initialize
21
- @agent = Polyphony::LibevAgent.new
21
+ @backend = Polyphony::Backend.new
22
22
  setup
23
23
  @ready = true
24
24
  result = @block.(*@args)
25
25
  rescue Polyphony::MoveOn, Polyphony::Terminate => e
26
26
  result = e.value
27
- rescue Exception => result
27
+ rescue Exception => e
28
+ result = e
28
29
  ensure
29
30
  @ready = true
30
31
  finalize(result)
31
32
  end
32
33
 
33
- attr_accessor :agent
34
+ attr_accessor :backend
34
35
 
35
36
  def setup
36
37
  @main_fiber = Fiber.current
@@ -48,7 +49,7 @@ class ::Thread
48
49
  @result = result
49
50
  signal_waiters(result)
50
51
  end
51
- @agent.finalize
52
+ @backend.finalize
52
53
  end
53
54
 
54
55
  def signal_waiters(result)
@@ -35,9 +35,10 @@ module Polyphony
35
35
  ::Socket.new(:INET, :STREAM).tap do |s|
36
36
  s.reuse_addr if opts[:reuse_addr]
37
37
  s.dont_linger if opts[:dont_linger]
38
+ s.reuse_port if opts[:reuse_port]
38
39
  addr = ::Socket.sockaddr_in(port, host)
39
40
  s.bind(addr)
40
- s.listen(0)
41
+ s.listen(opts[:backlog] || Socket::SOMAXCONN)
41
42
  end
42
43
  end
43
44
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.43.9'
4
+ VERSION = '0.45.1'
5
5
  end
@@ -21,17 +21,21 @@ Gem::Specification.new do |s|
21
21
  s.require_paths = ["lib"]
22
22
  s.required_ruby_version = '>= 2.6'
23
23
 
24
- s.add_development_dependency 'httparty', '0.17.0'
25
- s.add_development_dependency 'localhost', '1.1.4'
24
+ s.add_development_dependency 'rake-compiler', '1.0.5'
26
25
  s.add_development_dependency 'minitest', '5.13.0'
27
26
  s.add_development_dependency 'minitest-reporters', '1.4.2'
28
27
  s.add_development_dependency 'simplecov', '0.17.1'
29
28
  s.add_development_dependency 'rubocop', '0.85.1'
29
+ s.add_development_dependency 'pry', '0.13.1'
30
+
30
31
  s.add_development_dependency 'pg', '1.1.4'
31
- s.add_development_dependency 'rake-compiler', '1.0.5'
32
32
  s.add_development_dependency 'redis', '4.1.0'
33
33
  s.add_development_dependency 'hiredis', '0.6.3'
34
34
  s.add_development_dependency 'http_parser.rb', '~>0.6.0'
35
+ s.add_development_dependency 'rack', '>=2.0.8', '<2.3.0'
36
+ s.add_development_dependency 'mysql2', '0.5.3'
37
+ s.add_development_dependency 'sequel', '5.34.0'
38
+ s.add_development_dependency 'httparty', '0.17.1'
35
39
 
36
40
  s.add_development_dependency 'jekyll', '~>3.8.6'
37
41
  s.add_development_dependency 'jekyll-remote-theme', '~>0.4.1'
@@ -31,7 +31,7 @@ class MiniTest::Test
31
31
  end
32
32
  Fiber.current.setup_main_fiber
33
33
  Fiber.current.instance_variable_set(:@auto_watcher, nil)
34
- Thread.current.agent = Polyphony::LibevAgent.new
34
+ Thread.current.backend = Polyphony::Backend.new
35
35
  sleep 0 # apparently this helps with timer accuracy
36
36
  end
37
37
 
@@ -2,39 +2,39 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class AgentTest < MiniTest::Test
5
+ class BackendTest < MiniTest::Test
6
6
  def setup
7
7
  super
8
- @prev_agent = Thread.current.agent
9
- @agent = Polyphony::LibevAgent.new
10
- Thread.current.agent = @agent
8
+ @prev_backend = Thread.current.backend
9
+ @backend = Polyphony::Backend.new
10
+ Thread.current.backend = @backend
11
11
  end
12
12
 
13
13
  def teardown
14
- @agent.finalize
15
- Thread.current.agent = @prev_agent
14
+ @backend.finalize
15
+ Thread.current.backend = @prev_backend
16
16
  end
17
17
 
18
18
  def test_sleep
19
19
  count = 0
20
20
  t0 = Time.now
21
21
  spin {
22
- @agent.sleep 0.01
22
+ @backend.sleep 0.01
23
23
  count += 1
24
- @agent.sleep 0.01
24
+ @backend.sleep 0.01
25
25
  count += 1
26
- @agent.sleep 0.01
26
+ @backend.sleep 0.01
27
27
  count += 1
28
28
  }.await
29
- assert Time.now - t0 >= 0.03
29
+ assert_in_delta 0.03, Time.now - t0, 0.005
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 { @agent.read(i, buf, 5, false) }
37
- @agent.write(o, 'Hello world')
36
+ f = spin { @backend.read(i, buf, 5, false) }
37
+ @backend.write(o, 'Hello world')
38
38
  return_value = f.await
39
39
 
40
40
  assert_equal 'Hello', buf
@@ -44,10 +44,10 @@ class AgentTest < MiniTest::Test
44
44
  def test_write_read_to_eof_limited_buffer
45
45
  i, o = IO.pipe
46
46
  buf = +''
47
- f = spin { @agent.read(i, buf, 5, true) }
48
- @agent.write(o, 'Hello')
47
+ f = spin { @backend.read(i, buf, 5, true) }
48
+ @backend.write(o, 'Hello')
49
49
  snooze
50
- @agent.write(o, ' world')
50
+ @backend.write(o, ' world')
51
51
  snooze
52
52
  o.close
53
53
  return_value = f.await
@@ -59,10 +59,10 @@ class AgentTest < MiniTest::Test
59
59
  def test_write_read_to_eof
60
60
  i, o = IO.pipe
61
61
  buf = +''
62
- f = spin { @agent.read(i, buf, 10**6, true) }
63
- @agent.write(o, 'Hello')
62
+ f = spin { @backend.read(i, buf, 10**6, true) }
63
+ @backend.write(o, 'Hello')
64
64
  snooze
65
- @agent.write(o, ' world')
65
+ @backend.write(o, ' world')
66
66
  snooze
67
67
  o.close
68
68
  return_value = f.await
@@ -73,11 +73,11 @@ class AgentTest < MiniTest::Test
73
73
 
74
74
  def test_waitpid
75
75
  pid = fork do
76
- @agent.post_fork
76
+ @backend.post_fork
77
77
  exit(42)
78
78
  end
79
79
 
80
- result = @agent.waitpid(pid)
80
+ result = @backend.waitpid(pid)
81
81
  assert_equal [pid, 42], result
82
82
  end
83
83
 
@@ -87,7 +87,7 @@ class AgentTest < MiniTest::Test
87
87
  buf = []
88
88
  spin do
89
89
  buf << :ready
90
- @agent.read_loop(i) { |d| buf << d }
90
+ @backend.read_loop(i) { |d| buf << d }
91
91
  buf << :done
92
92
  end
93
93
 
@@ -107,7 +107,7 @@ class AgentTest < MiniTest::Test
107
107
 
108
108
  clients = []
109
109
  server_fiber = spin do
110
- @agent.accept_loop(server) { |c| clients << c }
110
+ @backend.accept_loop(server) { |c| clients << c }
111
111
  end
112
112
 
113
113
  c1 = TCPSocket.new('127.0.0.1', 1234)
@@ -352,7 +352,7 @@ class FiberTest < MiniTest::Test
352
352
  result = []
353
353
  f = Fiber.current.spin do
354
354
  result << :start
355
- result << Thread.current.agent.sleep(1)
355
+ result << Thread.current.backend.sleep(1)
356
356
  end
357
357
  snooze
358
358
  f.interrupt
@@ -413,6 +413,22 @@ class FiberTest < MiniTest::Test
413
413
  f2&.stop
414
414
  end
415
415
 
416
+ def test_interject
417
+ buf = []
418
+ f = spin_loop { sleep }
419
+ snooze
420
+ f.interject { buf << Fiber.current }
421
+ snooze
422
+ assert_equal [f], buf
423
+ assert_equal :waiting, f.state
424
+
425
+ f.interject { buf << :foo; raise Polyphony::MoveOn }
426
+ snooze
427
+
428
+ assert_equal [f, :foo], buf
429
+ assert_equal :dead, f.state
430
+ end
431
+
416
432
  def test_state
417
433
  counter = 0
418
434
  f = spin do
@@ -625,7 +641,7 @@ class FiberTest < MiniTest::Test
625
641
  end
626
642
  end
627
643
  sleep 0.1
628
- f = spin { Thread.current.agent.waitpid(pid) }
644
+ f = spin { Thread.current.backend.waitpid(pid) }
629
645
  o.close
630
646
  Process.kill('INT', pid)
631
647
  f.await
@@ -647,7 +663,7 @@ class FiberTest < MiniTest::Test
647
663
  end
648
664
  end
649
665
  sleep 0.2
650
- f = spin { Thread.current.agent.waitpid(pid) }
666
+ f = spin { Thread.current.backend.waitpid(pid) }
651
667
  o.close
652
668
  Process.kill('TERM', pid)
653
669
  f.await
@@ -674,7 +690,7 @@ class FiberTest < MiniTest::Test
674
690
  sleep 0.2
675
691
  Process.kill('TERM', pid)
676
692
  end
677
- Thread.current.agent.waitpid(pid)
693
+ Thread.current.backend.waitpid(pid)
678
694
  klass = i.read
679
695
  i.close
680
696
  assert_equal 'Polyphony::Terminate', klass
@@ -692,7 +708,7 @@ class FiberTest < MiniTest::Test
692
708
 
693
709
  f.schedule
694
710
  f << 'bar'
695
- snooze
711
+ 2.times { snooze }
696
712
  assert_equal ['bar'], buffer
697
713
  end
698
714
  end