polyphony 0.44.0 → 0.45.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -1
  3. data/CHANGELOG.md +41 -0
  4. data/Gemfile.lock +14 -8
  5. data/Rakefile +1 -1
  6. data/TODO.md +12 -15
  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 +1 -1
  14. data/examples/adapters/sequel_pg.rb +24 -0
  15. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  16. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  17. data/examples/core/deferring-an-operation.rb +16 -0
  18. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  19. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  20. data/examples/core/handling-signals.rb +11 -0
  21. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  22. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  23. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  24. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  25. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  26. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  27. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  28. data/examples/core/supervisor.rb +20 -0
  29. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  30. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  31. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  32. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  33. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  34. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  35. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  36. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  37. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  38. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  39. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  40. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  41. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  42. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  43. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  44. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  45. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  46. data/examples/io/{xx-open.rb → open.rb} +0 -0
  47. data/examples/io/pry.rb +18 -0
  48. data/examples/io/rack_server.rb +71 -0
  49. data/examples/io/raw.rb +14 -0
  50. data/examples/io/reline.rb +18 -0
  51. data/examples/io/{xx-system.rb → system.rb} +1 -1
  52. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  53. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  54. data/examples/io/tunnel.rb +6 -1
  55. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  56. data/examples/performance/fiber_transfer.rb +2 -1
  57. data/examples/performance/fs_read.rb +5 -6
  58. data/examples/performance/multi_snooze.rb +0 -1
  59. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  60. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  61. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  62. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  63. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  64. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
  65. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  66. data/examples/performance/thread_pool_perf.rb +6 -7
  67. data/ext/polyphony/backend.h +40 -0
  68. data/ext/polyphony/event.c +3 -3
  69. data/ext/polyphony/extconf.rb +1 -1
  70. data/ext/polyphony/fiber.c +90 -13
  71. data/ext/polyphony/{libev_agent.c → libev_backend.c} +226 -224
  72. data/ext/polyphony/polyphony.c +5 -7
  73. data/ext/polyphony/polyphony.h +18 -18
  74. data/ext/polyphony/polyphony_ext.c +5 -4
  75. data/ext/polyphony/queue.c +5 -6
  76. data/ext/polyphony/ring_buffer.c +0 -1
  77. data/ext/polyphony/runqueue.c +102 -0
  78. data/ext/polyphony/runqueue_ring_buffer.c +85 -0
  79. data/ext/polyphony/runqueue_ring_buffer.h +31 -0
  80. data/ext/polyphony/thread.c +53 -102
  81. data/lib/polyphony.rb +15 -14
  82. data/lib/polyphony/adapters/fs.rb +1 -1
  83. data/lib/polyphony/adapters/irb.rb +2 -17
  84. data/lib/polyphony/adapters/mysql2.rb +1 -1
  85. data/lib/polyphony/adapters/postgres.rb +5 -5
  86. data/lib/polyphony/adapters/process.rb +2 -5
  87. data/lib/polyphony/adapters/readline.rb +17 -0
  88. data/lib/polyphony/adapters/redis.rb +1 -1
  89. data/lib/polyphony/adapters/sequel.rb +1 -1
  90. data/lib/polyphony/core/global_api.rb +19 -14
  91. data/lib/polyphony/core/resource_pool.rb +2 -2
  92. data/lib/polyphony/core/sync.rb +43 -3
  93. data/lib/polyphony/core/throttler.rb +1 -1
  94. data/lib/polyphony/extensions/core.rb +25 -32
  95. data/lib/polyphony/extensions/fiber.rb +22 -45
  96. data/lib/polyphony/extensions/io.rb +60 -16
  97. data/lib/polyphony/extensions/openssl.rb +6 -6
  98. data/lib/polyphony/extensions/socket.rb +14 -15
  99. data/lib/polyphony/extensions/thread.rb +6 -5
  100. data/lib/polyphony/version.rb +1 -1
  101. data/polyphony.gemspec +5 -3
  102. data/test/helper.rb +1 -1
  103. data/test/{test_agent.rb → test_backend.rb} +22 -22
  104. data/test/test_fiber.rb +13 -12
  105. data/test/test_global_api.rb +29 -0
  106. data/test/test_io.rb +59 -1
  107. data/test/test_kernel.rb +5 -0
  108. data/test/test_signal.rb +14 -11
  109. data/test/test_socket.rb +17 -0
  110. data/test/test_sync.rb +73 -0
  111. metadata +99 -98
  112. data/.gitbook.yaml +0 -4
  113. data/examples/adapters/concurrent-ruby.rb +0 -9
  114. data/examples/core/04-handling-signals.rb +0 -19
  115. data/examples/core/xx-agent.rb +0 -102
  116. data/examples/core/xx-at_exit.rb +0 -29
  117. data/examples/core/xx-caller.rb +0 -12
  118. data/examples/core/xx-daemon.rb +0 -14
  119. data/examples/core/xx-deadlock.rb +0 -8
  120. data/examples/core/xx-deferring-an-operation.rb +0 -14
  121. data/examples/core/xx-exception-backtrace.rb +0 -40
  122. data/examples/core/xx-fork-cleanup.rb +0 -22
  123. data/examples/core/xx-fork-spin.rb +0 -42
  124. data/examples/core/xx-fork-terminate.rb +0 -27
  125. data/examples/core/xx-move_on.rb +0 -23
  126. data/examples/core/xx-queue-async.rb +0 -120
  127. data/examples/core/xx-readpartial.rb +0 -18
  128. data/examples/core/xx-signals.rb +0 -16
  129. data/examples/core/xx-sleep-forever.rb +0 -9
  130. data/examples/core/xx-sleeping.rb +0 -25
  131. data/examples/core/xx-snooze-starve.rb +0 -16
  132. data/examples/core/xx-spin-fork.rb +0 -49
  133. data/examples/core/xx-state-machine.rb +0 -51
  134. data/examples/core/xx-stop.rb +0 -20
  135. data/examples/core/xx-supervisors.rb +0 -21
  136. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  137. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  138. data/examples/core/xx-thread-snooze.rb +0 -34
  139. data/examples/core/xx-timer-gc.rb +0 -17
  140. data/examples/core/xx-trace.rb +0 -79
  141. data/examples/performance/xx-array.rb +0 -11
  142. data/examples/performance/xx-fiber-switch.rb +0 -9
  143. data/examples/performance/xx-snooze.rb +0 -15
  144. data/examples/xx-spin.rb +0 -32
  145. data/ext/polyphony/agent.h +0 -41
