polyphony 0.66 → 0.70
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 +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
|