polyphony 0.70 → 0.73.1
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 +3 -2
- data/.gitignore +3 -1
- data/CHANGELOG.md +32 -4
- data/Gemfile.lock +11 -11
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- 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 +15 -9
- data/ext/polyphony/backend_common.h +1 -1
- data/ext/polyphony/backend_io_uring.c +56 -64
- data/ext/polyphony/backend_io_uring_context.c +1 -1
- data/ext/polyphony/backend_io_uring_context.h +1 -1
- data/ext/polyphony/backend_libev.c +36 -30
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.h +5 -1
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue_ring_buffer.c +3 -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 +27 -9
- 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 +3 -4
- 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 -5
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/stress.rb +1 -1
- data/test/test_backend.rb +12 -12
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +52 -7
- data/test/test_global_api.rb +16 -3
- data/test/test_io.rb +3 -3
- 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 +12 -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 +1 -1
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +2 -2
- data/test/test_trace.rb +1 -1
- metadata +13 -4
data/ext/polyphony/extconf.rb
CHANGED
@@ -3,32 +3,43 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'mkmf'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
|
7
|
+
KERNEL_INFO_RE = /Linux (\d)\.(\d+)\.(?:\d+)\-(?:\d+\-)?(\w+)/
|
8
|
+
def get_config
|
9
|
+
config = { linux: !!(RUBY_PLATFORM =~ /linux/) }
|
10
|
+
return config if !config[:linux]
|
11
|
+
|
12
|
+
kernel_info = `uname -sr`
|
13
|
+
m = kernel_info.match(KERNEL_INFO_RE)
|
14
|
+
raise "Could not parse Linux kernel information (#{kernel_info.inspect})" if !m
|
15
|
+
|
16
|
+
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[3]
|
17
|
+
config[:pidfd_open] = (version == 5) && (major_revision >= 3)
|
18
|
+
|
19
|
+
force_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
|
20
|
+
config[:io_uring] = !force_libev &&
|
21
|
+
(version == 5) && (major_revision >= 6) && (distribution != 'linuxkit')
|
22
|
+
config
|
15
23
|
end
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
config = get_config
|
26
|
+
puts "Building Polyphony... (#{config.inspect})"
|
27
|
+
|
28
|
+
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
29
|
+
if config[:io_uring]
|
19
30
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
20
31
|
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
21
32
|
$CFLAGS << " -Wno-pointer-arith"
|
22
33
|
else
|
23
34
|
$defs << "-DPOLYPHONY_BACKEND_LIBEV"
|
24
|
-
$defs << "-DPOLYPHONY_LINUX" if linux
|
35
|
+
$defs << "-DPOLYPHONY_LINUX" if config[:linux]
|
25
36
|
$defs << '-DEV_USE_LINUXAIO' if have_header('linux/aio_abi.h')
|
26
37
|
$defs << '-DEV_USE_SELECT' if have_header('sys/select.h')
|
27
38
|
$defs << '-DEV_USE_POLL' if have_type('port_event_t', 'poll.h')
|
28
39
|
$defs << '-DEV_USE_EPOLL' if have_header('sys/epoll.h')
|
29
40
|
$defs << '-DEV_USE_KQUEUE' if have_header('sys/event.h') && have_header('sys/queue.h')
|
30
41
|
$defs << '-DEV_USE_PORT' if have_type('port_event_t', 'port.h')
|
31
|
-
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
42
|
+
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
32
43
|
|
33
44
|
$CFLAGS << " -Wno-comment"
|
34
45
|
$CFLAGS << " -Wno-unused-result"
|
@@ -40,6 +51,7 @@ $defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
|
|
40
51
|
|
41
52
|
CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
|
42
53
|
|
54
|
+
have_func('rb_fiber_transfer', 'ruby.h')
|
43
55
|
|
44
56
|
dir_config 'polyphony_ext'
|
45
57
|
create_makefile 'polyphony_ext'
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -26,7 +26,11 @@
|
|
26
26
|
#define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
|
27
27
|
|
28
28
|
// Fiber#transfer
|
29
|
-
#
|
29
|
+
#if HAVE_RB_FIBER_TRANSFER
|
30
|
+
#define FIBER_TRANSFER(fiber, value) rb_fiber_transfer(fiber, 1, &value)
|
31
|
+
#else
|
32
|
+
#define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
|
33
|
+
#endif
|
30
34
|
|
31
35
|
#define BACKEND() (rb_ivar_get(rb_thread_current(), ID_ivar_backend))
|
32
36
|
|
data/ext/polyphony/queue.c
CHANGED
@@ -162,12 +162,12 @@ VALUE Queue_cap(VALUE self, VALUE cap) {
|
|
162
162
|
Queue_t *queue;
|
163
163
|
GetQueue(self, queue);
|
164
164
|
queue->capacity = new_capacity;
|
165
|
-
|
165
|
+
|
166
166
|
if (queue->capacity)
|
167
167
|
queue_schedule_blocked_fibers_to_capacity(queue);
|
168
168
|
else
|
169
169
|
queue_schedule_all_blocked_fibers(&queue->push_queue);
|
170
|
-
|
170
|
+
|
171
171
|
return self;
|
172
172
|
}
|
173
173
|
|
@@ -61,8 +61,9 @@ inline void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber,
|
|
61
61
|
|
62
62
|
inline void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
63
63
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
64
|
-
|
65
|
-
rb_gc_mark(
|
64
|
+
runqueue_entry entry = buffer->entries[(buffer->head + i) % buffer->size];
|
65
|
+
rb_gc_mark(entry.fiber);
|
66
|
+
rb_gc_mark(entry.value);
|
66
67
|
}
|
67
68
|
}
|
68
69
|
|
data/ext/polyphony/thread.c
CHANGED
@@ -40,7 +40,7 @@ VALUE Thread_fiber_schedule_and_wakeup(VALUE self, VALUE fiber, VALUE resume_obj
|
|
40
40
|
}
|
41
41
|
|
42
42
|
if (Backend_wakeup(rb_ivar_get(self, ID_ivar_backend)) == Qnil) {
|
43
|
-
// we're not inside
|
43
|
+
// we're not inside Backend_poll, so we just do a switchpoint
|
44
44
|
Thread_switch_fiber(self);
|
45
45
|
}
|
46
46
|
|
@@ -3,26 +3,36 @@
|
|
3
3
|
require 'polyphony'
|
4
4
|
|
5
5
|
if Object.constants.include?(:Reline)
|
6
|
+
puts "reline"
|
6
7
|
class Reline::ANSI
|
7
8
|
def self.select(read_ios = [], write_ios = [], error_ios = [], timeout = nil)
|
8
|
-
p [:select, read_ios]
|
9
|
+
# p [:select, read_ios, timeout]
|
10
|
+
# puts caller.join("\n")
|
9
11
|
raise if read_ios.size > 1
|
10
12
|
raise if write_ios.size > 0
|
11
13
|
raise if error_ios.size > 0
|
12
14
|
|
15
|
+
# p 1
|
13
16
|
fiber = Fiber.current
|
14
17
|
timer = spin do
|
15
18
|
sleep timeout
|
16
19
|
fiber.cancel
|
17
20
|
end
|
21
|
+
# p 2
|
18
22
|
read_ios.each do |io|
|
23
|
+
# p wait: io
|
19
24
|
Polyphony.backend_wait_io(io, false)
|
25
|
+
# p :done_wait
|
20
26
|
return [io]
|
21
27
|
end
|
28
|
+
# p 3
|
22
29
|
rescue Polyphony::Cancel
|
30
|
+
# p :cancel
|
23
31
|
return nil
|
24
32
|
ensure
|
33
|
+
# p :ensure
|
25
34
|
timer.stop
|
35
|
+
# p :ensure_done
|
26
36
|
end
|
27
37
|
end
|
28
38
|
else
|
File without changes
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../extensions/core'
|
4
|
-
require_relative '../extensions/fiber'
|
5
|
-
require_relative './exceptions'
|
6
3
|
require_relative './throttler'
|
7
4
|
|
8
5
|
module Polyphony
|
@@ -73,7 +70,7 @@ module Polyphony
|
|
73
70
|
|
74
71
|
def spin_scope
|
75
72
|
raise unless block_given?
|
76
|
-
|
73
|
+
|
77
74
|
spin do
|
78
75
|
result = yield
|
79
76
|
Fiber.current.await_all_children
|
@@ -122,8 +119,8 @@ module Polyphony
|
|
122
119
|
Fiber.current.receive_all_pending
|
123
120
|
end
|
124
121
|
|
125
|
-
def supervise(*args, &block)
|
126
|
-
Fiber.current.supervise(*args, &block)
|
122
|
+
def supervise(*args, **opts, &block)
|
123
|
+
Fiber.current.supervise(*args, **opts, &block)
|
127
124
|
end
|
128
125
|
|
129
126
|
def sleep(duration = nil)
|
data/lib/polyphony/core/timer.rb
CHANGED
@@ -44,7 +44,7 @@ module Polyphony
|
|
44
44
|
ensure
|
45
45
|
@timeouts.delete(fiber)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def cancel_after(interval, with_exception: Polyphony::Cancel)
|
49
49
|
fiber = Fiber.current
|
50
50
|
@timeouts[fiber] = {
|
@@ -74,7 +74,7 @@ module Polyphony
|
|
74
74
|
def reset
|
75
75
|
record = @timeouts[Fiber.current]
|
76
76
|
return unless record
|
77
|
-
|
77
|
+
|
78
78
|
record[:target_stamp] = now + record[:interval]
|
79
79
|
end
|
80
80
|
|
data/lib/polyphony/debugger.rb
CHANGED
@@ -9,11 +9,11 @@ module Polyphony
|
|
9
9
|
:return,
|
10
10
|
:b_call,
|
11
11
|
:b_return
|
12
|
-
]
|
12
|
+
]
|
13
13
|
|
14
14
|
def self.start_debug_server(socket_path)
|
15
15
|
server = DebugServer.new(socket_path)
|
16
|
-
controller = DebugController.new(server)
|
16
|
+
controller = DebugController.new(server)
|
17
17
|
trace = TracePoint.new(*TP_EVENTS) { |tp| controller.handle_tp(trace, tp) }
|
18
18
|
trace.enable
|
19
19
|
|
@@ -124,7 +124,7 @@ module Polyphony
|
|
124
124
|
h
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
def cmd_step(cmd)
|
129
129
|
tp = nil
|
130
130
|
fiber = nil
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Exeption overrides
|
4
|
+
class ::Exception
|
5
|
+
class << self
|
6
|
+
attr_accessor :__disable_sanitized_backtrace__
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :source_fiber, :raising_fiber
|
10
|
+
|
11
|
+
alias_method :orig_initialize, :initialize
|
12
|
+
def initialize(*args)
|
13
|
+
@raising_fiber = Fiber.current
|
14
|
+
orig_initialize(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :orig_backtrace, :backtrace
|
18
|
+
def backtrace
|
19
|
+
unless @backtrace_called
|
20
|
+
@backtrace_called = true
|
21
|
+
return orig_backtrace
|
22
|
+
end
|
23
|
+
|
24
|
+
sanitized_backtrace
|
25
|
+
end
|
26
|
+
|
27
|
+
def sanitized_backtrace
|
28
|
+
return sanitize(orig_backtrace) unless @raising_fiber
|
29
|
+
|
30
|
+
backtrace = orig_backtrace || []
|
31
|
+
sanitize(backtrace + @raising_fiber.caller)
|
32
|
+
end
|
33
|
+
|
34
|
+
POLYPHONY_DIR = File.expand_path(File.join(__dir__, '..'))
|
35
|
+
|
36
|
+
def sanitize(backtrace)
|
37
|
+
return backtrace if ::Exception.__disable_sanitized_backtrace__
|
38
|
+
|
39
|
+
backtrace.reject { |l| l[POLYPHONY_DIR] }
|
40
|
+
end
|
41
|
+
|
42
|
+
def invoke
|
43
|
+
Kernel.raise(self)
|
44
|
+
end
|
45
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'fiber'
|
4
|
-
|
5
3
|
require_relative '../core/exceptions'
|
6
4
|
|
7
5
|
module Polyphony
|
@@ -19,7 +17,7 @@ module Polyphony
|
|
19
17
|
alias_method :stop, :interrupt
|
20
18
|
|
21
19
|
def restart(value = nil)
|
22
|
-
raise "Can'
|
20
|
+
raise "Can't restart main fiber" if @main
|
23
21
|
|
24
22
|
if @running
|
25
23
|
schedule Polyphony::Restart.new(value)
|
@@ -83,6 +81,8 @@ module Polyphony
|
|
83
81
|
def supervise(*fibers, **opts, &block)
|
84
82
|
block ||= supervise_opts_to_block(opts)
|
85
83
|
|
84
|
+
@supervise_mode = true
|
85
|
+
fibers = children if fibers.empty?
|
86
86
|
fibers.each do |f|
|
87
87
|
f.attach_to(self) unless f.parent == self
|
88
88
|
f.monitor(self)
|
@@ -94,15 +94,18 @@ module Polyphony
|
|
94
94
|
(fiber, result) = mailbox.shift
|
95
95
|
block&.call(fiber, result)
|
96
96
|
end
|
97
|
+
ensure
|
98
|
+
@supervise_mode = false
|
97
99
|
end
|
98
100
|
|
99
101
|
def supervise_opts_to_block(opts)
|
100
102
|
block = opts[:on_done] || opts[:on_error]
|
101
|
-
|
103
|
+
restart = opts[:restart]
|
104
|
+
return nil unless block || restart
|
102
105
|
|
103
106
|
error_only = !!opts[:on_error]
|
104
|
-
restart_always =
|
105
|
-
restart_on_error =
|
107
|
+
restart_always = (restart == :always) || (restart == true)
|
108
|
+
restart_on_error = restart == :on_error
|
106
109
|
|
107
110
|
->(f, r) do
|
108
111
|
is_error = r.is_a?(Exception)
|
@@ -114,6 +117,14 @@ module Polyphony
|
|
114
117
|
|
115
118
|
# Class methods for controlling fibers (namely await and select)
|
116
119
|
module FiberControlClassMethods
|
120
|
+
# call-seq:
|
121
|
+
# Fiber.await(*fibers) -> [*results]
|
122
|
+
# Fiber.join(*fibers) -> [*results]
|
123
|
+
#
|
124
|
+
# Waits for all given fibers to terminate, then returns the respective
|
125
|
+
# return values for all terminated fibers. If any of the awaited fibers
|
126
|
+
# terminates with an uncaught exception, `Fiber.await` will await all the
|
127
|
+
# other fibers to terminate, then reraise the exception.
|
117
128
|
def await(*fibers)
|
118
129
|
return [] if fibers.empty?
|
119
130
|
|
@@ -149,7 +160,7 @@ module Polyphony
|
|
149
160
|
|
150
161
|
def select(*fibers)
|
151
162
|
return nil if fibers.empty?
|
152
|
-
|
163
|
+
|
153
164
|
current_fiber = self.current
|
154
165
|
mailbox = current_fiber.monitor_mailbox
|
155
166
|
fibers.each do |f|
|
@@ -163,7 +174,7 @@ module Polyphony
|
|
163
174
|
while true
|
164
175
|
(fiber, result) = mailbox.shift
|
165
176
|
next unless fibers.include?(fiber)
|
166
|
-
|
177
|
+
|
167
178
|
fibers.each { |f| f.unmonitor(current_fiber) }
|
168
179
|
if result.is_a?(Exception)
|
169
180
|
raise result
|
@@ -197,6 +208,7 @@ module Polyphony
|
|
197
208
|
|
198
209
|
def add_child(child_fiber)
|
199
210
|
(@children ||= {})[child_fiber] = true
|
211
|
+
child_fiber.monitor(self) if @supervise_mode
|
200
212
|
end
|
201
213
|
|
202
214
|
def remove_child(child_fiber)
|
@@ -207,6 +219,7 @@ module Polyphony
|
|
207
219
|
f = Fiber.new { |v| f.run(v) }
|
208
220
|
f.prepare(tag, block, orig_caller, self)
|
209
221
|
(@children ||= {})[f] = true
|
222
|
+
f.monitor(self) if @supervise_mode
|
210
223
|
f
|
211
224
|
end
|
212
225
|
|
@@ -237,10 +250,15 @@ module Polyphony
|
|
237
250
|
end
|
238
251
|
end
|
239
252
|
|
253
|
+
def attach_all_children_to(fiber)
|
254
|
+
@children&.keys.each { |c| c.attach_to(fiber) }
|
255
|
+
end
|
256
|
+
|
240
257
|
def detach
|
241
258
|
@parent.remove_child(self)
|
242
259
|
@parent = @thread.main_fiber
|
243
260
|
@parent.add_child(self)
|
261
|
+
self
|
244
262
|
end
|
245
263
|
|
246
264
|
def attach_to(fiber)
|
@@ -328,7 +346,7 @@ module Polyphony
|
|
328
346
|
# the children are shut down, it is returned along with the uncaught_exception
|
329
347
|
# flag set. Otherwise, it returns the given arguments.
|
330
348
|
def finalize_children(result, uncaught_exception)
|
331
|
-
shutdown_all_children
|
349
|
+
shutdown_all_children(graceful_shutdown?)
|
332
350
|
[result, uncaught_exception]
|
333
351
|
rescue Exception => e
|
334
352
|
[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
|
@@ -32,7 +32,7 @@ class ::Socket
|
|
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
34
|
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
35
|
-
|
35
|
+
|
36
36
|
buf = +''
|
37
37
|
len = buf.bytesize
|
38
38
|
while true
|
@@ -168,7 +168,7 @@ class ::TCPSocket
|
|
168
168
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
169
169
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
170
170
|
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
171
|
-
|
171
|
+
|
172
172
|
buf = +''
|
173
173
|
len = buf.bytesize
|
174
174
|
while true
|
@@ -232,7 +232,6 @@ class ::TCPServer
|
|
232
232
|
alias_method :orig_accept, :accept
|
233
233
|
def accept
|
234
234
|
Polyphony.backend_accept(@io, TCPSocket)
|
235
|
-
# @io.accept
|
236
235
|
end
|
237
236
|
|
238
237
|
def accept_loop(&block)
|
@@ -261,7 +260,7 @@ class ::UNIXSocket
|
|
261
260
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
262
261
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
263
262
|
return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
|
264
|
-
|
263
|
+
|
265
264
|
buf = +''
|
266
265
|
len = buf.bytesize
|
267
266
|
while true
|
@@ -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,12 @@
|
|
2
2
|
|
3
3
|
require 'fiber'
|
4
4
|
require_relative './polyphony_ext'
|
5
|
-
|
6
|
-
require_relative './polyphony/extensions/core'
|
7
|
-
require_relative './polyphony/extensions/thread'
|
8
|
-
require_relative './polyphony/extensions/fiber'
|
9
|
-
require_relative './polyphony/extensions/io'
|
5
|
+
require_relative './polyphony/extensions'
|
10
6
|
|
11
7
|
Thread.current.setup_fiber_scheduling
|
12
8
|
Thread.current.backend = Polyphony::Backend.new
|
13
9
|
|
10
|
+
require_relative './polyphony/core/exceptions'
|
14
11
|
require_relative './polyphony/core/global_api'
|
15
12
|
require_relative './polyphony/core/resource_pool'
|
16
13
|
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
|