polyphony 0.69 → 0.73
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/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +2 -2
- data/.gitignore +3 -1
- data/CHANGELOG.md +33 -4
- data/Gemfile.lock +2 -2
- data/TODO.md +1 -24
- data/bin/pdbg +1 -1
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/exception.md +5 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/core/ring.rb +29 -0
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +31 -7
- data/ext/polyphony/backend_common.h +2 -1
- data/ext/polyphony/backend_io_uring.c +57 -67
- data/ext/polyphony/backend_io_uring_context.c +1 -1
- data/ext/polyphony/backend_io_uring_context.h +1 -1
- data/ext/polyphony/backend_libev.c +38 -30
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.h +5 -1
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue_ring_buffer.c +3 -2
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/{extensions → core}/debug.rb +0 -0
- data/lib/polyphony/core/global_api.rb +3 -6
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/exception.rb +45 -0
- data/lib/polyphony/extensions/fiber.rb +30 -16
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/{core.rb → kernel.rb} +0 -73
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/process.rb +19 -0
- data/lib/polyphony/extensions/socket.rb +3 -4
- data/lib/polyphony/extensions/timeout.rb +10 -0
- data/lib/polyphony/extensions.rb +9 -0
- data/lib/polyphony/net.rb +0 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -5
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/stress.rb +1 -1
- data/test/test_backend.rb +12 -12
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +52 -12
- data/test/test_global_api.rb +16 -4
- data/test/test_io.rb +3 -3
- data/test/test_process_supervision.rb +39 -10
- data/test/test_queue.rb +6 -6
- data/test/test_signal.rb +20 -1
- data/test/test_socket.rb +12 -10
- data/test/test_supervise.rb +249 -81
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +2 -2
- data/test/test_trace.rb +1 -1
- metadata +18 -9
@@ -31,10 +31,28 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
31
31
|
runqueue_mark(&base->parked_runqueue);
|
32
32
|
}
|
33
33
|
|
34
|
+
void backend_base_reset(struct Backend_base *base) {
|
35
|
+
runqueue_finalize(&base->runqueue);
|
36
|
+
runqueue_finalize(&base->parked_runqueue);
|
37
|
+
|
38
|
+
runqueue_initialize(&base->runqueue);
|
39
|
+
runqueue_initialize(&base->parked_runqueue);
|
40
|
+
|
41
|
+
base->currently_polling = 0;
|
42
|
+
base->op_count = 0;
|
43
|
+
base->switch_count = 0;
|
44
|
+
base->poll_count = 0;
|
45
|
+
base->pending_count = 0;
|
46
|
+
base->idle_gc_period = 0;
|
47
|
+
base->idle_gc_last_time = 0;
|
48
|
+
base->idle_proc = Qnil;
|
49
|
+
base->trace_proc = Qnil;
|
50
|
+
}
|
51
|
+
|
34
52
|
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
35
53
|
|
36
54
|
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
37
|
-
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
55
|
+
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
38
56
|
Backend_poll(backend, Qnil);
|
39
57
|
}
|
40
58
|
|
@@ -44,7 +62,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
44
62
|
unsigned int pending_ops_count = base->pending_count;
|
45
63
|
unsigned int backend_was_polled = 0;
|
46
64
|
unsigned int idle_tasks_run_count = 0;
|
47
|
-
|
65
|
+
|
48
66
|
base->switch_count++;
|
49
67
|
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
50
68
|
|
@@ -64,7 +82,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
64
82
|
|
65
83
|
break;
|
66
84
|
}
|
67
|
-
|
85
|
+
|
68
86
|
if (!idle_tasks_run_count) {
|
69
87
|
idle_tasks_run_count++;
|
70
88
|
backend_run_idle_tasks(base);
|
@@ -94,7 +112,7 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
94
112
|
|
95
113
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
96
114
|
|
97
|
-
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
115
|
+
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
98
116
|
&base->parked_runqueue : &base->runqueue;
|
99
117
|
|
100
118
|
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
@@ -184,7 +202,6 @@ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
|
184
202
|
}
|
185
203
|
|
186
204
|
inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
187
|
-
OBJ_TAINT(str);
|
188
205
|
rb_enc_associate(str, io_read_encoding(fptr));
|
189
206
|
return str;
|
190
207
|
}
|
@@ -228,6 +245,13 @@ inline double current_time() {
|
|
228
245
|
return t / 1e9;
|
229
246
|
}
|
230
247
|
|
248
|
+
inline uint64_t current_time_ns() {
|
249
|
+
struct timespec ts;
|
250
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
251
|
+
uint64_t ns = ts.tv_sec;
|
252
|
+
return ns * 1e9 + ts.tv_nsec;
|
253
|
+
}
|
254
|
+
|
231
255
|
inline VALUE backend_timeout_exception(VALUE exception) {
|
232
256
|
if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
|
233
257
|
return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
|
@@ -282,7 +306,7 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
282
306
|
int flags = fcntl(fptr->fd, F_GETFL);
|
283
307
|
if (flags == -1) return;
|
284
308
|
int is_nonblocking = flags & O_NONBLOCK;
|
285
|
-
|
309
|
+
|
286
310
|
if (blocking == Qtrue) {
|
287
311
|
if (!is_nonblocking) return;
|
288
312
|
flags &= ~O_NONBLOCK;
|
@@ -357,7 +381,7 @@ void backend_setup_stats_symbols() {
|
|
357
381
|
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
358
382
|
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
359
383
|
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
360
|
-
|
384
|
+
|
361
385
|
rb_global_variable(&SYM_runqueue_size);
|
362
386
|
rb_global_variable(&SYM_runqueue_length);
|
363
387
|
rb_global_variable(&SYM_runqueue_max_length);
|
@@ -32,6 +32,7 @@ struct Backend_base {
|
|
32
32
|
void backend_base_initialize(struct Backend_base *base);
|
33
33
|
void backend_base_finalize(struct Backend_base *base);
|
34
34
|
void backend_base_mark(struct Backend_base *base);
|
35
|
+
void backend_base_reset(struct Backend_base *base);
|
35
36
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
36
37
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
37
38
|
void backend_base_park_fiber(struct Backend_base *base, VALUE fiber);
|
@@ -81,7 +82,6 @@ VALUE backend_snooze();
|
|
81
82
|
shrinkable = io_setstrbuf(&str, len); \
|
82
83
|
buf = RSTRING_PTR(str); \
|
83
84
|
total = 0; \
|
84
|
-
OBJ_TAINT(str); \
|
85
85
|
}
|
86
86
|
|
87
87
|
#define READ_LOOP_YIELD_STR() { \
|
@@ -100,6 +100,7 @@ VALUE backend_snooze();
|
|
100
100
|
|
101
101
|
void rectify_io_file_pos(rb_io_t *fptr);
|
102
102
|
double current_time();
|
103
|
+
uint64_t current_time_ns();
|
103
104
|
VALUE backend_timeout_exception(VALUE exception);
|
104
105
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
105
106
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
@@ -106,9 +106,7 @@ VALUE Backend_post_fork(VALUE self) {
|
|
106
106
|
io_uring_queue_exit(&backend->ring);
|
107
107
|
io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
|
108
108
|
context_store_free(&backend->store);
|
109
|
-
backend->base
|
110
|
-
backend->base.pending_count = 0;
|
111
|
-
backend->pending_sqes = 0;
|
109
|
+
backend_base_reset(&backend->base);
|
112
110
|
|
113
111
|
return self;
|
114
112
|
}
|
@@ -129,7 +127,7 @@ void *io_uring_backend_poll_without_gvl(void *ptr) {
|
|
129
127
|
|
130
128
|
// copied from queue.c
|
131
129
|
static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
132
|
-
|
130
|
+
return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
|
133
131
|
}
|
134
132
|
|
135
133
|
static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
@@ -143,13 +141,13 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
143
141
|
context_store_release(&backend->store, ctx);
|
144
142
|
}
|
145
143
|
|
146
|
-
// adapted from io_uring_peek_batch_cqe in queue.c
|
144
|
+
// adapted from io_uring_peek_batch_cqe in queue.c
|
147
145
|
// this peeks at cqes and handles each available cqe
|
148
146
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
149
147
|
struct io_uring *ring = &backend->ring;
|
150
|
-
|
148
|
+
bool overflow_checked = false;
|
151
149
|
struct io_uring_cqe *cqe;
|
152
|
-
|
150
|
+
unsigned head;
|
153
151
|
unsigned cqe_count;
|
154
152
|
|
155
153
|
again:
|
@@ -160,16 +158,16 @@ again:
|
|
160
158
|
}
|
161
159
|
io_uring_cq_advance(ring, cqe_count);
|
162
160
|
|
163
|
-
|
161
|
+
if (overflow_checked) goto done;
|
164
162
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
163
|
+
if (cq_ring_needs_flush(ring)) {
|
164
|
+
__sys_io_uring_enter(ring->ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
|
165
|
+
overflow_checked = true;
|
166
|
+
goto again;
|
167
|
+
}
|
170
168
|
|
171
169
|
done:
|
172
|
-
|
170
|
+
return;
|
173
171
|
}
|
174
172
|
|
175
173
|
void io_uring_backend_poll(Backend_t *backend) {
|
@@ -202,19 +200,12 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
202
200
|
}
|
203
201
|
|
204
202
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
205
|
-
|
206
|
-
// printf(
|
207
|
-
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
208
|
-
// is_blocking,
|
209
|
-
// backend->base.pending_count,
|
210
|
-
// backend->store.taken_count,
|
211
|
-
// backend->store.available_count,
|
212
|
-
// backend->base.runqueue.entries.count
|
213
|
-
// );
|
203
|
+
|
214
204
|
if (is_blocking) io_uring_backend_poll(backend);
|
215
205
|
io_uring_backend_handle_ready_cqes(backend);
|
216
|
-
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
217
206
|
|
207
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
208
|
+
|
218
209
|
return self;
|
219
210
|
}
|
220
211
|
|
@@ -257,7 +248,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
257
248
|
io_uring_prep_nop(sqe);
|
258
249
|
backend->pending_sqes = 0;
|
259
250
|
io_uring_submit(&backend->ring);
|
260
|
-
|
251
|
+
|
261
252
|
return Qtrue;
|
262
253
|
}
|
263
254
|
|
@@ -342,7 +333,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
342
333
|
rb_io_check_byte_readable(fptr);
|
343
334
|
io_unset_nonblock(fptr, io);
|
344
335
|
rectify_io_file_pos(fptr);
|
345
|
-
OBJ_TAINT(str);
|
346
336
|
|
347
337
|
while (1) {
|
348
338
|
VALUE resume_value = Qnil;
|
@@ -413,7 +403,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
413
403
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
414
404
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
415
405
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
416
|
-
|
406
|
+
|
417
407
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
418
408
|
int completed = context_store_release(&backend->store, ctx);
|
419
409
|
if (!completed) {
|
@@ -463,7 +453,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
463
453
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
464
454
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
465
455
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
466
|
-
|
456
|
+
|
467
457
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
468
458
|
int completed = context_store_release(&backend->store, ctx);
|
469
459
|
if (!completed) {
|
@@ -509,7 +499,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
509
499
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
510
500
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
511
501
|
io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
|
512
|
-
|
502
|
+
|
513
503
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
514
504
|
int completed = context_store_release(&backend->store, ctx);
|
515
505
|
if (!completed) {
|
@@ -518,7 +508,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
518
508
|
return resume_value;
|
519
509
|
}
|
520
510
|
RB_GC_GUARD(resume_value);
|
521
|
-
|
511
|
+
|
522
512
|
if (result < 0)
|
523
513
|
rb_syserr_fail(-result, strerror(-result));
|
524
514
|
else {
|
@@ -561,7 +551,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
561
551
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
|
562
552
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
563
553
|
io_uring_prep_writev(sqe, fptr->fd, iov_ptr, iov_count, -1);
|
564
|
-
|
554
|
+
|
565
555
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
566
556
|
int completed = context_store_release(&backend->store, ctx);
|
567
557
|
if (!completed) {
|
@@ -630,14 +620,13 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
630
620
|
rb_io_check_byte_readable(fptr);
|
631
621
|
io_unset_nonblock(fptr, io);
|
632
622
|
rectify_io_file_pos(fptr);
|
633
|
-
OBJ_TAINT(str);
|
634
623
|
|
635
624
|
while (1) {
|
636
625
|
VALUE resume_value = Qnil;
|
637
626
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
638
627
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
639
628
|
io_uring_prep_recv(sqe, fptr->fd, buf, len - total, 0);
|
640
|
-
|
629
|
+
|
641
630
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
642
631
|
int completed = context_store_release(&backend->store, ctx);
|
643
632
|
if (!completed) {
|
@@ -687,7 +676,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
687
676
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
688
677
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
689
678
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
690
|
-
|
679
|
+
|
691
680
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
692
681
|
int completed = context_store_release(&backend->store, ctx);
|
693
682
|
if (!completed) {
|
@@ -736,7 +725,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
736
725
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
737
726
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
738
727
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
739
|
-
|
728
|
+
|
740
729
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
741
730
|
int completed = context_store_release(&backend->store, ctx);
|
742
731
|
if (!completed) {
|
@@ -782,7 +771,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
782
771
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
783
772
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
784
773
|
io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
|
785
|
-
|
774
|
+
|
786
775
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
787
776
|
int completed = context_store_release(&backend->store, ctx);
|
788
777
|
if (!completed) {
|
@@ -819,7 +808,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
819
808
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
|
820
809
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
821
810
|
io_uring_prep_accept(sqe, fptr->fd, &addr, &len, 0);
|
822
|
-
|
811
|
+
|
823
812
|
int fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
824
813
|
int completed = context_store_release(&backend->store, ctx);
|
825
814
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -840,7 +829,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
840
829
|
rb_io_synchronized(fp);
|
841
830
|
|
842
831
|
// if (rsock_do_not_reverse_lookup) {
|
843
|
-
|
832
|
+
// fp->mode |= FMODE_NOREVLOOKUP;
|
844
833
|
// }
|
845
834
|
if (loop) {
|
846
835
|
rb_yield(socket);
|
@@ -890,7 +879,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
890
879
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
891
880
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
892
881
|
io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
|
893
|
-
|
882
|
+
|
894
883
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
895
884
|
int completed = context_store_release(&backend->store, ctx);
|
896
885
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -946,7 +935,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
946
935
|
RAISE_IF_EXCEPTION(resume_value);
|
947
936
|
if (!completed) return resume_value;
|
948
937
|
RB_GC_GUARD(resume_value);
|
949
|
-
|
938
|
+
|
950
939
|
if (result < 0) rb_syserr_fail(-result, strerror(-result));
|
951
940
|
return sock;
|
952
941
|
}
|
@@ -971,7 +960,7 @@ inline struct __kernel_timespec double_to_timespec(double duration) {
|
|
971
960
|
double duration_fraction = modf(duration, &duration_integral);
|
972
961
|
struct __kernel_timespec ts;
|
973
962
|
ts.tv_sec = duration_integral;
|
974
|
-
|
963
|
+
ts.tv_nsec = floor(duration_fraction * 1000000000);
|
975
964
|
return ts;
|
976
965
|
}
|
977
966
|
|
@@ -983,7 +972,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
|
|
983
972
|
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
984
973
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
985
974
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
986
|
-
|
975
|
+
|
987
976
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
988
977
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
989
978
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
@@ -1003,29 +992,34 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
1003
992
|
|
1004
993
|
VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
1005
994
|
Backend_t *backend;
|
1006
|
-
|
995
|
+
uint64_t interval_ns = NUM2DBL(interval) * 1e9;
|
996
|
+
uint64_t next_time_ns = 0;
|
997
|
+
VALUE resume_value = Qnil;
|
998
|
+
|
1007
999
|
GetBackend(self, backend);
|
1008
|
-
double next_time = 0.;
|
1009
1000
|
|
1010
1001
|
while (1) {
|
1011
|
-
double
|
1012
|
-
if (
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1002
|
+
double now_ns = current_time_ns();
|
1003
|
+
if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
|
1004
|
+
if (next_time_ns > now_ns) {
|
1005
|
+
double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
|
1006
|
+
int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
|
1007
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1008
|
+
if (!completed) return resume_value;
|
1009
|
+
}
|
1010
|
+
else {
|
1011
|
+
resume_value = backend_snooze();
|
1012
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1013
|
+
}
|
1021
1014
|
|
1022
1015
|
rb_yield(Qnil);
|
1023
1016
|
|
1024
1017
|
while (1) {
|
1025
|
-
|
1026
|
-
if (
|
1018
|
+
next_time_ns += interval_ns;
|
1019
|
+
if (next_time_ns > now_ns) break;
|
1027
1020
|
}
|
1028
1021
|
}
|
1022
|
+
RB_GC_GUARD(resume_value);
|
1029
1023
|
}
|
1030
1024
|
|
1031
1025
|
struct Backend_timeout_ctx {
|
@@ -1053,7 +1047,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1053
1047
|
VALUE exception;
|
1054
1048
|
VALUE move_on_value = Qnil;
|
1055
1049
|
rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
|
1056
|
-
|
1050
|
+
|
1057
1051
|
struct __kernel_timespec ts = duration_to_timespec(duration);
|
1058
1052
|
Backend_t *backend;
|
1059
1053
|
GetBackend(self, backend);
|
@@ -1061,7 +1055,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1061
1055
|
VALUE timeout = rb_funcall(cTimeoutException, ID_new, 0);
|
1062
1056
|
|
1063
1057
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1064
|
-
|
1058
|
+
|
1065
1059
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1066
1060
|
ctx->resume_value = timeout;
|
1067
1061
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1096,7 +1090,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1096
1090
|
RAISE_IF_EXCEPTION(resume_value);
|
1097
1091
|
RB_GC_GUARD(resume_value);
|
1098
1092
|
}
|
1099
|
-
|
1093
|
+
|
1100
1094
|
int status;
|
1101
1095
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1102
1096
|
if (ret < 0) {
|
@@ -1246,7 +1240,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1246
1240
|
}
|
1247
1241
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1248
1242
|
}
|
1249
|
-
|
1243
|
+
|
1250
1244
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1251
1245
|
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1252
1246
|
io_uring_sqe_set_flags(last_sqe, flags);
|
@@ -1261,7 +1255,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1261
1255
|
int completed = context_store_release(&backend->store, ctx);
|
1262
1256
|
if (!completed) {
|
1263
1257
|
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1264
|
-
|
1258
|
+
|
1265
1259
|
// op was not completed (an exception was raised), so we need to cancel it
|
1266
1260
|
ctx->result = -ECANCELED;
|
1267
1261
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1271,7 +1265,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1271
1265
|
RAISE_IF_EXCEPTION(resume_value);
|
1272
1266
|
return resume_value;
|
1273
1267
|
}
|
1274
|
-
|
1268
|
+
|
1275
1269
|
RB_GC_GUARD(resume_value);
|
1276
1270
|
return INT2NUM(result);
|
1277
1271
|
}
|
@@ -1406,7 +1400,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1406
1400
|
|
1407
1401
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1408
1402
|
if (chunk_len == 0) break;
|
1409
|
-
|
1403
|
+
|
1410
1404
|
total += chunk_len;
|
1411
1405
|
chunk_len_value = INT2NUM(chunk_len);
|
1412
1406
|
|
@@ -1528,10 +1522,6 @@ void Init_Backend() {
|
|
1528
1522
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1529
1523
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1530
1524
|
|
1531
|
-
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1532
|
-
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1533
|
-
#endif
|
1534
|
-
|
1535
1525
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
1536
1526
|
SYM_send = ID2SYM(rb_intern("send"));
|
1537
1527
|
SYM_splice = ID2SYM(rb_intern("splice"));
|
@@ -64,7 +64,7 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
64
64
|
// printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
65
65
|
|
66
66
|
assert(ctx->ref_count);
|
67
|
-
|
67
|
+
|
68
68
|
ctx->ref_count--;
|
69
69
|
if (ctx->ref_count) return 0;
|
70
70
|
|
@@ -118,7 +118,7 @@ inline struct ev_loop *libev_new_loop() {
|
|
118
118
|
|
119
119
|
static VALUE Backend_initialize(VALUE self) {
|
120
120
|
Backend_t *backend;
|
121
|
-
|
121
|
+
|
122
122
|
GetBackend(self, backend);
|
123
123
|
|
124
124
|
backend_base_initialize(&backend->base);
|
@@ -157,6 +157,8 @@ VALUE Backend_post_fork(VALUE self) {
|
|
157
157
|
ev_loop_destroy(backend->ev_loop);
|
158
158
|
backend->ev_loop = EV_DEFAULT;
|
159
159
|
|
160
|
+
backend_base_reset(&backend->base);
|
161
|
+
|
160
162
|
return self;
|
161
163
|
}
|
162
164
|
|
@@ -186,7 +188,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
186
188
|
Backend_t *backend;
|
187
189
|
GetBackend(self, backend);
|
188
190
|
|
189
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
191
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
190
192
|
}
|
191
193
|
|
192
194
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -285,7 +287,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
285
287
|
io_verify_blocking_mode(fptr, io, Qfalse);
|
286
288
|
rectify_io_file_pos(fptr);
|
287
289
|
watcher.fiber = Qnil;
|
288
|
-
OBJ_TAINT(str);
|
289
290
|
|
290
291
|
while (1) {
|
291
292
|
backend->base.op_count++;
|
@@ -969,7 +970,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
969
970
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
970
971
|
|
971
972
|
watcher.fiber = Qnil;
|
972
|
-
|
973
|
+
|
973
974
|
while (1) {
|
974
975
|
backend->base.op_count++;
|
975
976
|
ssize_t n = read(src_fptr->fd, buf, len);
|
@@ -1045,7 +1046,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1045
1046
|
|
1046
1047
|
watcher.fiber = Qnil;
|
1047
1048
|
|
1048
|
-
while (1) {
|
1049
|
+
while (1) {
|
1049
1050
|
char *ptr = buf;
|
1050
1051
|
while (1) {
|
1051
1052
|
backend->base.op_count++;
|
@@ -1145,33 +1146,40 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
1145
1146
|
noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
1146
1147
|
Backend_t *backend;
|
1147
1148
|
struct libev_timer watcher;
|
1148
|
-
double interval_d = NUM2DBL(interval);
|
1149
|
-
|
1150
|
-
GetBackend(self, backend);
|
1151
1149
|
watcher.fiber = rb_fiber_current();
|
1150
|
+
uint64_t interval_ns = NUM2DBL(interval) * 1e9;
|
1151
|
+
uint64_t next_time_ns = 0;
|
1152
|
+
VALUE resume_value = Qnil;
|
1152
1153
|
|
1153
|
-
|
1154
|
+
GetBackend(self, backend);
|
1154
1155
|
|
1155
1156
|
while (1) {
|
1156
|
-
|
1157
|
-
if (
|
1158
|
-
double sleep_duration =
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1157
|
+
uint64_t now_ns = current_time_ns();
|
1158
|
+
if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
|
1159
|
+
double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
|
1160
|
+
|
1161
|
+
if (next_time_ns > now_ns) {
|
1162
|
+
double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
|
1163
|
+
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
1164
|
+
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1165
|
+
backend->base.op_count++;
|
1166
|
+
resume_value = backend_await((struct Backend_base *)backend);
|
1167
|
+
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
1168
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1169
|
+
}
|
1170
|
+
else {
|
1171
|
+
resume_value = backend_snooze();
|
1172
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1173
|
+
}
|
1169
1174
|
|
1170
1175
|
rb_yield(Qnil);
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1176
|
+
|
1177
|
+
while (1) {
|
1178
|
+
next_time_ns += interval_ns;
|
1179
|
+
if (next_time_ns > now_ns) break;
|
1180
|
+
}
|
1174
1181
|
}
|
1182
|
+
RB_GC_GUARD(resume_value);
|
1175
1183
|
}
|
1176
1184
|
|
1177
1185
|
struct libev_timeout {
|
@@ -1217,7 +1225,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1217
1225
|
|
1218
1226
|
struct Backend_timeout_ctx timeout_ctx = {backend, &watcher};
|
1219
1227
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
1220
|
-
|
1228
|
+
|
1221
1229
|
if (result == timeout) {
|
1222
1230
|
if (exception == Qnil) return move_on_value;
|
1223
1231
|
RAISE_EXCEPTION(backend_timeout_exception(exception));
|
@@ -1335,7 +1343,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1335
1343
|
else
|
1336
1344
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1337
1345
|
}
|
1338
|
-
|
1346
|
+
|
1339
1347
|
RB_GC_GUARD(result);
|
1340
1348
|
return result;
|
1341
1349
|
}
|
@@ -1384,14 +1392,14 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1384
1392
|
return 0;
|
1385
1393
|
}
|
1386
1394
|
|
1387
|
-
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1395
|
+
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1388
1396
|
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1389
1397
|
#ifdef POLYPHONY_LINUX
|
1390
1398
|
backend->base.op_count++;
|
1391
1399
|
while (1) {
|
1392
1400
|
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1393
1401
|
if (*chunk_len >= 0) return 0;
|
1394
|
-
|
1402
|
+
|
1395
1403
|
int err = errno;
|
1396
1404
|
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1397
1405
|
|
@@ -1487,7 +1495,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1487
1495
|
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1488
1496
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1489
1497
|
if (chunk_len == 0) break;
|
1490
|
-
|
1498
|
+
|
1491
1499
|
total += chunk_len;
|
1492
1500
|
chunk_len_value = INT2NUM(chunk_len);
|
1493
1501
|
|