@@ -7,20 +7,6 @@ require_relative '../core/exceptions'
7
7
  module Polyphony
8
8
  # Fiber control API
9
9
  module FiberControl
10
- def await
11
- if @running == false
12
- return @result.is_a?(Exception) ? (Kernel.raise @result) : @result
13
- end
14
-
15
- fiber = Fiber.current
16
- @waiting_fibers ||= {}
17
- @waiting_fibers[fiber] = true
18
- suspend
19
- ensure
20
- @waiting_fibers&.delete(fiber)
21
- end
22
- alias_method :join, :await
23
-
24
10
  def interrupt(value = nil)
25
11
  return if @running == false
26
12
 
@@ -117,7 +103,7 @@ module Polyphony
117
103
  suspend
118
104
  fibers.map(&:result)
119
105
  ensure
120
- await_select_cleanup(state)
106
+ await_select_cleanup(state) if state
121
107
  end
122
108
  alias_method :join, :await
123
109
 
@@ -179,21 +165,19 @@ module Polyphony
179
165
  state[:selected] = true
180
166
  end
181
167
  end
182
- end
183
168
 
184
- # Messaging functionality
185
- module FiberMessaging
186
- def <<(value)
187
- @mailbox << value
188
- end
189
- alias_method :send, :<<
190
-
191
- def receive
192
- @mailbox.shift
193
- end
194
-
195
- def receive_pending
196
- @mailbox.shift_all
169
+ # Creates and schedules with priority an out-of-band fiber that runs the
170
+ # supplied block. If any uncaught exception is raised while the fiber is
171
+ # running, it will bubble up to the main thread's main fiber, which will
172
+ # also be scheduled with priority. This method is mainly used trapping
173
+ # signals (see also the patched `Kernel#trap`)
174
+ def schedule_priority_oob_fiber(&block)
175
+ f = Fiber.new do
176
+ block.call
177
+ rescue Exception => e
178
+ Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, e)
179
+ end
180
+ Thread.current.break_out_of_ev_loop(f, nil)
197
181
  end
198
182
  end
199
183
 
@@ -225,14 +209,14 @@ module Polyphony
225
209
  def await_all_children
226
210
  return unless @children && !@children.empty?
227
211
 
