polyphony 0.67 → 0.68
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/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/bin/pdbg +91 -9
- data/ext/polyphony/backend_io_uring.c +1 -1
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/debugger.rb +225 -0
- data/lib/polyphony/extensions/fiber.rb +24 -38
- data/lib/polyphony/extensions/io.rb +0 -2
- data/lib/polyphony/extensions/openssl.rb +62 -0
- data/lib/polyphony/extensions/socket.rb +2 -2
- data/lib/polyphony/net.rb +1 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +0 -1
- data/test/test_fiber.rb +2 -2
- data/test/test_supervise.rb +24 -24
- metadata +4 -4
- data/lib/polyphony/debugger/server.rb +0 -137
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d23a9c0f60530fdee1d367f34359e4f694bd4a42ba3c0112e61433df05c29a81
|
4
|
+
data.tar.gz: bf75e3f1a633f5c94a43fd45a2de2545d87b1e751753980abb8e1d3eddd4eade
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b810c7ddbd383039e5f34fe76dbea089807417d4415e79a952f6d6a46538cf99c55ae7a34f3eadf61d22af23ac29a0910c62ea5c97dff6e86b94083d98444edf
|
7
|
+
data.tar.gz: '063459edd8f669a024e0b7b8f1daa47983db4cf9ac7f3ca81a69359de92eace4831d843e9b74645db08a50c26d83a2878a5fdb6b125adc260afd13a3135e710c'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 0.68 2021-08-13
|
2
|
+
|
3
|
+
- Fix missing default value in socket classes' `#readpartial`
|
4
|
+
- Fix linking of operations in `Backend#chain` (io_uring version)
|
5
|
+
- Rename `Fiber#attach` to `Fiber#attach_to`
|
6
|
+
- Expose original `SSLServer#accept`
|
7
|
+
|
1
8
|
## 0.67 2021-08-06
|
2
9
|
|
3
10
|
- Improve fiber monitoring
|
data/Gemfile.lock
CHANGED
data/bin/pdbg
CHANGED
@@ -8,23 +8,105 @@ UNIX_SOCKET_PATH = '/tmp/pdbg.sock'
|
|
8
8
|
|
9
9
|
cmd = ARGV.join(' ')
|
10
10
|
injected_lib_path = File.expand_path('../lib/polyphony/debugger/server_inject.rb', __dir__)
|
11
|
-
p cmd
|
12
11
|
pid = fork { exec("env POLYPHONY_DEBUG_SOCKET_PATH=#{UNIX_SOCKET_PATH} ruby #{cmd}") }
|
13
12
|
puts "Started debugged process (#{pid})"
|
14
13
|
|
15
|
-
|
16
|
-
socket
|
14
|
+
socket = nil
|
15
|
+
while !socket
|
16
|
+
socket = UNIXSocket.new(UNIX_SOCKET_PATH) rescue nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_command(cmd)
|
20
|
+
case cmd
|
21
|
+
when /^(step|s)$/
|
22
|
+
{ cmd: :step }
|
23
|
+
when /^(state|st)$/
|
24
|
+
{ cmd: :state }
|
25
|
+
when /^(help|h)$/
|
26
|
+
{ cmd: :help }
|
27
|
+
when /^(list|l)$/
|
28
|
+
{ cmd: :list }
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def display_info(info)
|
35
|
+
info = eval(info)
|
36
|
+
case (info && info[:kind])
|
37
|
+
when :listing
|
38
|
+
print_listing(info)
|
39
|
+
when :state
|
40
|
+
print_state(info)
|
41
|
+
else
|
42
|
+
p info
|
43
|
+
end
|
44
|
+
rescue SyntaxError
|
45
|
+
puts "Failed to eval:"
|
46
|
+
p info
|
47
|
+
end
|
48
|
+
|
49
|
+
FILE_LINES_CACHE = {}
|
50
|
+
|
51
|
+
def self.get_snippet(path, lineno)
|
52
|
+
lines = FILE_LINES_CACHE[path] ||= IO.read(path).lines
|
53
|
+
start_idx = lineno - 5
|
54
|
+
stop_idx = lineno + 3
|
55
|
+
stop_idx = lines.size - 1 if stop_idx >= lines.size
|
56
|
+
start_idx = 0 if start_idx < 0
|
57
|
+
(start_idx..stop_idx).map { |idx| [idx + 1, lines[idx]]}
|
58
|
+
end
|
59
|
+
|
60
|
+
def print_snippet(info, snippet, cur_line)
|
61
|
+
places = FILE_LINES_CACHE[info[:path]].size.to_s.size
|
62
|
+
snippet.each do |(lineno, line)|
|
63
|
+
is_cur = lineno == cur_line
|
64
|
+
formatted = format("%s% #{places}d %s", is_cur ? '=> ' : ' ', lineno, line)
|
65
|
+
puts formatted
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def print_listing(info)
|
70
|
+
snippet = get_snippet(info[:path], info[:lineno])
|
71
|
+
puts "Fiber: #{info[:fiber]} Location: #{info[:path]}:#{info[:lineno]}"
|
72
|
+
puts
|
73
|
+
print_snippet(info, snippet, info[:lineno])
|
74
|
+
puts
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_help
|
78
|
+
puts
|
79
|
+
puts "Here's some help..."
|
80
|
+
puts
|
81
|
+
end
|
82
|
+
|
83
|
+
def print_state(info)
|
84
|
+
p info
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_user_cmd
|
88
|
+
while true
|
89
|
+
STDOUT << "(pdbg) "
|
90
|
+
cmd = parse_command(STDIN.gets)
|
91
|
+
next unless cmd
|
92
|
+
|
93
|
+
if cmd[:cmd] == :help
|
94
|
+
print_help
|
95
|
+
else
|
96
|
+
return cmd if cmd
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
17
101
|
socket.puts 'pdbg'
|
18
102
|
response = socket.gets
|
19
103
|
if response.chomp == 'pdbg'
|
20
104
|
puts 'Connected to process'
|
21
105
|
end
|
22
106
|
loop do
|
23
|
-
|
24
|
-
|
107
|
+
info = socket.gets.chomp
|
108
|
+
display_info(info)
|
25
109
|
|
26
|
-
|
27
|
-
cmd
|
28
|
-
puts '-' * 40
|
29
|
-
socket.puts cmd
|
110
|
+
cmd = get_user_cmd
|
111
|
+
socket.puts cmd.inspect
|
30
112
|
end
|
@@ -1248,7 +1248,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1248
1248
|
}
|
1249
1249
|
|
1250
1250
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1251
|
-
unsigned int flags = (i == argc - 1) ? IOSQE_ASYNC : IOSQE_ASYNC
|
1251
|
+
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1252
1252
|
io_uring_sqe_set_flags(last_sqe, flags);
|
1253
1253
|
sqe_count++;
|
1254
1254
|
}
|
data/lib/polyphony.rb
CHANGED
@@ -124,6 +124,6 @@ Polyphony.install_at_exit_handler
|
|
124
124
|
|
125
125
|
if (debug_socket_path = ENV['POLYPHONY_DEBUG_SOCKET_PATH'])
|
126
126
|
puts "Starting debug server on #{debug_socket_path}"
|
127
|
-
require 'polyphony/debugger
|
128
|
-
Polyphony
|
127
|
+
require 'polyphony/debugger'
|
128
|
+
Polyphony.start_debug_server(debug_socket_path)
|
129
129
|
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'polyphony/extensions/debug'
|
4
|
+
|
5
|
+
module Polyphony
|
6
|
+
TP_EVENTS = [
|
7
|
+
:line,
|
8
|
+
:call,
|
9
|
+
:return,
|
10
|
+
:b_call,
|
11
|
+
:b_return
|
12
|
+
]
|
13
|
+
|
14
|
+
def self.start_debug_server(socket_path)
|
15
|
+
server = DebugServer.new(socket_path)
|
16
|
+
controller = DebugController.new(server)
|
17
|
+
trace = TracePoint.new(*TP_EVENTS) { |tp| controller.handle_tp(trace, tp) }
|
18
|
+
trace.enable
|
19
|
+
|
20
|
+
at_exit do
|
21
|
+
Kernel.trace "program terminated"
|
22
|
+
trace.disable
|
23
|
+
server.stop
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class DebugController
|
28
|
+
def initialize(server)
|
29
|
+
@server = server
|
30
|
+
@server.wait_for_client
|
31
|
+
@state = { fibers: {} }
|
32
|
+
@control_fiber = Fiber.new { |f| control_loop(f) }
|
33
|
+
@control_fiber.transfer Fiber.current
|
34
|
+
end
|
35
|
+
|
36
|
+
def control_loop(source_fiber)
|
37
|
+
@peer = source_fiber
|
38
|
+
cmd = { cmd: :initial }
|
39
|
+
loop do
|
40
|
+
cmd = send(:"cmd_#{cmd[:cmd]}", cmd)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
POLYPHONY_LIB_DIR = File.expand_path('..', __dir__)
|
45
|
+
|
46
|
+
def get_next_trace_event
|
47
|
+
@peer.transfer.tap { |e| update_state(e) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_state(event)
|
51
|
+
trace update_state: event
|
52
|
+
@state[:fiber] = event[:fiber]
|
53
|
+
@state[:path] = event[:path]
|
54
|
+
@state[:lineno] = event[:lineno]
|
55
|
+
update_fiber_state(event)
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_fiber_state(event)
|
59
|
+
fiber_state = @state[:fibers][event[:fiber]] ||= { stack: [] }
|
60
|
+
case event[:kind]
|
61
|
+
when :call, :c_call, :b_call
|
62
|
+
fiber_state[:stack] << event
|
63
|
+
when :return, :c_return, :b_return
|
64
|
+
fiber_state[:stack].pop
|
65
|
+
end
|
66
|
+
fiber_state[:binding] = event[:binding]
|
67
|
+
fiber_state[:path] = event[:path]
|
68
|
+
fiber_state[:lineno] = event[:lineno]
|
69
|
+
end
|
70
|
+
|
71
|
+
def state_presentation(state)
|
72
|
+
{
|
73
|
+
fiber: fiber_id(state[:fiber]),
|
74
|
+
path: state[:path],
|
75
|
+
lineno: state[:lineno]
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def fiber_id(fiber)
|
80
|
+
{
|
81
|
+
object_id: fiber.object_id,
|
82
|
+
tag: fiber.tag
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def fiber_representation(fiber)
|
87
|
+
{
|
88
|
+
object_id: fiber.object_id,
|
89
|
+
tag: fiber.tag,
|
90
|
+
parent: fiber.parent && fiber_id(fiber.parent),
|
91
|
+
children: fiber.children.map { |c| fiber_id(c) }
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_next_command(info)
|
96
|
+
@server.get_command(info)
|
97
|
+
end
|
98
|
+
|
99
|
+
def cmd_initial(cmd)
|
100
|
+
get_next_command(nil)
|
101
|
+
end
|
102
|
+
|
103
|
+
def info_listing(state)
|
104
|
+
{
|
105
|
+
kind: :listing,
|
106
|
+
fiber: fiber_id(state[:fiber]),
|
107
|
+
path: state[:path],
|
108
|
+
lineno: state[:lineno]
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def info_state(state)
|
113
|
+
info_listing(state).merge(
|
114
|
+
kind: :state,
|
115
|
+
fibers: info_fiber_states(state[:fibers])
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
def info_fiber_states(fiber_states)
|
120
|
+
fiber_states.inject({}) do |h, (f, s)|
|
121
|
+
h[fiber_id(f)] = {
|
122
|
+
stack: s[:stack].map { |e| { path: e[:path], lineno: e[:lineno] } }
|
123
|
+
}
|
124
|
+
h
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def cmd_step(cmd)
|
129
|
+
tp = nil
|
130
|
+
fiber = nil
|
131
|
+
while true
|
132
|
+
event = get_next_trace_event
|
133
|
+
@peer = event[:fiber]
|
134
|
+
if event[:kind] == :line && event[:path] !~ /#{POLYPHONY_LIB_DIR}/
|
135
|
+
return get_next_command(info_listing(@state))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
rescue => e
|
139
|
+
trace "Uncaught error: #{e.inspect}"
|
140
|
+
@trace&.disable
|
141
|
+
end
|
142
|
+
|
143
|
+
def cmd_help(cmd)
|
144
|
+
get_next_command(kind: :help)
|
145
|
+
end
|
146
|
+
|
147
|
+
def cmd_list(cmd)
|
148
|
+
get_next_command(info_listing(@state))
|
149
|
+
end
|
150
|
+
|
151
|
+
def cmd_state(cmd)
|
152
|
+
get_next_command(info_state(@state))
|
153
|
+
end
|
154
|
+
|
155
|
+
def handle_tp(trace, tp)
|
156
|
+
return if Thread.current == @server.thread
|
157
|
+
return if Fiber.current == @control_fiber
|
158
|
+
|
159
|
+
kind = tp.event
|
160
|
+
event = {
|
161
|
+
fiber: Fiber.current,
|
162
|
+
kind: kind,
|
163
|
+
path: tp.path,
|
164
|
+
lineno: tp.lineno,
|
165
|
+
binding: tp.binding
|
166
|
+
}
|
167
|
+
case kind
|
168
|
+
when :call, :c_call, :b_call
|
169
|
+
event[:method_id] = tp.method_id
|
170
|
+
event[:parameters] = tp.parameters
|
171
|
+
when :return, :c_return, :b_return
|
172
|
+
event[:method_id] = tp.method_id
|
173
|
+
event[:return_value] = tp.return_value
|
174
|
+
end
|
175
|
+
@control_fiber.transfer(event)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class DebugServer
|
180
|
+
attr_reader :thread
|
181
|
+
|
182
|
+
def initialize(socket_path)
|
183
|
+
@socket_path = socket_path
|
184
|
+
@fiber = Fiber.current
|
185
|
+
start_server_thread
|
186
|
+
end
|
187
|
+
|
188
|
+
def start_server_thread
|
189
|
+
@thread = Thread.new do
|
190
|
+
puts("Listening on #{@socket_path}")
|
191
|
+
FileUtils.rm(@socket_path) if File.exists?(@socket_path)
|
192
|
+
socket = UNIXServer.new(@socket_path)
|
193
|
+
loop do
|
194
|
+
@client = socket.accept
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def stop
|
200
|
+
@thread.kill
|
201
|
+
end
|
202
|
+
|
203
|
+
def handle_client(client)
|
204
|
+
@client = client
|
205
|
+
end
|
206
|
+
|
207
|
+
def wait_for_client
|
208
|
+
sleep 0.1 until @client
|
209
|
+
msg = @client.gets
|
210
|
+
@client.puts msg
|
211
|
+
end
|
212
|
+
|
213
|
+
def get_command(info)
|
214
|
+
@client&.orig_write "#{info.inspect}\n"
|
215
|
+
cmd = @client&.orig_gets&.chomp
|
216
|
+
eval(cmd)
|
217
|
+
rescue SystemCallError
|
218
|
+
nil
|
219
|
+
rescue => e
|
220
|
+
trace "Error in interact_with_client: #{e.inspect}"
|
221
|
+
e.backtrace[0..3].each { |l| trace l }
|
222
|
+
@client = nil
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -79,47 +79,26 @@ module Polyphony
|
|
79
79
|
|
80
80
|
# Fiber supervision
|
81
81
|
module FiberSupervision
|
82
|
-
def supervise(opts
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
while true
|
88
|
-
supervise_perform(opts)
|
89
|
-
end
|
90
|
-
rescue Polyphony::MoveOn
|
91
|
-
# generated in #supervise_perform to stop supervisor
|
92
|
-
ensure
|
93
|
-
@on_child_done = nil
|
94
|
-
end
|
82
|
+
def supervise(*fibers, **opts, &block)
|
83
|
+
block ||= opts[:on_done] ||
|
84
|
+
(opts[:on_error] && supervise_on_error_proc(opts[:on_error]))
|
85
|
+
raise "No block given" unless block
|
95
86
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
restart_fiber(fiber, opts)
|
100
|
-
elsif Fiber.current.children.empty?
|
101
|
-
Fiber.current.stop
|
87
|
+
fibers.each do |f|
|
88
|
+
f.attach_to(self) unless f.parent == self
|
89
|
+
f.monitor(self)
|
102
90
|
end
|
103
|
-
rescue Polyphony::Restart
|
104
|
-
restart_all_children
|
105
|
-
rescue Exception => e
|
106
|
-
Kernel.raise e if e.source_fiber.nil? || e.source_fiber == self
|
107
91
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
92
|
+
mailbox = monitor_mailbox
|
93
|
+
|
94
|
+
while true
|
95
|
+
(fiber, result) = mailbox.shift
|
96
|
+
block&.call(fiber, result)
|
112
97
|
end
|
113
98
|
end
|
114
99
|
|
115
|
-
def
|
116
|
-
opts[:
|
117
|
-
case opts[:restart]
|
118
|
-
when true
|
119
|
-
fiber.restart
|
120
|
-
when :one_for_all
|
121
|
-
@children.keys.each(&:restart)
|
122
|
-
end
|
100
|
+
def supervise_on_error_proc(on_error)
|
101
|
+
->(f, r) { opts[:on_error].(f, r) if r.is_a?(Exception) }
|
123
102
|
end
|
124
103
|
end
|
125
104
|
|
@@ -261,10 +240,17 @@ module Polyphony
|
|
261
240
|
@parent.add_child(self)
|
262
241
|
end
|
263
242
|
|
264
|
-
def
|
243
|
+
def attach_to(fiber)
|
265
244
|
@parent.remove_child(self)
|
266
|
-
@parent =
|
267
|
-
|
245
|
+
@parent = fiber
|
246
|
+
fiber.add_child(self)
|
247
|
+
end
|
248
|
+
|
249
|
+
def attach_and_monitor(fiber)
|
250
|
+
@parent.remove_child(self)
|
251
|
+
@parent = fiber
|
252
|
+
fiber.add_child(self)
|
253
|
+
monitor(fiber)
|
268
254
|
end
|
269
255
|
end
|
270
256
|
|
@@ -114,6 +114,68 @@ end
|
|
114
114
|
|
115
115
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
116
116
|
class ::OpenSSL::SSL::SSLServer
|
117
|
+
attr_reader :ctx
|
118
|
+
|
119
|
+
alias_method :orig_accept, :accept
|
120
|
+
def accept
|
121
|
+
# when @ctx.servername_cb is set, we use a worker thread to run the
|
122
|
+
# ssl.accept call. We need to do this because:
|
123
|
+
# - We cannot switch fibers inside of the servername_cb proc (see
|
124
|
+
# https://github.com/ruby/openssl/issues/415)
|
125
|
+
# - We don't want to stop the world while we're busy provisioning an ACME
|
126
|
+
# certificate
|
127
|
+
if @use_accept_worker.nil?
|
128
|
+
if (@use_accept_worker = use_accept_worker_thread?)
|
129
|
+
start_accept_worker_thread
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
sock, = @svr.accept
|
134
|
+
begin
|
135
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
136
|
+
ssl.sync_close = true
|
137
|
+
if @use_accept_worker
|
138
|
+
@accept_worker_fiber << [ssl, Fiber.current]
|
139
|
+
receive
|
140
|
+
else
|
141
|
+
ssl.accept
|
142
|
+
end
|
143
|
+
ssl
|
144
|
+
rescue Exception => ex
|
145
|
+
if ssl
|
146
|
+
ssl.close
|
147
|
+
else
|
148
|
+
sock.close
|
149
|
+
end
|
150
|
+
raise ex
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def start_accept_worker_thread
|
155
|
+
fiber = Fiber.current
|
156
|
+
@accept_worker_thread = Thread.new do
|
157
|
+
fiber << Fiber.current
|
158
|
+
loop do
|
159
|
+
socket, peer = receive
|
160
|
+
socket.accept
|
161
|
+
peer << socket
|
162
|
+
rescue => e
|
163
|
+
peer.schedule(e) if fiber
|
164
|
+
end
|
165
|
+
end
|
166
|
+
@accept_worker_fiber = receive
|
167
|
+
end
|
168
|
+
|
169
|
+
def use_accept_worker_thread?
|
170
|
+
!!@ctx.servername_cb
|
171
|
+
end
|
172
|
+
|
173
|
+
alias_method :orig_close, :close
|
174
|
+
def close
|
175
|
+
@accept_worker_thread&.kill
|
176
|
+
orig_close
|
177
|
+
end
|
178
|
+
|
117
179
|
def accept_loop(ignore_errors = true)
|
118
180
|
loop do
|
119
181
|
yield accept
|
@@ -206,7 +206,7 @@ class ::TCPSocket
|
|
206
206
|
# Polyphony.backend_send(self, mesg, 0)
|
207
207
|
# end
|
208
208
|
|
209
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
209
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
210
210
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
211
211
|
raise EOFError if !result && raise_on_eof
|
212
212
|
result
|
@@ -299,7 +299,7 @@ class ::UNIXSocket
|
|
299
299
|
Polyphony.backend_send(self, mesg, 0)
|
300
300
|
end
|
301
301
|
|
302
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
302
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
303
303
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
304
304
|
raise EOFError if !result && raise_on_eof
|
305
305
|
result
|
data/lib/polyphony/net.rb
CHANGED
data/lib/polyphony/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -47,7 +47,6 @@ class MiniTest::Test
|
|
47
47
|
def setup
|
48
48
|
# trace "* setup #{self.name}"
|
49
49
|
Fiber.current.setup_main_fiber
|
50
|
-
Fiber.current.instance_variable_set(:@auto_watcher, nil)
|
51
50
|
Thread.current.backend.finalize
|
52
51
|
Thread.current.backend = Polyphony::Backend.new
|
53
52
|
sleep 0.001
|
data/test/test_fiber.rb
CHANGED
@@ -791,7 +791,7 @@ class FiberTest < MiniTest::Test
|
|
791
791
|
], buf
|
792
792
|
end
|
793
793
|
|
794
|
-
def
|
794
|
+
def test_attach_to
|
795
795
|
buf = []
|
796
796
|
child = nil
|
797
797
|
parent = spin(:parent) do
|
@@ -809,7 +809,7 @@ class FiberTest < MiniTest::Test
|
|
809
809
|
|
810
810
|
snooze
|
811
811
|
assert_equal parent, child.parent
|
812
|
-
child.
|
812
|
+
child.attach_to(new_parent)
|
813
813
|
assert_equal new_parent, child.parent
|
814
814
|
parent.await
|
815
815
|
|
data/test/test_supervise.rb
CHANGED
@@ -2,29 +2,29 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
5
|
+
class SuperviseTest < MiniTest::Test
|
6
|
+
def test_supervise_with_no_arguments
|
7
|
+
assert_raises(RuntimeError) do
|
8
|
+
supervise
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_supervise_with_block
|
13
|
+
buffer = []
|
14
|
+
f1 = spin(:f1) { receive }
|
15
|
+
f2 = spin(:f2) { receive }
|
16
|
+
supervisor = spin(:supervisor) { supervise(f1, f2) { |*args| buffer << args } }
|
17
|
+
|
18
|
+
snooze
|
19
|
+
f1 << 'foo'
|
20
|
+
f1.await
|
21
|
+
10.times { snooze }
|
22
|
+
assert_equal [[f1, 'foo']], buffer
|
23
|
+
|
24
|
+
f2 << 'bar'
|
25
|
+
f2.await
|
26
|
+
assert_equal [[f1, 'foo'], [f2, 'bar']], buffer
|
27
|
+
end
|
28
28
|
|
29
29
|
# def test_supervise_with_restart
|
30
30
|
# watcher = spin { receive }
|
@@ -101,4 +101,4 @@ require_relative 'helper'
|
|
101
101
|
# assert :dead, f.state
|
102
102
|
# assert :dead, p.state
|
103
103
|
# end
|
104
|
-
|
104
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.68'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -357,7 +357,7 @@ files:
|
|
357
357
|
- lib/polyphony/core/thread_pool.rb
|
358
358
|
- lib/polyphony/core/throttler.rb
|
359
359
|
- lib/polyphony/core/timer.rb
|
360
|
-
- lib/polyphony/debugger
|
360
|
+
- lib/polyphony/debugger.rb
|
361
361
|
- lib/polyphony/extensions/core.rb
|
362
362
|
- lib/polyphony/extensions/debug.rb
|
363
363
|
- lib/polyphony/extensions/fiber.rb
|
@@ -421,7 +421,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
421
421
|
- !ruby/object:Gem::Version
|
422
422
|
version: '0'
|
423
423
|
requirements: []
|
424
|
-
rubygems_version: 3.1.
|
424
|
+
rubygems_version: 3.1.4
|
425
425
|
signing_key:
|
426
426
|
specification_version: 4
|
427
427
|
summary: Fine grained concurrency for Ruby
|
@@ -1,137 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'polyphony/extensions/debug'
|
4
|
-
|
5
|
-
module Polyphony
|
6
|
-
class DebugServer
|
7
|
-
TP_EVENTS = [
|
8
|
-
:line,
|
9
|
-
:call,
|
10
|
-
:return,
|
11
|
-
:b_call,
|
12
|
-
:b_return
|
13
|
-
]
|
14
|
-
|
15
|
-
|
16
|
-
def self.start(socket_path)
|
17
|
-
server = self.new(socket_path)
|
18
|
-
server.start
|
19
|
-
|
20
|
-
trace = TracePoint.new(*TP_EVENTS) { |tp| server.handle_tp(trace, tp) }
|
21
|
-
trace.enable
|
22
|
-
|
23
|
-
at_exit do
|
24
|
-
puts "program terminated"
|
25
|
-
trace.disable
|
26
|
-
server.stop
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def initialize(socket_path)
|
31
|
-
@socket_path = socket_path
|
32
|
-
@fiber = Fiber.current
|
33
|
-
@controller = spin { control_loop }
|
34
|
-
puts "@fiber: #{@fiber.inspect}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def start
|
38
|
-
fiber = Fiber.current
|
39
|
-
@server = spin(:pdbg_server) do
|
40
|
-
puts("Listening on #{@socket_path}")
|
41
|
-
FileUtils.rm(@socket_path) if File.exists?(@socket_path)
|
42
|
-
socket = UNIXServer.new(@socket_path)
|
43
|
-
fiber << :ready
|
44
|
-
id = 0
|
45
|
-
socket.accept_loop do |client|
|
46
|
-
puts "accepted connection"
|
47
|
-
handle_client(client)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
receive
|
51
|
-
end
|
52
|
-
|
53
|
-
def stop
|
54
|
-
@server.terminate
|
55
|
-
@controller.terminate
|
56
|
-
end
|
57
|
-
|
58
|
-
POLYPHONY_LIB_DIR = File.expand_path('../..', __dir__)
|
59
|
-
def handle_client(client)
|
60
|
-
@client = client
|
61
|
-
puts "trace enabled"
|
62
|
-
end
|
63
|
-
|
64
|
-
def control_loop
|
65
|
-
@cmd = :step
|
66
|
-
loop do
|
67
|
-
case @cmd
|
68
|
-
when :step
|
69
|
-
step
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def step
|
75
|
-
tp = nil
|
76
|
-
fiber = nil
|
77
|
-
while true
|
78
|
-
event = receive
|
79
|
-
fiber = event[:fiber]
|
80
|
-
if fiber == @fiber && event[:kind] == :line && event[:path] !~ /#{POLYPHONY_LIB_DIR}/
|
81
|
-
interact_with_client(event)
|
82
|
-
fiber << :ok
|
83
|
-
fiber.__unpark__
|
84
|
-
return
|
85
|
-
end
|
86
|
-
|
87
|
-
fiber << :ok
|
88
|
-
fiber.__unpark__
|
89
|
-
end
|
90
|
-
rescue => e
|
91
|
-
puts "Uncaught error: #{e.inspect}"
|
92
|
-
@trace&.disable
|
93
|
-
@client = nil
|
94
|
-
end
|
95
|
-
|
96
|
-
def interact_with_client(event)
|
97
|
-
@client.puts event.inspect
|
98
|
-
result = @client.gets&.chomp
|
99
|
-
end
|
100
|
-
|
101
|
-
def handle_tp(trace, tp)
|
102
|
-
return if @in_handle_tp
|
103
|
-
|
104
|
-
process_tp(trace, tp)
|
105
|
-
end
|
106
|
-
|
107
|
-
def process_tp(trace, tp)
|
108
|
-
@in_handle_tp = true
|
109
|
-
if !@client
|
110
|
-
wait_for_client
|
111
|
-
end
|
112
|
-
|
113
|
-
puts "- #{tp.event} #{tp.path}:#{tp.lineno}"
|
114
|
-
|
115
|
-
fiber = Fiber.current
|
116
|
-
fiber.__park__
|
117
|
-
|
118
|
-
@controller << {
|
119
|
-
fiber: fiber,
|
120
|
-
kind: tp.event,
|
121
|
-
path: tp.path,
|
122
|
-
lineno: tp.lineno
|
123
|
-
}
|
124
|
-
receive
|
125
|
-
ensure
|
126
|
-
@in_handle_tp = nil
|
127
|
-
end
|
128
|
-
|
129
|
-
def wait_for_client
|
130
|
-
puts "wait_for_client"
|
131
|
-
sleep 0.1 until @client
|
132
|
-
puts " got client!"
|
133
|
-
msg = @client.gets
|
134
|
-
@client.puts msg
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|