polyphony 0.71 → 0.74
Sign up to get free protection for your applications and to get access to all the features.
- 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
|