228
- @results = @children.dup
212
+ results = @children.dup
229
213
  @on_child_done = proc do |c, r|
230
- @results[c] = r
231
- self.schedule if @children.empty?
214
+ results[c] = r
215
+ schedule if @children.empty?
232
216
  end
233
217
  suspend
234
218
  @on_child_done = nil
235
- @results.values
219
+ results.values
236
220
  end
237
221
 
238
222
  def shutdown_all_children
@@ -249,7 +233,6 @@ module Polyphony
249
233
  @parent = parent
250
234
  @caller = caller
251
235
  @block = block
252
- @mailbox = Polyphony::Queue.new
253
236
  __fiber_trace__(:fiber_create, self)
254
237
  schedule
255
238
  end
@@ -279,7 +262,6 @@ module Polyphony
279
262
  # allows the fiber to be scheduled and to receive messages.
280
263
  def setup_raw
281
264
  @thread = Thread.current
282
- @mailbox = Polyphony::Queue.new
283
265
  end
284
266
 
285
267
  def setup_main_fiber
@@ -288,11 +270,10 @@ module Polyphony
288
270
  @thread = Thread.current
289
271
  @running = true
290
272
  @children&.clear
291
- @mailbox = Polyphony::Queue.new
292
273
  end
293
274
 
294
275
  def restart_self(first_value)
295
- @mailbox = Polyphony::Queue.new
276
+ @mailbox = nil
296
277
  @when_done_procs = nil
297
278
  @waiting_fibers = nil
298
279
  run(first_value)
@@ -324,13 +305,10 @@ module Polyphony
324
305
  def inform_dependants(result, uncaught_exception)
325
306
  @parent&.child_done(self, result)
326
307
  @when_done_procs&.each { |p| p.(result) }
327
- @waiting_fibers&.each_key do |f|
328
- f.schedule(result)
329
- end
330
- return unless uncaught_exception && !@waiting_fibers
331
-
308
+ @waiting_fibers&.each_key { |f| f.schedule(result) }
309
+
332
310
  # propagate unaught exception to parent
333
- @parent&.schedule(result)
311
+ @parent&.schedule_with_priority(result) if uncaught_exception && !@waiting_fibers
334
312
  end
335
313
 
336
314
  def when_done(&block)
@@ -344,14 +322,13 @@ end
344
322
  class ::Fiber
345
323
  prepend Polyphony::FiberControl
346
324
  include Polyphony::FiberSupervision
347
- include Polyphony::FiberMessaging
348
325
  include Polyphony::ChildFiberControl
349
326
  include Polyphony::FiberLifeCycle
350
327
 
351
328
  extend Polyphony::FiberControlClassMethods
352
329
 
353
330
  attr_accessor :tag, :thread, :parent
354
- attr_reader :result
331
+ attr_reader :result, :mailbox
355
332
 
356
333
  def running?
357
334
  @running
@@ -90,16 +90,27 @@ class ::IO
90
90
  # def each_codepoint
91
91
  # end
92
92
 
93
- # def getbyte
94
- # end
93
+ alias_method :orig_getbyte, :getbyte
94
+ def getbyte
95
+ char = getc
96
+ char ? char.getbyte(0) : nil
97
+ end
95
98
 
96
- # def getc
97
- # end
99
+ alias_method :orig_getc, :getc
100
+ def getc
101
+ return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
102
+
103
+ @read_buffer ||= +''
104
+ Thread.current.backend.read(self, @read_buffer, 8192, false)
105
+ return @read_buffer.slice!(0) if !@read_buffer.empty?
106
+
107
+ nil
108
+ end
98
109
 
99
110
  alias_method :orig_read, :read
100
111
  def read(len = nil)
101
112
  @read_buffer ||= +''
102
- result = Thread.current.agent.read(self, @read_buffer, len, true)
113
+ result = Thread.current.backend.read(self, @read_buffer, len, true)
103
114
  return nil unless result
104
115
 
105
116
  already_read = @read_buffer
@@ -110,7 +121,7 @@ class ::IO
110
121
  alias_method :orig_readpartial, :read
111
122
  def readpartial(len, str = nil)
112
123
  @read_buffer ||= +''
113
- result = Thread.current.agent.read(self, @read_buffer, len, false)
124
+ result = Thread.current.backend.read(self, @read_buffer, len, false)
114
125
  raise EOFError unless result
115
126
 
116
127
  if str
@@ -124,12 +135,12 @@ class ::IO
124
135
 
