polyphony 0.71 → 0.74
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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +15 -11
- data/.github/workflows/test_io_uring.yml +32 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +33 -4
- data/Gemfile.lock +16 -13
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/exception.md +5 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/core/ring.rb +29 -0
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +88 -18
- data/ext/polyphony/backend_common.h +8 -1
- data/ext/polyphony/backend_io_uring.c +280 -164
- data/ext/polyphony/backend_io_uring_context.c +2 -1
- data/ext/polyphony/backend_io_uring_context.h +3 -2
- data/ext/polyphony/backend_libev.c +42 -38
- data/ext/polyphony/event.c +5 -2
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.c +10 -1
- data/ext/polyphony/polyphony.h +7 -1
- data/ext/polyphony/queue.c +12 -7
- data/ext/polyphony/runqueue_ring_buffer.c +6 -3
- data/ext/polyphony/socket_extensions.c +5 -2
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/{extensions → core}/debug.rb +0 -0
- data/lib/polyphony/core/global_api.rb +3 -6
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/exception.rb +45 -0
- data/lib/polyphony/extensions/fiber.rb +87 -11
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/{core.rb → kernel.rb} +0 -73
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/process.rb +19 -0
- data/lib/polyphony/extensions/socket.rb +20 -9
- data/lib/polyphony/extensions/thread.rb +9 -3
- data/lib/polyphony/extensions/timeout.rb +10 -0
- data/lib/polyphony/extensions.rb +9 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -4
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/test_backend.rb +15 -17
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +31 -7
- data/test/test_global_api.rb +23 -14
- data/test/test_io.rb +5 -5
- data/test/test_kernel.rb +2 -2
- data/test/test_process_supervision.rb +1 -1
- data/test/test_queue.rb +6 -6
- data/test/test_signal.rb +20 -1
- data/test/test_socket.rb +45 -10
- data/test/test_supervise.rb +85 -0
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +3 -3
- data/test/test_timer.rb +3 -3
- data/test/test_trace.rb +1 -1
- metadata +19 -9
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'fiber'
|
|
4
|
-
|
|
5
3
|
require_relative '../core/exceptions'
|
|
6
4
|
|
|
7
5
|
module Polyphony
|
|
8
6
|
# Fiber control API
|
|
9
7
|
module FiberControl
|
|
8
|
+
# Returns the fiber's monitoring mailbox queue, used for receiving fiber
|
|
9
|
+
# monitoring messages.
|
|
10
|
+
#
|
|
11
|
+
# @return [Polyphony::Queue] Monitoring mailbox queue
|
|
10
12
|
def monitor_mailbox
|
|
11
13
|
@monitor_mailbox ||= Polyphony::Queue.new
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
# call-seq:
|
|
17
|
+
# fiber.stop(value = nil) -> fiber
|
|
18
|
+
# Fiber.interrupt(value = nil) -> fiber
|
|
19
|
+
#
|
|
20
|
+
# Stops the fiber by raising a Polyphony::MoveOn exception. The given value
|
|
21
|
+
# will become the fiber's return value.
|
|
22
|
+
#
|
|
23
|
+
# @param value [any] Fiber's eventual return value
|
|
24
|
+
# @return [Fiber] fiber
|
|
14
25
|
def interrupt(value = nil)
|
|
15
26
|
return if @running == false
|
|
16
27
|
|
|
17
28
|
schedule Polyphony::MoveOn.new(value)
|
|
29
|
+
self
|
|
18
30
|
end
|
|
19
31
|
alias_method :stop, :interrupt
|
|
20
32
|
|
|
33
|
+
# call-seq:
|
|
34
|
+
# fiber.reset(value = nil) -> fiber
|
|
35
|
+
# fiber.restart(value = nil) -> fiber
|
|
36
|
+
#
|
|
37
|
+
# Restarts the fiber, with the given value serving as the first value passed
|
|
38
|
+
# to the fiber's block.
|
|
39
|
+
#
|
|
40
|
+
# @param value [any] value passed to fiber block
|
|
41
|
+
# @return [Fiber] restarted fiber
|
|
21
42
|
def restart(value = nil)
|
|
22
|
-
raise "Can'
|
|
43
|
+
raise "Can't restart main fiber" if @main
|
|
23
44
|
|
|
24
45
|
if @running
|
|
25
46
|
schedule Polyphony::Restart.new(value)
|
|
@@ -33,32 +54,58 @@ module Polyphony
|
|
|
33
54
|
end
|
|
34
55
|
alias_method :reset, :restart
|
|
35
56
|
|
|
57
|
+
# Stops a fiber by raising a Polyphony::Cancel exception.
|
|
58
|
+
#
|
|
59
|
+
# @return [Fiber] fiber
|
|
36
60
|
def cancel
|
|
37
61
|
return if @running == false
|
|
38
62
|
|
|
39
63
|
schedule Polyphony::Cancel.new
|
|
64
|
+
self
|
|
40
65
|
end
|
|
41
66
|
|
|
67
|
+
# Sets the graceful shutdown flag for the fiber.
|
|
68
|
+
#
|
|
69
|
+
# @param graceful [bool] Whether or not to perform a graceful shutdown
|
|
42
70
|
def graceful_shutdown=(graceful)
|
|
43
71
|
@graceful_shutdown = graceful
|
|
44
72
|
end
|
|
45
73
|
|
|
74
|
+
# Returns the graceful shutdown flag for the fiber.
|
|
75
|
+
#
|
|
76
|
+
# @return [bool]
|
|
46
77
|
def graceful_shutdown?
|
|
47
78
|
@graceful_shutdown
|
|
48
79
|
end
|
|
49
80
|
|
|
81
|
+
# Terminates the fiber, optionally setting the graceful shutdown flag.
|
|
82
|
+
#
|
|
83
|
+
# @param graceful [bool] Whether to perform a graceful shutdown
|
|
84
|
+
# @return [Fiber]
|
|
50
85
|
def terminate(graceful = false)
|
|
51
86
|
return if @running == false
|
|
52
87
|
|
|
53
88
|
@graceful_shutdown = graceful
|
|
54
89
|
schedule Polyphony::Terminate.new
|
|
55
|
-
|
|
56
|
-
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# call-seq:
|
|
94
|
+
# fiber.raise(message) -> fiber
|
|
95
|
+
# fiber.raise(exception_class) -> fiber
|
|
96
|
+
# fiber.raise(exception_class, exception_message) -> fiber
|
|
97
|
+
# fiber.raise(exception) -> fiber
|
|
98
|
+
#
|
|
99
|
+
# Raises an exception in the context of the fiber.
|
|
100
|
+
#
|
|
101
|
+
# @return [Fiber]
|
|
57
102
|
def raise(*args)
|
|
58
103
|
error = error_from_raise_args(args)
|
|
59
104
|
schedule(error)
|
|
105
|
+
self
|
|
60
106
|
end
|
|
61
107
|
|
|
108
|
+
# :no-doc:
|
|
62
109
|
def error_from_raise_args(args)
|
|
63
110
|
case (arg = args.shift)
|
|
64
111
|
when String then RuntimeError.new(arg)
|
|
@@ -83,6 +130,8 @@ module Polyphony
|
|
|
83
130
|
def supervise(*fibers, **opts, &block)
|
|
84
131
|
block ||= supervise_opts_to_block(opts)
|
|
85
132
|
|
|
133
|
+
@supervise_mode = true
|
|
134
|
+
fibers = children if fibers.empty?
|
|
86
135
|
fibers.each do |f|
|
|
87
136
|
f.attach_to(self) unless f.parent == self
|
|
88
137
|
f.monitor(self)
|
|
@@ -94,15 +143,18 @@ module Polyphony
|
|
|
94
143
|
(fiber, result) = mailbox.shift
|
|
95
144
|
block&.call(fiber, result)
|
|
96
145
|
end
|
|
146
|
+
ensure
|
|
147
|
+
@supervise_mode = false
|
|
97
148
|
end
|
|
98
149
|
|
|
99
150
|
def supervise_opts_to_block(opts)
|
|
100
151
|
block = opts[:on_done] || opts[:on_error]
|
|
101
|
-
|
|
152
|
+
restart = opts[:restart]
|
|
153
|
+
return nil unless block || restart
|
|
102
154
|
|
|
103
155
|
error_only = !!opts[:on_error]
|
|
104
|
-
restart_always =
|
|
105
|
-
restart_on_error =
|
|
156
|
+
restart_always = (restart == :always) || (restart == true)
|
|
157
|
+
restart_on_error = restart == :on_error
|
|
106
158
|
|
|
107
159
|
->(f, r) do
|
|
108
160
|
is_error = r.is_a?(Exception)
|
|
@@ -114,6 +166,17 @@ module Polyphony
|
|
|
114
166
|
|
|
115
167
|
# Class methods for controlling fibers (namely await and select)
|
|
116
168
|
module FiberControlClassMethods
|
|
169
|
+
# call-seq:
|
|
170
|
+
# Fiber.await(*fibers) -> [*results]
|
|
171
|
+
# Fiber.join(*fibers) -> [*results]
|
|
172
|
+
#
|
|
173
|
+
# Waits for all given fibers to terminate, then returns the respective
|
|
174
|
+
# return values for all terminated fibers. If any of the awaited fibers
|
|
175
|
+
# terminates with an uncaught exception, `Fiber.await` will await all the
|
|
176
|
+
# other fibers to terminate, then reraise the exception.
|
|
177
|
+
#
|
|
178
|
+
# @param *fibers [Array<Fiber>] fibers to wait for
|
|
179
|
+
# @return [Array<any>] return values of given fibers
|
|
117
180
|
def await(*fibers)
|
|
118
181
|
return [] if fibers.empty?
|
|
119
182
|
|
|
@@ -147,9 +210,15 @@ module Polyphony
|
|
|
147
210
|
end
|
|
148
211
|
alias_method :join, :await
|
|
149
212
|
|
|
213
|
+
# Waits for at least one of the given fibers to terminate, returning an
|
|
214
|
+
# array containing the first terminated fiber and its return value. If an
|
|
215
|
+
# exception occurs in one of the given fibers, it will be reraised.
|
|
216
|
+
#
|
|
217
|
+
# @param *fibers [Array<Fiber>] Fibers to wait for
|
|
218
|
+
# @return [Array] Array containing the first terminated fiber and its return value
|
|
150
219
|
def select(*fibers)
|
|
151
220
|
return nil if fibers.empty?
|
|
152
|
-
|
|
221
|
+
|
|
153
222
|
current_fiber = self.current
|
|
154
223
|
mailbox = current_fiber.monitor_mailbox
|
|
155
224
|
fibers.each do |f|
|
|
@@ -163,7 +232,7 @@ module Polyphony
|
|
|
163
232
|
while true
|
|
164
233
|
(fiber, result) = mailbox.shift
|
|
165
234
|
next unless fibers.include?(fiber)
|
|
166
|
-
|
|
235
|
+
|
|
167
236
|
fibers.each { |f| f.unmonitor(current_fiber) }
|
|
168
237
|
if result.is_a?(Exception)
|
|
169
238
|
raise result
|
|
@@ -197,6 +266,7 @@ module Polyphony
|
|
|
197
266
|
|
|
198
267
|
def add_child(child_fiber)
|
|
199
268
|
(@children ||= {})[child_fiber] = true
|
|
269
|
+
child_fiber.monitor(self) if @supervise_mode
|
|
200
270
|
end
|
|
201
271
|
|
|
202
272
|
def remove_child(child_fiber)
|
|
@@ -207,6 +277,7 @@ module Polyphony
|
|
|
207
277
|
f = Fiber.new { |v| f.run(v) }
|
|
208
278
|
f.prepare(tag, block, orig_caller, self)
|
|
209
279
|
(@children ||= {})[f] = true
|
|
280
|
+
f.monitor(self) if @supervise_mode
|
|
210
281
|
f
|
|
211
282
|
end
|
|
212
283
|
|
|
@@ -237,10 +308,15 @@ module Polyphony
|
|
|
237
308
|
end
|
|
238
309
|
end
|
|
239
310
|
|
|
311
|
+
def attach_all_children_to(fiber)
|
|
312
|
+
@children&.keys.each { |c| c.attach_to(fiber) }
|
|
313
|
+
end
|
|
314
|
+
|
|
240
315
|
def detach
|
|
241
316
|
@parent.remove_child(self)
|
|
242
317
|
@parent = @thread.main_fiber
|
|
243
318
|
@parent.add_child(self)
|
|
319
|
+
self
|
|
244
320
|
end
|
|
245
321
|
|
|
246
322
|
def attach_to(fiber)
|
|
@@ -328,7 +404,7 @@ module Polyphony
|
|
|
328
404
|
# the children are shut down, it is returned along with the uncaught_exception
|
|
329
405
|
# flag set. Otherwise, it returns the given arguments.
|
|
330
406
|
def finalize_children(result, uncaught_exception)
|
|
331
|
-
shutdown_all_children
|
|
407
|
+
shutdown_all_children(graceful_shutdown?)
|
|
332
408
|
[result, uncaught_exception]
|
|
333
409
|
rescue Exception => e
|
|
334
410
|
[e, true]
|
|
@@ -103,7 +103,7 @@ class ::IO
|
|
|
103
103
|
alias_method :orig_getc, :getc
|
|
104
104
|
def getc
|
|
105
105
|
return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
@read_buffer ||= +''
|
|
108
108
|
Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
|
|
109
109
|
return @read_buffer.slice!(0) if !@read_buffer.empty?
|
|
@@ -116,7 +116,7 @@ class ::IO
|
|
|
116
116
|
if buf
|
|
117
117
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
|
118
118
|
end
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
@read_buffer ||= +''
|
|
121
121
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
|
122
122
|
return nil unless result
|
|
@@ -1,73 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'fiber'
|
|
4
|
-
require 'timeout'
|
|
5
3
|
require 'open3'
|
|
6
4
|
|
|
7
|
-
require_relative '../core/exceptions'
|
|
8
|
-
|
|
9
|
-
# Exeption overrides
|
|
10
|
-
class ::Exception
|
|
11
|
-
class << self
|
|
12
|
-
attr_accessor :__disable_sanitized_backtrace__
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
attr_accessor :source_fiber, :raising_fiber
|
|
16
|
-
|
|
17
|
-
alias_method :orig_initialize, :initialize
|
|
18
|
-
def initialize(*args)
|
|
19
|
-
@raising_fiber = Fiber.current
|
|
20
|
-
orig_initialize(*args)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
alias_method :orig_backtrace, :backtrace
|
|
24
|
-
def backtrace
|
|
25
|
-
unless @backtrace_called
|
|
26
|
-
@backtrace_called = true
|
|
27
|
-
return orig_backtrace
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
sanitized_backtrace
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def sanitized_backtrace
|
|
34
|
-
return sanitize(orig_backtrace) unless @raising_fiber
|
|
35
|
-
|
|
36
|
-
backtrace = orig_backtrace || []
|
|
37
|
-
sanitize(backtrace + @raising_fiber.caller)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
POLYPHONY_DIR = File.expand_path(File.join(__dir__, '..'))
|
|
41
|
-
|
|
42
|
-
def sanitize(backtrace)
|
|
43
|
-
return backtrace if ::Exception.__disable_sanitized_backtrace__
|
|
44
|
-
|
|
45
|
-
backtrace.reject { |l| l[POLYPHONY_DIR] }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def invoke
|
|
49
|
-
Kernel.raise(self)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Overrides for Process
|
|
54
|
-
module ::Process
|
|
55
|
-
class << self
|
|
56
|
-
alias_method :orig_detach, :detach
|
|
57
|
-
def detach(pid)
|
|
58
|
-
fiber = spin { Polyphony.backend_waitpid(pid) }
|
|
59
|
-
fiber.define_singleton_method(:pid) { pid }
|
|
60
|
-
fiber
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
alias_method :orig_daemon, :daemon
|
|
64
|
-
def daemon(*args)
|
|
65
|
-
orig_daemon(*args)
|
|
66
|
-
Polyphony.original_pid = Process.pid
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
5
|
# Kernel extensions (methods available to all objects / call sites)
|
|
72
6
|
module ::Kernel
|
|
73
7
|
alias_method :orig_sleep, :sleep
|
|
@@ -159,10 +93,3 @@ module ::Kernel
|
|
|
159
93
|
end
|
|
160
94
|
end
|
|
161
95
|
end
|
|
162
|
-
|
|
163
|
-
# Override Timeout to use cancel scope
|
|
164
|
-
module ::Timeout
|
|
165
|
-
def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
|
|
166
|
-
cancel_after(sec, with_exception: [klass, message], &block)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
@@ -130,24 +130,32 @@ class ::OpenSSL::SSL::SSLServer
|
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
+
# STDOUT.puts 'SSLServer#accept'
|
|
133
134
|
sock, = @svr.accept
|
|
135
|
+
# STDOUT.puts "- raw sock: #{sock.inspect}"
|
|
134
136
|
begin
|
|
135
137
|
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
|
138
|
+
# STDOUT.puts "- ssl sock: #{ssl.inspect}"
|
|
136
139
|
ssl.sync_close = true
|
|
137
140
|
if @use_accept_worker
|
|
141
|
+
# STDOUT.puts "- send to accept worker"
|
|
138
142
|
@accept_worker_fiber << [ssl, Fiber.current]
|
|
139
|
-
|
|
143
|
+
# STDOUT.puts "- wait for accept worker"
|
|
144
|
+
r = receive
|
|
145
|
+
# STDOUT.puts "- got reply from accept worker: #{r.inspect}"
|
|
146
|
+
r.invoke if r.is_a?(Exception)
|
|
140
147
|
else
|
|
141
148
|
ssl.accept
|
|
142
149
|
end
|
|
143
150
|
ssl
|
|
144
|
-
rescue Exception =>
|
|
151
|
+
rescue Exception => e
|
|
152
|
+
# STDOUT.puts "- accept exception: #{e.inspect}"
|
|
145
153
|
if ssl
|
|
146
154
|
ssl.close
|
|
147
155
|
else
|
|
148
156
|
sock.close
|
|
149
157
|
end
|
|
150
|
-
raise
|
|
158
|
+
raise e
|
|
151
159
|
end
|
|
152
160
|
end
|
|
153
161
|
|
|
@@ -156,11 +164,18 @@ class ::OpenSSL::SSL::SSLServer
|
|
|
156
164
|
@accept_worker_thread = Thread.new do
|
|
157
165
|
fiber << Fiber.current
|
|
158
166
|
loop do
|
|
167
|
+
# STDOUT.puts "- accept_worker wait for work"
|
|
159
168
|
socket, peer = receive
|
|
169
|
+
# STDOUT.puts "- accept_worker got socket from peer #{peer.inspect}"
|
|
160
170
|
socket.accept
|
|
171
|
+
# STDOUT.puts "- accept_worker accept returned"
|
|
161
172
|
peer << socket
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
# STDOUT.puts "- accept_worker sent socket back to peer"
|
|
174
|
+
rescue Polyphony::BaseException
|
|
175
|
+
raise
|
|
176
|
+
rescue Exception => e
|
|
177
|
+
# STDOUT.puts "- accept_worker error: #{e}"
|
|
178
|
+
peer << e if peer
|
|
164
179
|
end
|
|
165
180
|
end
|
|
166
181
|
@accept_worker_fiber = receive
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Overrides for Process
|
|
4
|
+
module ::Process
|
|
5
|
+
class << self
|
|
6
|
+
alias_method :orig_detach, :detach
|
|
7
|
+
def detach(pid)
|
|
8
|
+
fiber = spin { Polyphony.backend_waitpid(pid) }
|
|
9
|
+
fiber.define_singleton_method(:pid) { pid }
|
|
10
|
+
fiber
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
alias_method :orig_daemon, :daemon
|
|
14
|
+
def daemon(*args)
|
|
15
|
+
orig_daemon(*args)
|
|
16
|
+
Polyphony.original_pid = Process.pid
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -31,8 +31,8 @@ class ::Socket
|
|
|
31
31
|
alias_method :orig_read, :read
|
|
32
32
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
|
33
33
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
|
34
|
-
return Polyphony.backend_recv(self,
|
|
35
|
-
|
|
34
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
|
35
|
+
|
|
36
36
|
buf = +''
|
|
37
37
|
len = buf.bytesize
|
|
38
38
|
while true
|
|
@@ -120,8 +120,16 @@ class ::TCPSocket
|
|
|
120
120
|
|
|
121
121
|
attr_reader :io
|
|
122
122
|
|
|
123
|
+
def self.open(*args)
|
|
124
|
+
new(*args)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def address_family(host)
|
|
128
|
+
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
|
129
|
+
end
|
|
130
|
+
|
|
123
131
|
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
|
124
|
-
@io = Socket.new
|
|
132
|
+
@io = Socket.new address_family(remote_host), Socket::SOCK_STREAM
|
|
125
133
|
if local_host && local_port
|
|
126
134
|
addr = Addrinfo.tcp(local_host, local_port)
|
|
127
135
|
@io.bind(addr)
|
|
@@ -167,8 +175,8 @@ class ::TCPSocket
|
|
|
167
175
|
alias_method :orig_read, :read
|
|
168
176
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
|
169
177
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
|
170
|
-
return Polyphony.backend_recv(self,
|
|
171
|
-
|
|
178
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
|
179
|
+
|
|
172
180
|
buf = +''
|
|
173
181
|
len = buf.bytesize
|
|
174
182
|
while true
|
|
@@ -223,8 +231,12 @@ end
|
|
|
223
231
|
|
|
224
232
|
# Override stock TCPServer code by encapsulating a Socket instance.
|
|
225
233
|
class ::TCPServer
|
|
234
|
+
def address_family(host)
|
|
235
|
+
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
|
236
|
+
end
|
|
237
|
+
|
|
226
238
|
def initialize(hostname = nil, port = 0)
|
|
227
|
-
@io = Socket.new
|
|
239
|
+
@io = Socket.new address_family(hostname), Socket::SOCK_STREAM
|
|
228
240
|
@io.bind(Addrinfo.tcp(hostname, port))
|
|
229
241
|
@io.listen(0)
|
|
230
242
|
end
|
|
@@ -232,7 +244,6 @@ class ::TCPServer
|
|
|
232
244
|
alias_method :orig_accept, :accept
|
|
233
245
|
def accept
|
|
234
246
|
Polyphony.backend_accept(@io, TCPSocket)
|
|
235
|
-
# @io.accept
|
|
236
247
|
end
|
|
237
248
|
|
|
238
249
|
def accept_loop(&block)
|
|
@@ -260,8 +271,8 @@ class ::UNIXSocket
|
|
|
260
271
|
alias_method :orig_read, :read
|
|
261
272
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
|
262
273
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
|
263
|
-
return Polyphony.backend_recv(self,
|
|
264
|
-
|
|
274
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
|
275
|
+
|
|
265
276
|
buf = +''
|
|
266
277
|
len = buf.bytesize
|
|
267
278
|
while true
|
|
@@ -18,14 +18,20 @@ class ::Thread
|
|
|
18
18
|
def execute
|
|
19
19
|
# backend must be created in the context of the new thread, therefore it
|
|
20
20
|
# cannot be created in Thread#initialize
|
|
21
|
-
|
|
21
|
+
raise_error = false
|
|
22
|
+
begin
|
|
23
|
+
@backend = Polyphony::Backend.new
|
|
24
|
+
rescue Exception => e
|
|
25
|
+
raise_error = true
|
|
26
|
+
raise e
|
|
27
|
+
end
|
|
22
28
|
setup
|
|
23
29
|
@ready = true
|
|
24
30
|
result = @block.(*@args)
|
|
25
31
|
rescue Polyphony::MoveOn, Polyphony::Terminate => e
|
|
26
32
|
result = e.value
|
|
27
33
|
rescue Exception => e
|
|
28
|
-
result = e
|
|
34
|
+
raise_error ? (raise e) : (result = e)
|
|
29
35
|
ensure
|
|
30
36
|
@ready = true
|
|
31
37
|
finalize(result)
|
|
@@ -48,7 +54,7 @@ class ::Thread
|
|
|
48
54
|
@result = result
|
|
49
55
|
signal_waiters(result)
|
|
50
56
|
end
|
|
51
|
-
@backend
|
|
57
|
+
@backend&.finalize
|
|
52
58
|
end
|
|
53
59
|
|
|
54
60
|
def signal_waiters(result)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'timeout'
|
|
4
|
+
|
|
5
|
+
# Override Timeout to use cancel scope
|
|
6
|
+
module ::Timeout
|
|
7
|
+
def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
|
|
8
|
+
cancel_after(sec, with_exception: [klass, message], &block)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative './extensions/exception'
|
|
4
|
+
require_relative './extensions/fiber'
|
|
5
|
+
require_relative './extensions/io'
|
|
6
|
+
require_relative './extensions/kernel'
|
|
7
|
+
require_relative './extensions/process'
|
|
8
|
+
require_relative './extensions/thread'
|
|
9
|
+
require_relative './extensions/timeout'
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require 'fiber'
|
|
4
4
|
require_relative './polyphony_ext'
|
|
5
|
-
|
|
6
|
-
require_relative './polyphony/extensions/core'
|
|
7
5
|
require_relative './polyphony/extensions/thread'
|
|
8
|
-
require_relative './polyphony/extensions/fiber'
|
|
9
|
-
require_relative './polyphony/extensions/io'
|
|
10
6
|
|
|
11
7
|
Thread.current.setup_fiber_scheduling
|
|
12
8
|
Thread.current.backend = Polyphony::Backend.new
|
|
13
9
|
|
|
10
|
+
require_relative './polyphony/extensions'
|
|
11
|
+
require_relative './polyphony/core/exceptions'
|
|
14
12
|
require_relative './polyphony/core/global_api'
|
|
15
13
|
require_relative './polyphony/core/resource_pool'
|
|
16
14
|
require_relative './polyphony/core/sync'
|
data/polyphony.gemspec
CHANGED
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
|
|
|
27
27
|
s.add_development_dependency 'simplecov', '0.17.1'
|
|
28
28
|
s.add_development_dependency 'rubocop', '0.85.1'
|
|
29
29
|
s.add_development_dependency 'pry', '0.13.1'
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
s.add_development_dependency 'msgpack', '1.4.2'
|
|
32
32
|
s.add_development_dependency 'httparty', '0.17.1'
|
|
33
33
|
s.add_development_dependency 'localhost', '~>1.1.4'
|
data/test/coverage.rb
CHANGED
|
@@ -24,10 +24,10 @@ module Coverage
|
|
|
24
24
|
@result = {}
|
|
25
25
|
trace = TracePoint.new(:line) do |tp|
|
|
26
26
|
next if tp.path =~ /\(/
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
absolute = File.expand_path(tp.path)
|
|
29
29
|
next unless LIB_FILES.include?(absolute)# =~ /^#{LIB_DIR}/
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
@result[absolute] ||= relevant_lines_for_filename(absolute)
|
|
32
32
|
@result[absolute][tp.lineno - 1] = 1
|
|
33
33
|
end
|