polyphony 0.66 → 0.70
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -1
- data/Gemfile.lock +1 -1
- data/TODO.md +10 -63
- data/bin/pdbg +112 -0
- data/examples/core/await.rb +9 -1
- data/ext/polyphony/backend_common.c +32 -1
- data/ext/polyphony/backend_common.h +4 -1
- data/ext/polyphony/backend_io_uring.c +17 -5
- data/ext/polyphony/backend_libev.c +16 -0
- data/ext/polyphony/fiber.c +20 -0
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -2
- data/ext/polyphony/runqueue.c +4 -0
- data/ext/polyphony/runqueue.h +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +25 -14
- data/ext/polyphony/runqueue_ring_buffer.h +2 -0
- data/ext/polyphony/thread.c +2 -8
- data/lib/polyphony.rb +6 -0
- data/lib/polyphony/debugger.rb +225 -0
- data/lib/polyphony/extensions/debug.rb +1 -1
- data/lib/polyphony/extensions/fiber.rb +66 -69
- data/lib/polyphony/extensions/io.rb +1 -3
- data/lib/polyphony/extensions/openssl.rb +63 -1
- data/lib/polyphony/extensions/socket.rb +3 -3
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +4 -5
- data/test/stress.rb +6 -2
- data/test/test_fiber.rb +30 -11
- data/test/test_process_supervision.rb +38 -9
- data/test/test_supervise.rb +183 -100
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +2 -2
- metadata +4 -2
data/ext/polyphony/fiber.c
CHANGED
@@ -114,6 +114,22 @@ VALUE Fiber_receive_all_pending(VALUE self) {
|
|
114
114
|
return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
|
115
115
|
}
|
116
116
|
|
117
|
+
VALUE Fiber_park(VALUE self) {
|
118
|
+
rb_ivar_set(self, ID_ivar_parked, Qtrue);
|
119
|
+
Backend_park_fiber(BACKEND(), self);
|
120
|
+
return self;
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE Fiber_unpark(VALUE self) {
|
124
|
+
rb_ivar_set(self, ID_ivar_parked, Qnil);
|
125
|
+
Backend_unpark_fiber(BACKEND(), self);
|
126
|
+
return self;
|
127
|
+
}
|
128
|
+
|
129
|
+
VALUE Fiber_parked_p(VALUE self) {
|
130
|
+
return rb_ivar_get(self, ID_ivar_parked);
|
131
|
+
}
|
132
|
+
|
117
133
|
void Init_Fiber() {
|
118
134
|
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
119
135
|
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
@@ -128,6 +144,10 @@ void Init_Fiber() {
|
|
128
144
|
rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
|
129
145
|
rb_define_method(cFiber, "mailbox", Fiber_mailbox, 0);
|
130
146
|
|
147
|
+
rb_define_method(cFiber, "__park__", Fiber_park, 0);
|
148
|
+
rb_define_method(cFiber, "__unpark__", Fiber_unpark, 0);
|
149
|
+
rb_define_method(cFiber, "__parked__?", Fiber_parked_p, 0);
|
150
|
+
|
131
151
|
SYM_dead = ID2SYM(rb_intern("dead"));
|
132
152
|
SYM_running = ID2SYM(rb_intern("running"));
|
133
153
|
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -12,6 +12,7 @@ ID ID_invoke;
|
|
12
12
|
ID ID_new;
|
13
13
|
ID ID_ivar_blocking_mode;
|
14
14
|
ID ID_ivar_io;
|
15
|
+
ID ID_ivar_parked;
|
15
16
|
ID ID_ivar_runnable;
|
16
17
|
ID ID_ivar_running;
|
17
18
|
ID ID_ivar_thread;
|
@@ -160,6 +161,7 @@ void Init_Polyphony() {
|
|
160
161
|
ID_invoke = rb_intern("invoke");
|
161
162
|
ID_ivar_blocking_mode = rb_intern("@blocking_mode");
|
162
163
|
ID_ivar_io = rb_intern("@io");
|
164
|
+
ID_ivar_parked = rb_intern("@parked");
|
163
165
|
ID_ivar_runnable = rb_intern("@runnable");
|
164
166
|
ID_ivar_running = rb_intern("@running");
|
165
167
|
ID_ivar_thread = rb_intern("@thread");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -44,6 +44,7 @@ extern ID ID_invoke;
|
|
44
44
|
extern ID ID_ivar_backend;
|
45
45
|
extern ID ID_ivar_blocking_mode;
|
46
46
|
extern ID ID_ivar_io;
|
47
|
+
extern ID ID_ivar_parked;
|
47
48
|
extern ID ID_ivar_runnable;
|
48
49
|
extern ID ID_ivar_running;
|
49
50
|
extern ID ID_ivar_thread;
|
@@ -115,9 +116,11 @@ VALUE Backend_run_idle_tasks(VALUE self);
|
|
115
116
|
VALUE Backend_switch_fiber(VALUE self);
|
116
117
|
void Backend_schedule_fiber(VALUE thread, VALUE self, VALUE fiber, VALUE value, int prioritize);
|
117
118
|
void Backend_unschedule_fiber(VALUE self, VALUE fiber);
|
119
|
+
void Backend_park_fiber(VALUE self, VALUE fiber);
|
120
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber);
|
118
121
|
|
119
|
-
|
120
|
-
|
122
|
+
void Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
123
|
+
void Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
|
121
124
|
VALUE Thread_switch_fiber(VALUE thread);
|
122
125
|
|
123
126
|
VALUE Polyphony_snooze(VALUE self);
|
data/ext/polyphony/runqueue.c
CHANGED
@@ -40,6 +40,10 @@ inline int runqueue_index_of(runqueue_t *runqueue, VALUE fiber) {
|
|
40
40
|
return runqueue_ring_buffer_index_of(&runqueue->entries, fiber);
|
41
41
|
}
|
42
42
|
|
43
|
+
inline void runqueue_migrate(runqueue_t *src, runqueue_t *dest, VALUE fiber) {
|
44
|
+
runqueue_ring_buffer_migrate(&src->entries, &dest->entries, fiber);
|
45
|
+
}
|
46
|
+
|
43
47
|
inline void runqueue_clear(runqueue_t *runqueue) {
|
44
48
|
runqueue_ring_buffer_clear(&runqueue->entries);
|
45
49
|
}
|
data/ext/polyphony/runqueue.h
CHANGED
@@ -18,6 +18,7 @@ void runqueue_unshift(runqueue_t *runqueue, VALUE fiber, VALUE value, int resche
|
|
18
18
|
runqueue_entry runqueue_shift(runqueue_t *runqueue);
|
19
19
|
void runqueue_delete(runqueue_t *runqueue, VALUE fiber);
|
20
20
|
int runqueue_index_of(runqueue_t *runqueue, VALUE fiber);
|
21
|
+
void runqueue_migrate(runqueue_t *src, runqueue_t *dest, VALUE fiber);
|
21
22
|
void runqueue_clear(runqueue_t *runqueue);
|
22
23
|
unsigned int runqueue_size(runqueue_t *runqueue);
|
23
24
|
unsigned int runqueue_len(runqueue_t *runqueue);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#include "polyphony.h"
|
2
2
|
#include "runqueue_ring_buffer.h"
|
3
3
|
|
4
|
-
void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
4
|
+
inline void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
5
5
|
buffer->size = 1;
|
6
6
|
buffer->count = 0;
|
7
7
|
buffer->entries = malloc(buffer->size * sizeof(runqueue_entry));
|
@@ -9,17 +9,21 @@ void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
|
9
9
|
buffer->tail = 0;
|
10
10
|
}
|
11
11
|
|
12
|
-
void runqueue_ring_buffer_free(runqueue_ring_buffer *buffer) {
|
12
|
+
inline void runqueue_ring_buffer_free(runqueue_ring_buffer *buffer) {
|
13
13
|
free(buffer->entries);
|
14
14
|
}
|
15
15
|
|
16
|
-
int runqueue_ring_buffer_empty_p(runqueue_ring_buffer *buffer) {
|
16
|
+
inline int runqueue_ring_buffer_empty_p(runqueue_ring_buffer *buffer) {
|
17
17
|
return buffer->count == 0;
|
18
18
|
}
|
19
19
|
|
20
|
+
inline void runqueue_ring_buffer_clear(runqueue_ring_buffer *buffer) {
|
21
|
+
buffer->count = buffer->head = buffer->tail = 0;
|
22
|
+
}
|
23
|
+
|
20
24
|
static runqueue_entry nil_runqueue_entry = {(Qnil), (Qnil)};
|
21
25
|
|
22
|
-
runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
26
|
+
inline runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
23
27
|
if (buffer->count == 0) return nil_runqueue_entry;
|
24
28
|
|
25
29
|
runqueue_entry value = buffer->entries[buffer->head];
|
@@ -28,7 +32,7 @@ runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
|
28
32
|
return value;
|
29
33
|
}
|
30
34
|
|
31
|
-
void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
35
|
+
inline void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
32
36
|
unsigned int old_size = buffer->size;
|
33
37
|
buffer->size = old_size == 1 ? 4 : old_size * 2;
|
34
38
|
buffer->entries = realloc(buffer->entries, buffer->size * sizeof(runqueue_entry));
|
@@ -37,7 +41,7 @@ void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
|
37
41
|
buffer->tail = buffer->head + buffer->count;
|
38
42
|
}
|
39
43
|
|
40
|
-
void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
44
|
+
inline void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
41
45
|
if (buffer->count == buffer->size) runqueue_ring_buffer_resize(buffer);
|
42
46
|
|
43
47
|
buffer->head = (buffer->head - 1) % buffer->size;
|
@@ -46,7 +50,7 @@ void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VAL
|
|
46
50
|
buffer->count++;
|
47
51
|
}
|
48
52
|
|
49
|
-
void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
53
|
+
inline void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
50
54
|
if (buffer->count == buffer->size) runqueue_ring_buffer_resize(buffer);
|
51
55
|
|
52
56
|
buffer->entries[buffer->tail].fiber = fiber;
|
@@ -55,14 +59,14 @@ void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE
|
|
55
59
|
buffer->count++;
|
56
60
|
}
|
57
61
|
|
58
|
-
void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
62
|
+
inline void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
59
63
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
60
64
|
rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].fiber);
|
61
65
|
rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].value);
|
62
66
|
}
|
63
67
|
}
|
64
68
|
|
65
|
-
void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int idx) {
|
69
|
+
inline void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int idx) {
|
66
70
|
for (unsigned int idx2 = idx; idx2 != buffer->tail; idx2 = (idx2 + 1) % buffer->size) {
|
67
71
|
buffer->entries[idx2] = buffer->entries[(idx2 + 1) % buffer->size];
|
68
72
|
}
|
@@ -70,7 +74,7 @@ void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int i
|
|
70
74
|
buffer->tail = (buffer->tail - 1) % buffer->size;
|
71
75
|
}
|
72
76
|
|
73
|
-
void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
77
|
+
inline void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
74
78
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
75
79
|
unsigned int idx = (buffer->head + i) % buffer->size;
|
76
80
|
if (buffer->entries[idx].fiber == fiber) {
|
@@ -80,7 +84,7 @@ void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
|
80
84
|
}
|
81
85
|
}
|
82
86
|
|
83
|
-
int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
87
|
+
inline int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
84
88
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
85
89
|
unsigned int idx = (buffer->head + i) % buffer->size;
|
86
90
|
if (buffer->entries[idx].fiber == fiber)
|
@@ -89,6 +93,13 @@ int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
|
89
93
|
return -1;
|
90
94
|
}
|
91
95
|
|
92
|
-
void
|
93
|
-
|
94
|
-
|
96
|
+
inline void runqueue_ring_buffer_migrate(runqueue_ring_buffer *src, runqueue_ring_buffer *dest, VALUE fiber) {
|
97
|
+
for (unsigned int i = 0; i < src->count; i++) {
|
98
|
+
unsigned int idx = (src->head + i) % src->size;
|
99
|
+
if (src->entries[idx].fiber == fiber) {
|
100
|
+
runqueue_ring_buffer_push(dest, src->entries[idx].fiber, src->entries[idx].value);
|
101
|
+
runqueue_ring_buffer_delete_at(src, idx);
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
@@ -29,4 +29,6 @@ void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE
|
|
29
29
|
void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber);
|
30
30
|
int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber);
|
31
31
|
|
32
|
+
void runqueue_ring_buffer_migrate(runqueue_ring_buffer *src, runqueue_ring_buffer *dest, VALUE fiber);
|
33
|
+
|
32
34
|
#endif /* RUNQUEUE_RING_BUFFER_H */
|
data/ext/polyphony/thread.c
CHANGED
@@ -22,14 +22,12 @@ VALUE Thread_fiber_unschedule(VALUE self, VALUE fiber) {
|
|
22
22
|
return self;
|
23
23
|
}
|
24
24
|
|
25
|
-
|
25
|
+
inline void Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
26
26
|
schedule_fiber(self, fiber, value, 0);
|
27
|
-
return self;
|
28
27
|
}
|
29
28
|
|
30
|
-
|
29
|
+
inline void Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value) {
|
31
30
|
schedule_fiber(self, fiber, value, 1);
|
32
|
-
return self;
|
33
31
|
}
|
34
32
|
|
35
33
|
VALUE Thread_switch_fiber(VALUE self) {
|
@@ -61,10 +59,6 @@ VALUE Thread_class_backend(VALUE _self) {
|
|
61
59
|
void Init_Thread() {
|
62
60
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
63
61
|
rb_define_method(rb_cThread, "schedule_and_wakeup", Thread_fiber_schedule_and_wakeup, 2);
|
64
|
-
|
65
|
-
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 2);
|
66
|
-
rb_define_method(rb_cThread, "schedule_fiber_with_priority",
|
67
|
-
Thread_schedule_fiber_with_priority, 2);
|
68
62
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
69
63
|
rb_define_method(rb_cThread, "fiber_unschedule", Thread_fiber_unschedule, 1);
|
70
64
|
|
data/lib/polyphony.rb
CHANGED
@@ -121,3 +121,9 @@ end
|
|
121
121
|
|
122
122
|
Polyphony.install_terminating_signal_handlers
|
123
123
|
Polyphony.install_at_exit_handler
|
124
|
+
|
125
|
+
if (debug_socket_path = ENV['POLYPHONY_DEBUG_SOCKET_PATH'])
|
126
|
+
puts "Starting debug server on #{debug_socket_path}"
|
127
|
+
require 'polyphony/debugger'
|
128
|
+
Polyphony.start_debug_server(debug_socket_path)
|
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
|