125
136
  alias_method :orig_write, :write
126
137
  def write(str, *args)
127
- Thread.current.agent.write(self, str, *args)
138
+ Thread.current.backend.write(self, str, *args)
128
139
  end
129
140
 
130
141
  alias_method :orig_write_chevron, :<<
131
142
  def <<(str)
132
- Thread.current.agent.write(self, str)
143
+ Thread.current.backend.write(self, str)
133
144
  self
134
145
  end
135
146
 
@@ -163,20 +174,29 @@ class ::IO
163
174
  # def putc(obj)
164
175
  # end
165
176
 
177
+ LINEFEED = "\n"
178
+ LINEFEED_RE = /\n$/.freeze
179
+
166
180
  alias_method :orig_puts, :puts
167
181
  def puts(*args)
168
182
  if args.empty?
169
- write "\n"
183
+ write LINEFEED
170
184
  return
171
185
  end
172
186
 
173
- strs = args.inject([]) do |m, a|
174
- a = a.to_s
175
- m << a
176
- m << "\n" unless a =~ /\n$/
177
- m
187
+ idx = 0
188
+ while idx < args.size
189
+ arg = args[idx]
190
+ args[idx] = arg = arg.to_s unless arg.is_a?(String)
191
+ if arg =~ LINEFEED_RE
192
+ idx += 1
193
+ else
194
+ args.insert(idx + 1, LINEFEED)
195
+ idx += 2
196
+ end
178
197
  end
179
- write *strs
198
+
199
+ write(*args)
180
200
  nil
181
201
  end
182
202
 
@@ -203,7 +223,7 @@ class ::IO
203
223
  end
204
224
 
205
225
  def read_loop(&block)
206
- Thread.current.agent.read_loop(self, &block)
226
+ Thread.current.backend.read_loop(self, &block)
207
227
  end
208
228
 
209
229
  # alias_method :orig_read, :read
@@ -218,4 +238,28 @@ class ::IO
218
238
  # end
219
239
  # outbuf
220
240
  # end
241
+
242
+ def wait_readable(timeout = nil)
243
+ if timeout
244
+ move_on_after(timeout) do
245
+ Thread.current.backend.wait_io(self, false)
246
+ self
247
+ end
248
+ else
249
+ Thread.current.backend.wait_io(self, false)
250
+ self
251
+ end
252
+ end
253
+
254
+ def wait_writable(timeout = nil)
255
+ if timeout
256
+ move_on_after(timeout) do
257
+ Thread.current.backend.wait_io(self, true)
258
+ self
259
+ end
260
+ else
261
+ Thread.current.backend.wait_io(self, true)
262
+ self
263
+ end
264
+ end
221
265
  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,26 +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
- Thread.current.agent.connect(self, remotesockaddr.ip_address, remotesockaddr.ip_port)
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)
28
19
  end
29
20
 
30
21
  def recv(maxlen, flags = 0, outbuf = nil)
@@ -33,7 +24,7 @@ class ::Socket
33
24
  result = recv_nonblock(maxlen, flags, outbuf, **NO_EXCEPTION)
34
25
  case result
35
26
  when nil then raise IOError
36
- when :wait_readable then Thread.current.agent.wait_io(self, false)
27
+ when :wait_readable then Thread.current.backend.wait_io(self, false)
37
28
  else
38
29
  return result
39
30
  end
@@ -46,7 +37,7 @@ class ::Socket
46
37
  result = recvfrom_nonblock(maxlen, flags, @read_buffer, **NO_EXCEPTION)
47
38
  case result
48
39
  when nil then raise IOError
49
- when :wait_readable then Thread.current.agent.wait_io(self, false)
40
+ when :wait_readable then Thread.current.backend.wait_io(self, false)
50
41
  else
51
42
  return result
52
43
  end
@@ -128,6 +119,14 @@ class ::TCPSocket
128
119
  def reuse_port
129
120
  setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
130
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::Agent.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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.44.0'
4
+ VERSION = '0.45.5'
5
5
  end
@@ -21,19 +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.1.1'
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'
35
36
  s.add_development_dependency 'mysql2', '0.5.3'
36
37
  s.add_development_dependency 'sequel', '5.34.0'
38
+ s.add_development_dependency 'httparty', '0.17.1'
37
39
 
38
40
  s.add_development_dependency 'jekyll', '~>3.8.6'
39
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::Agent.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::Agent.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)