polyphony 0.74 → 0.78
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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +1 -1
- data/examples/core/trap1.rb +21 -0
- data/examples/core/trap2.rb +14 -0
- data/ext/polyphony/backend_common.c +9 -1
- data/ext/polyphony/backend_common.h +1 -0
- data/ext/polyphony/backend_io_uring.c +33 -29
- data/ext/polyphony/backend_libev.c +5 -0
- data/ext/polyphony/fiber.c +1 -1
- data/ext/polyphony/polyphony.c +5 -4
- data/ext/polyphony/polyphony.h +4 -3
- data/ext/polyphony/queue.c +82 -6
- data/ext/test_eintr.c +50 -0
- data/lib/polyphony/core/debug.rb +2 -0
- data/lib/polyphony/extensions/fiber.rb +27 -5
- data/lib/polyphony/extensions/openssl.rb +5 -1
- data/lib/polyphony/extensions/socket.rb +5 -11
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -0
- data/test/helper.rb +2 -6
- data/test/stress.rb +1 -1
- data/test/test_fiber.rb +6 -4
- data/test/test_queue.rb +103 -1
- data/test/test_signal.rb +57 -0
- data/test/test_supervise.rb +27 -0
- data/test/test_thread.rb +1 -1
- data/test/test_timer.rb +1 -1
- data/test/test_trace.rb +7 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51eecc20956cb4f1a35a7f6510dea2730652700e99d29c7d42ade201a119ea2e
|
4
|
+
data.tar.gz: bc2b57dc2cc5a8918bba1d8bf526cdbe23f44d134f9bdca5018b9e9e66930f91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21c446f9a6fa032577b245e6de5155832c8e6932d6c17e58824a55923c82be014453b64b29ccbb66fe5d01cde8622d3275664acda403637954f1e7e6851e93c7
|
7
|
+
data.tar.gz: a57831fe861ac51fa43692b66175291a457077822cdb5f795a093fca1e44bf95fb2b6a312cfe8a6c2b3c3e873319ffd03436e6236874a6acdd45843a21bc4981
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## 0.78 2022-02-16
|
2
|
+
|
3
|
+
- Fix Polyphony::Queue API compatibility (#72)
|
4
|
+
|
5
|
+
## 0.77 2022-02-07
|
6
|
+
|
7
|
+
- Fix behaviour of signal traps (#71)
|
8
|
+
|
9
|
+
## 0.76 2022-02-06
|
10
|
+
|
11
|
+
- Comment out `Backend_close` API (#70)
|
12
|
+
|
13
|
+
## 0.75 2022-02-04
|
14
|
+
|
15
|
+
- Fix handling of MoveOn on main fiber of forked process
|
16
|
+
- Ensure SSLSocket underlying socket is in nonblocking mode
|
17
|
+
- Add `Polyphony.backend_verify_blocking_mode` API
|
18
|
+
- Fix address resolution for hostnames with IPv6 address
|
19
|
+
- Improve behaviour of OOB fiber
|
20
|
+
- Include caller in `fiber_switchpoint` trace
|
21
|
+
|
1
22
|
## 0.74 2022-02-01
|
2
23
|
|
3
24
|
- Add support for IPv6 (#69)
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
pid = Process.pid
|
4
|
+
fork do
|
5
|
+
sleep 1
|
6
|
+
Process.kill('SIGINT', pid)
|
7
|
+
# sleep 10
|
8
|
+
# Process.kill(-9, pid)
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'bundler/setup'
|
12
|
+
require 'polyphony'
|
13
|
+
|
14
|
+
Thread.backend.trace_proc = proc { |*e| STDOUT.orig_write("#{e.inspect}\n") }
|
15
|
+
trap('SIGINT') { STDOUT.orig_write("* recv SIGINT\n") }
|
16
|
+
# trap('SIGCHLD') { STDOUT.orig_write("* recv SIGCHLD\n") }
|
17
|
+
STDOUT.orig_write("* pre gets\n")
|
18
|
+
# STDIN.wait_readable
|
19
|
+
s = gets
|
20
|
+
p s
|
21
|
+
STDOUT.orig_write("* post gets\n")
|
@@ -64,7 +64,8 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
64
64
|
unsigned int idle_tasks_run_count = 0;
|
65
65
|
|
66
66
|
base->switch_count++;
|
67
|
-
|
67
|
+
if (SHOULD_TRACE(base))
|
68
|
+
TRACE(base, 3, SYM_fiber_switchpoint, current_fiber, CALLER());
|
68
69
|
|
69
70
|
while (1) {
|
70
71
|
next = runqueue_shift(&base->runqueue);
|
@@ -415,6 +416,13 @@ VALUE Backend_stats(VALUE self) {
|
|
415
416
|
return stats;
|
416
417
|
}
|
417
418
|
|
419
|
+
VALUE Backend_verify_blocking_mode(VALUE self, VALUE io, VALUE blocking) {
|
420
|
+
rb_io_t *fptr;
|
421
|
+
GetOpenFile(io, fptr);
|
422
|
+
io_verify_blocking_mode(fptr, io, blocking);
|
423
|
+
return self;
|
424
|
+
}
|
425
|
+
|
418
426
|
void backend_setup_stats_symbols() {
|
419
427
|
SYM_runqueue_size = ID2SYM(rb_intern("runqueue_size"));
|
420
428
|
SYM_runqueue_length = ID2SYM(rb_intern("runqueue_length"));
|
@@ -112,6 +112,7 @@ VALUE Backend_timeout_ensure_safe(VALUE arg);
|
|
112
112
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
113
113
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
114
114
|
VALUE Backend_stats(VALUE self);
|
115
|
+
VALUE Backend_verify_blocking_mode(VALUE self, VALUE io, VALUE blocking);
|
115
116
|
void backend_run_idle_tasks(struct Backend_base *base);
|
116
117
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
117
118
|
void backend_setup_stats_symbols();
|
@@ -191,10 +191,14 @@ void io_uring_backend_poll(Backend_t *backend) {
|
|
191
191
|
io_uring_submit(&backend->ring);
|
192
192
|
}
|
193
193
|
|
194
|
+
wait_cqe:
|
194
195
|
backend->base.currently_polling = 1;
|
195
196
|
rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
|
196
197
|
backend->base.currently_polling = 0;
|
197
|
-
if (poll_ctx.result < 0)
|
198
|
+
if (poll_ctx.result < 0) {
|
199
|
+
if (poll_ctx.result == -EINTR && runqueue_empty_p(&backend->base.runqueue)) goto wait_cqe;
|
200
|
+
return;
|
201
|
+
}
|
198
202
|
|
199
203
|
io_uring_backend_handle_completion(poll_ctx.cqe, backend);
|
200
204
|
io_uring_cqe_seen(&backend->ring, poll_ctx.cqe);
|
@@ -1017,39 +1021,39 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
1017
1021
|
return self;
|
1018
1022
|
}
|
1019
1023
|
|
1020
|
-
VALUE Backend_close(VALUE self, VALUE io) {
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1024
|
+
// VALUE Backend_close(VALUE self, VALUE io) {
|
1025
|
+
// Backend_t *backend;
|
1026
|
+
// rb_io_t *fptr;
|
1027
|
+
// VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
1028
|
+
// VALUE resume_value = Qnil;
|
1029
|
+
// op_context_t *ctx;
|
1030
|
+
// struct io_uring_sqe *sqe;
|
1031
|
+
// int result;
|
1032
|
+
// int completed;
|
1029
1033
|
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1034
|
+
// if (underlying_io != Qnil) io = underlying_io;
|
1035
|
+
// GetBackend(self, backend);
|
1036
|
+
// GetOpenFile(io, fptr);
|
1033
1037
|
|
1034
|
-
|
1038
|
+
// if (fptr->fd < 0) return Qnil;
|
1035
1039
|
|
1036
|
-
|
1040
|
+
// io_unset_nonblock(fptr, io);
|
1037
1041
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1042
|
+
// ctx = context_store_acquire(&backend->store, OP_CLOSE);
|
1043
|
+
// sqe = io_uring_get_sqe(&backend->ring);
|
1044
|
+
// io_uring_prep_close(sqe, fptr->fd);
|
1045
|
+
// result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
1046
|
+
// completed = context_store_release(&backend->store, ctx);
|
1047
|
+
// RAISE_IF_EXCEPTION(resume_value);
|
1048
|
+
// if (!completed) return resume_value;
|
1049
|
+
// RB_GC_GUARD(resume_value);
|
1046
1050
|
|
1047
|
-
|
1051
|
+
// if (result < 0) rb_syserr_fail(-result, strerror(-result));
|
1048
1052
|
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
}
|
1053
|
+
// fptr_finalize(fptr);
|
1054
|
+
// // fptr->fd = -1;
|
1055
|
+
// return io;
|
1056
|
+
// }
|
1053
1057
|
|
1054
1058
|
inline struct __kernel_timespec double_to_timespec(double duration) {
|
1055
1059
|
double duration_integral;
|
@@ -1640,7 +1644,7 @@ void Init_Backend() {
|
|
1640
1644
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1641
1645
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1642
1646
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1643
|
-
rb_define_method(cBackend, "close", Backend_close, 1);
|
1647
|
+
// rb_define_method(cBackend, "close", Backend_close, 1);
|
1644
1648
|
|
1645
1649
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
1646
1650
|
SYM_send = ID2SYM(rb_intern("send"));
|
@@ -169,9 +169,14 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
169
169
|
backend->base.poll_count++;
|
170
170
|
|
171
171
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
172
|
+
|
173
|
+
ev_run:
|
172
174
|
backend->base.currently_polling = 1;
|
175
|
+
errno = 0;
|
173
176
|
ev_run(backend->ev_loop, blocking == Qtrue ? EVRUN_ONCE : EVRUN_NOWAIT);
|
174
177
|
backend->base.currently_polling = 0;
|
178
|
+
if (errno == EINTR && runqueue_empty_p(&backend->base.runqueue)) goto ev_run;
|
179
|
+
|
175
180
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
176
181
|
|
177
182
|
return self;
|
data/ext/polyphony/fiber.c
CHANGED
data/ext/polyphony/polyphony.c
CHANGED
@@ -125,9 +125,9 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
|
|
125
125
|
return Backend_write_m(argc, argv, BACKEND());
|
126
126
|
}
|
127
127
|
|
128
|
-
VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
129
|
-
|
130
|
-
}
|
128
|
+
// VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
129
|
+
// return Backend_close(BACKEND(), io);
|
130
|
+
// }
|
131
131
|
|
132
132
|
void Init_Polyphony() {
|
133
133
|
mPolyphony = rb_define_module("Polyphony");
|
@@ -153,7 +153,8 @@ void Init_Polyphony() {
|
|
153
153
|
rb_define_singleton_method(mPolyphony, "backend_wait_io", Polyphony_backend_wait_io, 2);
|
154
154
|
rb_define_singleton_method(mPolyphony, "backend_waitpid", Polyphony_backend_waitpid, 1);
|
155
155
|
rb_define_singleton_method(mPolyphony, "backend_write", Polyphony_backend_write, -1);
|
156
|
-
rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
|
156
|
+
// rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
|
157
|
+
rb_define_singleton_method(mPolyphony, "backend_verify_blocking_mode", Backend_verify_blocking_mode, 2);
|
157
158
|
|
158
159
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
159
160
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -10,7 +10,8 @@
|
|
10
10
|
// debugging
|
11
11
|
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
12
12
|
#define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
|
13
|
-
#define
|
13
|
+
#define CALLER() rb_funcall(rb_mKernel, rb_intern("caller"), 0)
|
14
|
+
#define TRACE_CALLER() INSPECT("caller: ", CALLER())
|
14
15
|
#define TRACE_C_STACK() { \
|
15
16
|
void *entries[10]; \
|
16
17
|
size_t size = backtrace(entries, 10); \
|
@@ -73,7 +74,7 @@ void Fiber_make_runnable(VALUE fiber, VALUE value);
|
|
73
74
|
|
74
75
|
VALUE Queue_push(VALUE self, VALUE value);
|
75
76
|
VALUE Queue_unshift(VALUE self, VALUE value);
|
76
|
-
VALUE Queue_shift(VALUE self);
|
77
|
+
VALUE Queue_shift(int argc,VALUE *argv, VALUE self);
|
77
78
|
VALUE Queue_shift_all(VALUE self);
|
78
79
|
|
79
80
|
void Runqueue_push(VALUE self, VALUE fiber, VALUE value, int reschedule);
|
@@ -113,7 +114,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise);
|
|
113
114
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write);
|
114
115
|
VALUE Backend_waitpid(VALUE self, VALUE pid);
|
115
116
|
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self);
|
116
|
-
VALUE Backend_close(VALUE self, VALUE io);
|
117
|
+
// VALUE Backend_close(VALUE self, VALUE io);
|
117
118
|
|
118
119
|
VALUE Backend_poll(VALUE self, VALUE blocking);
|
119
120
|
VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
|
data/ext/polyphony/queue.c
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#include "ring_buffer.h"
|
3
3
|
|
4
4
|
typedef struct queue {
|
5
|
+
unsigned int closed;
|
5
6
|
ring_buffer values;
|
6
7
|
ring_buffer shift_queue;
|
7
8
|
ring_buffer push_queue;
|
@@ -9,6 +10,8 @@ typedef struct queue {
|
|
9
10
|
} Queue_t;
|
10
11
|
|
11
12
|
VALUE cQueue = Qnil;
|
13
|
+
VALUE cClosedQueueError = Qnil;
|
14
|
+
VALUE cThreadError = Qnil;
|
12
15
|
|
13
16
|
static void Queue_mark(void *ptr) {
|
14
17
|
Queue_t *queue = ptr;
|
@@ -49,6 +52,7 @@ static VALUE Queue_initialize(int argc, VALUE *argv, VALUE self) {
|
|
49
52
|
Queue_t *queue;
|
50
53
|
GetQueue(self, queue);
|
51
54
|
|
55
|
+
queue->closed = 0;
|
52
56
|
ring_buffer_init(&queue->values);
|
53
57
|
ring_buffer_init(&queue->shift_queue);
|
54
58
|
ring_buffer_init(&queue->push_queue);
|
@@ -99,6 +103,9 @@ VALUE Queue_push(VALUE self, VALUE value) {
|
|
99
103
|
Queue_t *queue;
|
100
104
|
GetQueue(self, queue);
|
101
105
|
|
106
|
+
if (queue->closed)
|
107
|
+
rb_raise(cClosedQueueError, "queue closed");
|
108
|
+
|
102
109
|
if (queue->capacity) capped_queue_block_push(queue);
|
103
110
|
|
104
111
|
queue_schedule_first_blocked_fiber(&queue->shift_queue);
|
@@ -111,6 +118,9 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
|
|
111
118
|
Queue_t *queue;
|
112
119
|
GetQueue(self, queue);
|
113
120
|
|
121
|
+
if (queue->closed)
|
122
|
+
rb_raise(cClosedQueueError, "queue closed");
|
123
|
+
|
114
124
|
if (queue->capacity) capped_queue_block_push(queue);
|
115
125
|
|
116
126
|
queue_schedule_first_blocked_fiber(&queue->shift_queue);
|
@@ -119,14 +129,25 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
|
|
119
129
|
return self;
|
120
130
|
}
|
121
131
|
|
122
|
-
VALUE
|
123
|
-
|
132
|
+
VALUE Queue_shift_nonblock(Queue_t *queue) {
|
133
|
+
if (queue->values.count) {
|
134
|
+
VALUE value = ring_buffer_shift(&queue->values);
|
135
|
+
if ((queue->capacity) && (queue->capacity > queue->values.count))
|
136
|
+
queue_schedule_first_blocked_fiber(&queue->push_queue);
|
137
|
+
RB_GC_GUARD(value);
|
138
|
+
return value;
|
139
|
+
}
|
140
|
+
rb_raise(cThreadError, "queue empty");
|
141
|
+
}
|
142
|
+
|
143
|
+
VALUE Queue_shift_block(Queue_t *queue) {
|
124
144
|
VALUE fiber = rb_fiber_current();
|
125
145
|
VALUE thread = rb_thread_current();
|
126
146
|
VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
|
127
147
|
VALUE value;
|
128
148
|
|
129
|
-
|
149
|
+
if (queue->closed && !queue->values.count)
|
150
|
+
rb_raise(cClosedQueueError, "queue closed");
|
130
151
|
|
131
152
|
while (1) {
|
132
153
|
VALUE switchpoint_result;
|
@@ -140,6 +161,7 @@ VALUE Queue_shift(VALUE self) {
|
|
140
161
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
141
162
|
RB_GC_GUARD(switchpoint_result);
|
142
163
|
if (queue->values.count) break;
|
164
|
+
if (queue->closed) return Qnil;
|
143
165
|
}
|
144
166
|
value = ring_buffer_shift(&queue->values);
|
145
167
|
if ((queue->capacity) && (queue->capacity > queue->values.count))
|
@@ -148,6 +170,16 @@ VALUE Queue_shift(VALUE self) {
|
|
148
170
|
return value;
|
149
171
|
}
|
150
172
|
|
173
|
+
VALUE Queue_shift(int argc,VALUE *argv, VALUE self) {
|
174
|
+
int nonblock = argc && RTEST(argv[0]);
|
175
|
+
Queue_t *queue;
|
176
|
+
GetQueue(self, queue);
|
177
|
+
|
178
|
+
return nonblock ?
|
179
|
+
Queue_shift_nonblock(queue) :
|
180
|
+
Queue_shift_block(queue);
|
181
|
+
}
|
182
|
+
|
151
183
|
VALUE Queue_delete(VALUE self, VALUE value) {
|
152
184
|
Queue_t *queue;
|
153
185
|
GetQueue(self, queue);
|
@@ -244,6 +276,13 @@ VALUE Queue_pending_p(VALUE self) {
|
|
244
276
|
return (queue->shift_queue.count) ? Qtrue : Qfalse;
|
245
277
|
}
|
246
278
|
|
279
|
+
VALUE Queue_num_waiting(VALUE self) {
|
280
|
+
Queue_t *queue;
|
281
|
+
GetQueue(self, queue);
|
282
|
+
|
283
|
+
return INT2NUM(queue->shift_queue.count);
|
284
|
+
}
|
285
|
+
|
247
286
|
VALUE Queue_size_m(VALUE self) {
|
248
287
|
Queue_t *queue;
|
249
288
|
GetQueue(self, queue);
|
@@ -251,20 +290,54 @@ VALUE Queue_size_m(VALUE self) {
|
|
251
290
|
return INT2NUM(queue->values.count);
|
252
291
|
}
|
253
292
|
|
293
|
+
VALUE Queue_closed_p(VALUE self) {
|
294
|
+
Queue_t *queue;
|
295
|
+
GetQueue(self, queue);
|
296
|
+
|
297
|
+
return (queue->closed) ? Qtrue : Qfalse;
|
298
|
+
}
|
299
|
+
|
300
|
+
VALUE Queue_close(VALUE self) {
|
301
|
+
Queue_t *queue;
|
302
|
+
GetQueue(self, queue);
|
303
|
+
|
304
|
+
if (queue->closed) goto end;
|
305
|
+
queue->closed = 1;
|
306
|
+
|
307
|
+
// release all fibers waiting on `#shift`
|
308
|
+
while (queue->shift_queue.count) {
|
309
|
+
VALUE fiber = ring_buffer_shift(&queue->shift_queue);
|
310
|
+
if (fiber == Qnil) break;
|
311
|
+
Fiber_make_runnable(fiber, Qnil);
|
312
|
+
}
|
313
|
+
|
314
|
+
end:
|
315
|
+
return self;
|
316
|
+
}
|
317
|
+
|
254
318
|
void Init_Queue() {
|
319
|
+
cClosedQueueError = rb_const_get(rb_cObject, rb_intern("ClosedQueueError"));
|
320
|
+
cThreadError = rb_const_get(rb_cObject, rb_intern("ThreadError"));
|
321
|
+
|
255
322
|
cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cObject);
|
256
323
|
rb_define_alloc_func(cQueue, Queue_allocate);
|
257
324
|
|
258
325
|
rb_define_method(cQueue, "initialize", Queue_initialize, -1);
|
259
326
|
rb_define_method(cQueue, "push", Queue_push, 1);
|
260
327
|
rb_define_method(cQueue, "<<", Queue_push, 1);
|
328
|
+
rb_define_method(cQueue, "enq", Queue_push, 1);
|
261
329
|
rb_define_method(cQueue, "unshift", Queue_unshift, 1);
|
262
330
|
|
263
|
-
rb_define_method(cQueue, "shift", Queue_shift,
|
264
|
-
rb_define_method(cQueue, "pop", Queue_shift,
|
331
|
+
rb_define_method(cQueue, "shift", Queue_shift, -1);
|
332
|
+
rb_define_method(cQueue, "pop", Queue_shift, -1);
|
333
|
+
rb_define_method(cQueue, "deq", Queue_shift, -1);
|
334
|
+
|
265
335
|
rb_define_method(cQueue, "delete", Queue_delete, 1);
|
266
336
|
rb_define_method(cQueue, "clear", Queue_clear, 0);
|
267
337
|
|
338
|
+
rb_define_method(cQueue, "size", Queue_size_m, 0);
|
339
|
+
rb_define_method(cQueue, "length", Queue_size_m, 0);
|
340
|
+
|
268
341
|
rb_define_method(cQueue, "cap", Queue_cap, 1);
|
269
342
|
rb_define_method(cQueue, "capped?", Queue_capped_p, 0);
|
270
343
|
|
@@ -273,5 +346,8 @@ void Init_Queue() {
|
|
273
346
|
rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
|
274
347
|
rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
|
275
348
|
rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
|
276
|
-
rb_define_method(cQueue, "
|
349
|
+
rb_define_method(cQueue, "num_waiting", Queue_num_waiting, 0);
|
350
|
+
|
351
|
+
rb_define_method(cQueue, "closed?", Queue_closed_p, 0);
|
352
|
+
rb_define_method(cQueue, "close", Queue_close, 0);
|
277
353
|
}
|
data/ext/test_eintr.c
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <unistd.h>
|
3
|
+
#include <signal.h>
|
4
|
+
#include <poll.h>
|
5
|
+
#include "./liburing/liburing.h"
|
6
|
+
|
7
|
+
void sig_handler(int sig) {
|
8
|
+
printf("handle signal %d!\n", sig);
|
9
|
+
}
|
10
|
+
|
11
|
+
int main(int argc, char *argv[])
|
12
|
+
{
|
13
|
+
int pid = getpid();
|
14
|
+
int child_pid = fork();
|
15
|
+
if (!child_pid) {
|
16
|
+
sleep(1);
|
17
|
+
kill(pid, SIGINT);
|
18
|
+
sleep(1);
|
19
|
+
kill(pid, SIGINT);
|
20
|
+
}
|
21
|
+
else {
|
22
|
+
struct sigaction sa;
|
23
|
+
|
24
|
+
sa.sa_handler = sig_handler;
|
25
|
+
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;//0;
|
26
|
+
sigemptyset(&sa.sa_mask);
|
27
|
+
sigaction(SIGINT, &sa, NULL);
|
28
|
+
|
29
|
+
printf("pid: %d\n", pid);
|
30
|
+
|
31
|
+
struct io_uring ring;
|
32
|
+
int ret = io_uring_queue_init(16, &ring, 0);
|
33
|
+
printf("io_uring_queue_init: %d\n", ret);
|
34
|
+
|
35
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
|
36
|
+
io_uring_prep_poll_add(sqe, STDIN_FILENO, POLLIN);
|
37
|
+
ret = io_uring_submit(&ring);
|
38
|
+
printf("io_uring_submit: %d\n", ret);
|
39
|
+
|
40
|
+
struct io_uring_cqe *cqe;
|
41
|
+
|
42
|
+
wait_cqe:
|
43
|
+
ret = io_uring_wait_cqe(&ring, &cqe);
|
44
|
+
printf("io_uring_wait_cqe: %d\n", ret);
|
45
|
+
if (ret == -EINTR) goto wait_cqe;
|
46
|
+
|
47
|
+
printf("done\n");
|
48
|
+
return 0;
|
49
|
+
}
|
50
|
+
}
|
data/lib/polyphony/core/debug.rb
CHANGED
@@ -6,6 +6,8 @@ module ::Kernel
|
|
6
6
|
def format_trace(args)
|
7
7
|
if args.size > 1 && args.first.is_a?(String)
|
8
8
|
format("%s: %p\n", args.shift, args.size == 1 ? args.first : args)
|
9
|
+
elsif args.size == 1 && args.first.is_a?(String)
|
10
|
+
"#{args.first}\n"
|
9
11
|
else
|
10
12
|
format("%p\n", args.size == 1 ? args.first : args)
|
11
13
|
end
|
@@ -248,13 +248,27 @@ module Polyphony
|
|
248
248
|
# also be scheduled with priority. This method is mainly used trapping
|
249
249
|
# signals (see also the patched `Kernel#trap`)
|
250
250
|
def schedule_priority_oob_fiber(&block)
|
251
|
-
|
251
|
+
oob_fiber = Fiber.new do
|
252
252
|
Fiber.current.setup_raw
|
253
|
-
block.call
|
253
|
+
result = block.call
|
254
254
|
rescue Exception => e
|
255
255
|
Thread.current.schedule_and_wakeup(Thread.main.main_fiber, e)
|
256
|
+
result = e
|
257
|
+
ensure
|
258
|
+
Thread.backend.trace(:fiber_terminate, Fiber.current, result)
|
259
|
+
suspend
|
256
260
|
end
|
257
|
-
|
261
|
+
prepare_oob_fiber(oob_fiber, block)
|
262
|
+
Thread.backend.trace(:fiber_create, oob_fiber)
|
263
|
+
oob_fiber.schedule_with_priority(nil)
|
264
|
+
end
|
265
|
+
|
266
|
+
def prepare_oob_fiber(fiber, block)
|
267
|
+
fiber.oob = true
|
268
|
+
fiber.tag = :oob
|
269
|
+
fiber.thread = Thread.current
|
270
|
+
location = block.source_location
|
271
|
+
fiber.set_caller(["#{location.join(':')}"])
|
258
272
|
end
|
259
273
|
end
|
260
274
|
|
@@ -449,7 +463,7 @@ class ::Fiber
|
|
449
463
|
|
450
464
|
extend Polyphony::FiberControlClassMethods
|
451
465
|
|
452
|
-
attr_accessor :tag, :thread, :parent
|
466
|
+
attr_accessor :tag, :thread, :parent, :oob
|
453
467
|
attr_reader :result
|
454
468
|
|
455
469
|
def running?
|
@@ -466,7 +480,11 @@ class ::Fiber
|
|
466
480
|
alias_method :to_s, :inspect
|
467
481
|
|
468
482
|
def location
|
469
|
-
|
483
|
+
if @oob
|
484
|
+
"#{@caller[0]} (oob)"
|
485
|
+
else
|
486
|
+
@caller ? @caller[0] : '(root)'
|
487
|
+
end
|
470
488
|
end
|
471
489
|
|
472
490
|
def caller
|
@@ -478,6 +496,10 @@ class ::Fiber
|
|
478
496
|
end
|
479
497
|
end
|
480
498
|
|
499
|
+
def set_caller(o)
|
500
|
+
@caller = o
|
501
|
+
end
|
502
|
+
|
481
503
|
def main?
|
482
504
|
@main
|
483
505
|
end
|
@@ -38,8 +38,10 @@ class ::OpenSSL::SSL::SSLSocket
|
|
38
38
|
|
39
39
|
alias_method :orig_sysread, :sysread
|
40
40
|
def sysread(maxlen, buf = +'')
|
41
|
+
# ensure socket is non blocking
|
42
|
+
Polyphony.backend_verify_blocking_mode(io, false)
|
41
43
|
while true
|
42
|
-
case (result =
|
44
|
+
case (result = sysread_nonblock(maxlen, buf, exception: false))
|
43
45
|
when :wait_readable then Polyphony.backend_wait_io(io, false)
|
44
46
|
when :wait_writable then Polyphony.backend_wait_io(io, true)
|
45
47
|
else return result
|
@@ -49,6 +51,8 @@ class ::OpenSSL::SSL::SSLSocket
|
|
49
51
|
|
50
52
|
alias_method :orig_syswrite, :syswrite
|
51
53
|
def syswrite(buf)
|
54
|
+
# ensure socket is non blocking
|
55
|
+
Polyphony.backend_verify_blocking_mode(io, false)
|
52
56
|
while true
|
53
57
|
case (result = write_nonblock(buf, exception: false))
|
54
58
|
when :wait_readable then Polyphony.backend_wait_io(io, false)
|
@@ -124,12 +124,9 @@ class ::TCPSocket
|
|
124
124
|
new(*args)
|
125
125
|
end
|
126
126
|
|
127
|
-
def address_family(host)
|
128
|
-
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
129
|
-
end
|
130
|
-
|
131
127
|
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
132
|
-
|
128
|
+
remote_addr = Addrinfo.tcp(remote_host, remote_port)
|
129
|
+
@io = Socket.new remote_addr.afamily, Socket::SOCK_STREAM
|
133
130
|
if local_host && local_port
|
134
131
|
addr = Addrinfo.tcp(local_host, local_port)
|
135
132
|
@io.bind(addr)
|
@@ -231,13 +228,10 @@ end
|
|
231
228
|
|
232
229
|
# Override stock TCPServer code by encapsulating a Socket instance.
|
233
230
|
class ::TCPServer
|
234
|
-
def address_family(host)
|
235
|
-
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
236
|
-
end
|
237
|
-
|
238
231
|
def initialize(hostname = nil, port = 0)
|
239
|
-
|
240
|
-
@io.
|
232
|
+
addr = Addrinfo.tcp(hostname, port)
|
233
|
+
@io = Socket.new addr.afamily, Socket::SOCK_STREAM
|
234
|
+
@io.bind(addr)
|
241
235
|
@io.listen(0)
|
242
236
|
end
|
243
237
|
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -21,10 +21,6 @@ IS_LINUX = RUBY_PLATFORM =~ /linux/
|
|
21
21
|
# Minitest::Reporters::SpecReporter.new
|
22
22
|
# ]
|
23
23
|
|
24
|
-
class ::Fiber
|
25
|
-
attr_writer :auto_watcher
|
26
|
-
end
|
27
|
-
|
28
24
|
module ::Kernel
|
29
25
|
def trace(*args)
|
30
26
|
STDOUT.orig_write(format_trace(args))
|
@@ -50,16 +46,16 @@ class MiniTest::Test
|
|
50
46
|
Thread.current.backend.finalize
|
51
47
|
Thread.current.backend = Polyphony::Backend.new
|
52
48
|
sleep 0.001
|
49
|
+
@__stamp = Time.now
|
53
50
|
end
|
54
51
|
|
55
52
|
def teardown
|
56
|
-
# trace "* teardown #{self.name}"
|
53
|
+
# trace "* teardown #{self.name} (#{Time.now - @__stamp}s)"
|
57
54
|
Fiber.current.shutdown_all_children
|
58
55
|
if Fiber.current.children.size > 0
|
59
56
|
puts "Children left after #{self.name}: #{Fiber.current.children.inspect}"
|
60
57
|
exit!
|
61
58
|
end
|
62
|
-
Fiber.current.instance_variable_set(:@auto_watcher, nil)
|
63
59
|
rescue => e
|
64
60
|
puts e
|
65
61
|
puts e.backtrace.join("\n")
|
data/test/stress.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
count = ARGV[0] ? ARGV[0].to_i : 100
|
4
4
|
test_name = ARGV[1]
|
5
5
|
|
6
|
-
$test_cmd = +'ruby test/run.rb --name
|
6
|
+
$test_cmd = +'ruby test/run.rb --name test_cross_thread_send_receive'
|
7
7
|
if test_name
|
8
8
|
$test_cmd << " --name #{test_name}"
|
9
9
|
end
|
data/test/test_fiber.rb
CHANGED
@@ -923,18 +923,20 @@ class MailboxTest < MiniTest::Test
|
|
923
923
|
def test_cross_thread_send_receive
|
924
924
|
ping_receive_buffer = []
|
925
925
|
pong_receive_buffer = []
|
926
|
+
master = Fiber.current
|
926
927
|
|
927
928
|
pong = Thread.new do
|
928
|
-
|
929
|
-
|
929
|
+
master << :pong_ready
|
930
|
+
3.times do
|
930
931
|
peer, data = receive
|
931
932
|
pong_receive_buffer << data
|
932
933
|
peer << 'pong'
|
933
934
|
end
|
934
935
|
end
|
935
936
|
|
937
|
+
assert_equal :pong_ready, receive
|
938
|
+
|
936
939
|
ping = Thread.new do
|
937
|
-
sleep 0.05
|
938
940
|
3.times do
|
939
941
|
pong << [Fiber.current, 'ping']
|
940
942
|
data = receive
|
@@ -943,7 +945,7 @@ class MailboxTest < MiniTest::Test
|
|
943
945
|
end
|
944
946
|
|
945
947
|
ping.join
|
946
|
-
pong.
|
948
|
+
pong.join
|
947
949
|
ping = pong = nil
|
948
950
|
|
949
951
|
assert_equal %w{pong pong pong}, ping_receive_buffer
|
data/test/test_queue.rb
CHANGED
@@ -21,6 +21,44 @@ class QueueTest < MiniTest::Test
|
|
21
21
|
assert_equal [1, 2, 3, 4], buf
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_chained_push
|
25
|
+
@queue << 5 << 6 << 7
|
26
|
+
|
27
|
+
buf = []
|
28
|
+
3.times { buf << @queue.shift }
|
29
|
+
assert_equal [5, 6, 7], buf
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_push_aliases
|
33
|
+
@queue.push 1
|
34
|
+
@queue << 2
|
35
|
+
@queue.enq 3
|
36
|
+
|
37
|
+
buf = []
|
38
|
+
3.times { buf << @queue.shift }
|
39
|
+
assert_equal [1, 2, 3], buf
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_pop_aliases
|
43
|
+
@queue << 1 << 2 << 3
|
44
|
+
|
45
|
+
assert_equal 1, @queue.pop
|
46
|
+
assert_equal 2, @queue.deq
|
47
|
+
assert_equal 3, @queue.shift
|
48
|
+
|
49
|
+
@queue << 1 << 2 << 3
|
50
|
+
|
51
|
+
assert_equal 1, @queue.pop(false)
|
52
|
+
assert_equal 2, @queue.deq(false)
|
53
|
+
assert_equal 3, @queue.shift(false)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_nonblocking_pop
|
57
|
+
assert_raises(ThreadError) { @queue.pop(true) }
|
58
|
+
assert_raises(ThreadError) { @queue.deq(true) }
|
59
|
+
assert_raises(ThreadError) { @queue.shift(true) }
|
60
|
+
end
|
61
|
+
|
24
62
|
def test_unshift
|
25
63
|
@queue.push 1
|
26
64
|
@queue.push 2
|
@@ -112,22 +150,86 @@ class QueueTest < MiniTest::Test
|
|
112
150
|
|
113
151
|
def test_queue_size
|
114
152
|
assert_equal 0, @queue.size
|
153
|
+
assert_equal 0, @queue.length
|
115
154
|
|
116
155
|
@queue.push 1
|
117
156
|
|
118
157
|
assert_equal 1, @queue.size
|
158
|
+
assert_equal 1, @queue.length
|
119
159
|
|
120
160
|
@queue.push 2
|
121
161
|
|
122
162
|
assert_equal 2, @queue.size
|
163
|
+
assert_equal 2, @queue.length
|
123
164
|
|
124
165
|
@queue.shift
|
125
166
|
|
126
167
|
assert_equal 1, @queue.size
|
168
|
+
assert_equal 1, @queue.length
|
127
169
|
|
128
170
|
@queue.shift
|
129
171
|
|
130
172
|
assert_equal 0, @queue.size
|
173
|
+
assert_equal 0, @queue.length
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_pending?
|
177
|
+
assert_equal false, @queue.pending?
|
178
|
+
|
179
|
+
buf = []
|
180
|
+
f = spin { buf << @queue.shift }
|
181
|
+
snooze
|
182
|
+
assert_equal true, @queue.pending?
|
183
|
+
|
184
|
+
@queue << 42
|
185
|
+
f.await
|
186
|
+
assert_equal [42], buf
|
187
|
+
assert_equal false, @queue.pending?
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_num_waiting
|
191
|
+
assert_equal 0, @queue.num_waiting
|
192
|
+
|
193
|
+
f1 = spin { @queue.shift }
|
194
|
+
snooze # allow fiber to start
|
195
|
+
assert_equal 1, @queue.num_waiting
|
196
|
+
|
197
|
+
f2 = spin { @queue.shift }
|
198
|
+
snooze # allow fiber to start
|
199
|
+
assert_equal 2, @queue.num_waiting
|
200
|
+
|
201
|
+
@queue << 1
|
202
|
+
f1.await
|
203
|
+
assert_equal 1, @queue.num_waiting
|
204
|
+
|
205
|
+
@queue << 2
|
206
|
+
f2.await
|
207
|
+
assert_equal 0, @queue.num_waiting
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_closed_queue
|
211
|
+
assert_equal false, @queue.closed?
|
212
|
+
|
213
|
+
buf = []
|
214
|
+
f = spin { buf << @queue.shift }
|
215
|
+
snooze # allow fiber to start
|
216
|
+
|
217
|
+
@queue.close
|
218
|
+
assert_equal true, @queue.closed?
|
219
|
+
cancel_after(1) { f.await }
|
220
|
+
assert_equal [nil], buf
|
221
|
+
|
222
|
+
assert_raises(ClosedQueueError) { @queue << 1 }
|
223
|
+
assert_raises(ClosedQueueError) { @queue.deq }
|
224
|
+
assert_raises(ThreadError) { @queue.pop(true) }
|
225
|
+
|
226
|
+
# test deq on closed non-empty queue
|
227
|
+
@queue = Polyphony::Queue.new
|
228
|
+
@queue << 42 << 43
|
229
|
+
@queue.close
|
230
|
+
|
231
|
+
assert_equal 42, @queue.deq(false)
|
232
|
+
assert_equal 43, @queue.deq(true)
|
131
233
|
end
|
132
234
|
end
|
133
235
|
|
@@ -246,4 +348,4 @@ class CappedQueueTest < MiniTest::Test
|
|
246
348
|
a.join
|
247
349
|
assert_equal [1, 2, 3, :d5, 4, :d8, 5], buffer
|
248
350
|
end
|
249
|
-
end
|
351
|
+
end
|
data/test/test_signal.rb
CHANGED
@@ -3,6 +3,63 @@
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
5
|
class SignalTrapTest < Minitest::Test
|
6
|
+
def test_signal_handler_trace
|
7
|
+
i1, o1 = IO.pipe
|
8
|
+
i2, o2 = IO.pipe
|
9
|
+
pid = Process.pid
|
10
|
+
child_pid = Polyphony.fork do
|
11
|
+
i1.gets
|
12
|
+
Process.kill('SIGINT', pid)
|
13
|
+
sleep 0.1
|
14
|
+
o2.puts "done"
|
15
|
+
o2.close
|
16
|
+
end
|
17
|
+
|
18
|
+
events = []
|
19
|
+
begin
|
20
|
+
Thread.backend.trace_proc = proc { |*e| events << [e[0], e[1].tag] }
|
21
|
+
trap ('SIGINT') { }
|
22
|
+
|
23
|
+
o1.orig_write("\n")
|
24
|
+
o1.close
|
25
|
+
|
26
|
+
msg = i2.gets
|
27
|
+
assert_equal "done\n", msg
|
28
|
+
ensure
|
29
|
+
Thread.backend.trace_proc = nil
|
30
|
+
trap ('SIGINT') { raise Interrupt }
|
31
|
+
end
|
32
|
+
|
33
|
+
Fiber.current.tag = :main
|
34
|
+
|
35
|
+
expected = [
|
36
|
+
[:fiber_switchpoint, :main],
|
37
|
+
[:fiber_event_poll_enter, :main],
|
38
|
+
[:fiber_create, :oob],
|
39
|
+
[:fiber_schedule, :oob],
|
40
|
+
[:fiber_event_poll_leave, :main],
|
41
|
+
[:fiber_run, :oob],
|
42
|
+
[:fiber_terminate, :oob],
|
43
|
+
[:fiber_switchpoint, :oob],
|
44
|
+
[:fiber_event_poll_enter, :oob],
|
45
|
+
[:fiber_schedule, :main],
|
46
|
+
[:fiber_event_poll_leave, :oob],
|
47
|
+
[:fiber_run, :main]
|
48
|
+
]
|
49
|
+
if Thread.backend.kind == :libev
|
50
|
+
expected += [
|
51
|
+
[:fiber_schedule, :main],
|
52
|
+
[:fiber_switchpoint, :main],
|
53
|
+
[:fiber_run, :main]
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_equal expected, events
|
58
|
+
ensure
|
59
|
+
Process.kill('SIGTERM', child_pid) rescue nil
|
60
|
+
Process.wait(child_pid) rescue nil
|
61
|
+
end
|
62
|
+
|
6
63
|
def test_int_signal
|
7
64
|
Thread.new { sleep 0.001; Process.kill('INT', Process.pid) }
|
8
65
|
assert_raises(Interrupt) { sleep 5 }
|
data/test/test_supervise.rb
CHANGED
@@ -269,4 +269,31 @@ class SuperviseTest < MiniTest::Test
|
|
269
269
|
snooze
|
270
270
|
assert_equal [[f1, :foo], [f2, :bar]], buffer
|
271
271
|
end
|
272
|
+
|
273
|
+
def test_detached_supervisor
|
274
|
+
buffer = []
|
275
|
+
|
276
|
+
s = nil
|
277
|
+
f = spin {
|
278
|
+
foo = spin do
|
279
|
+
sleep 0.1
|
280
|
+
ensure
|
281
|
+
buffer << :foo
|
282
|
+
end
|
283
|
+
bar = spin do
|
284
|
+
sleep 0.2
|
285
|
+
ensure
|
286
|
+
buffer << :bar
|
287
|
+
end
|
288
|
+
|
289
|
+
s = spin { supervise }.detach
|
290
|
+
Fiber.current.attach_all_children_to(s)
|
291
|
+
|
292
|
+
s.terminate(true)
|
293
|
+
}
|
294
|
+
|
295
|
+
f.await
|
296
|
+
s.await
|
297
|
+
assert_equal [:foo, :bar], buffer
|
298
|
+
end
|
272
299
|
end
|
data/test/test_thread.rb
CHANGED
@@ -132,7 +132,7 @@ class ThreadTest < MiniTest::Test
|
|
132
132
|
Thread.backend.trace_proc = proc {|*r| records << r }
|
133
133
|
suspend
|
134
134
|
assert_equal [
|
135
|
-
[:fiber_switchpoint, Fiber.current]
|
135
|
+
[:fiber_switchpoint, Fiber.current, ["#{__FILE__}:#{__LINE__ - 2}:in `test_that_suspend_returns_immediately_if_no_watchers'"] + caller]
|
136
136
|
], records
|
137
137
|
ensure
|
138
138
|
Thread.backend.trace_proc = nil
|
data/test/test_timer.rb
CHANGED
data/test/test_trace.rb
CHANGED
@@ -10,7 +10,7 @@ class TraceTest < MiniTest::Test
|
|
10
10
|
|
11
11
|
assert_equal [
|
12
12
|
[:fiber_schedule, Fiber.current, nil, false],
|
13
|
-
[:fiber_switchpoint, Fiber.current],
|
13
|
+
[:fiber_switchpoint, Fiber.current, ["#{__FILE__}:#{__LINE__ - 4}:in `test_tracing_enabled'"] + caller],
|
14
14
|
[:fiber_run, Fiber.current, nil]
|
15
15
|
], events
|
16
16
|
ensure
|
@@ -22,9 +22,15 @@ class TraceTest < MiniTest::Test
|
|
22
22
|
Thread.backend.trace_proc = proc { |*e| events << e }
|
23
23
|
|
24
24
|
f = spin { sleep 0; :byebye }
|
25
|
+
l0 = __LINE__ + 1
|
25
26
|
suspend
|
26
27
|
sleep 0
|
27
28
|
|
29
|
+
Thread.backend.trace_proc = nil
|
30
|
+
|
31
|
+
# remove caller info for :fiber_switchpoint events
|
32
|
+
events.each {|e| e.pop if e[0] == :fiber_switchpoint }
|
33
|
+
|
28
34
|
assert_equal [
|
29
35
|
[:fiber_create, f],
|
30
36
|
[:fiber_schedule, f, nil, false],
|
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.78'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -245,6 +245,8 @@ files:
|
|
245
245
|
- examples/core/thread_pool.rb
|
246
246
|
- examples/core/throttling.rb
|
247
247
|
- examples/core/timeout.rb
|
248
|
+
- examples/core/trap1.rb
|
249
|
+
- examples/core/trap2.rb
|
248
250
|
- examples/core/using-a-mutex.rb
|
249
251
|
- examples/core/worker-thread.rb
|
250
252
|
- examples/io/backticks.rb
|
@@ -346,6 +348,7 @@ files:
|
|
346
348
|
- ext/polyphony/runqueue_ring_buffer.h
|
347
349
|
- ext/polyphony/socket_extensions.c
|
348
350
|
- ext/polyphony/thread.c
|
351
|
+
- ext/test_eintr.c
|
349
352
|
- lib/polyphony.rb
|
350
353
|
- lib/polyphony/adapters/fs.rb
|
351
354
|
- lib/polyphony/adapters/irb.rb
|