polyphony 0.70 → 0.73.1
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 +3 -2
- data/.gitignore +3 -1
- data/CHANGELOG.md +32 -4
- data/Gemfile.lock +11 -11
- data/TODO.md +1 -1
- 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 +15 -9
- data/ext/polyphony/backend_common.h +1 -1
- data/ext/polyphony/backend_io_uring.c +56 -64
- 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 +36 -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 +27 -9
- 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/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 -7
- data/test/test_global_api.rb +16 -3
- data/test/test_io.rb +3 -3
- data/test/test_process_supervision.rb +1 -1
- 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 +85 -0
- 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 +13 -4
@@ -34,7 +34,7 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
34
34
|
void backend_base_reset(struct Backend_base *base) {
|
35
35
|
runqueue_finalize(&base->runqueue);
|
36
36
|
runqueue_finalize(&base->parked_runqueue);
|
37
|
-
|
37
|
+
|
38
38
|
runqueue_initialize(&base->runqueue);
|
39
39
|
runqueue_initialize(&base->parked_runqueue);
|
40
40
|
|
@@ -46,13 +46,13 @@ void backend_base_reset(struct Backend_base *base) {
|
|
46
46
|
base->idle_gc_period = 0;
|
47
47
|
base->idle_gc_last_time = 0;
|
48
48
|
base->idle_proc = Qnil;
|
49
|
-
base->trace_proc = Qnil;
|
49
|
+
base->trace_proc = Qnil;
|
50
50
|
}
|
51
51
|
|
52
52
|
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
53
53
|
|
54
54
|
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
55
|
-
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)
|
56
56
|
Backend_poll(backend, Qnil);
|
57
57
|
}
|
58
58
|
|
@@ -62,7 +62,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
62
62
|
unsigned int pending_ops_count = base->pending_count;
|
63
63
|
unsigned int backend_was_polled = 0;
|
64
64
|
unsigned int idle_tasks_run_count = 0;
|
65
|
-
|
65
|
+
|
66
66
|
base->switch_count++;
|
67
67
|
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
68
68
|
|
@@ -82,7 +82,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
82
82
|
|
83
83
|
break;
|
84
84
|
}
|
85
|
-
|
85
|
+
|
86
86
|
if (!idle_tasks_run_count) {
|
87
87
|
idle_tasks_run_count++;
|
88
88
|
backend_run_idle_tasks(base);
|
@@ -112,7 +112,7 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
112
112
|
|
113
113
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
114
114
|
|
115
|
-
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
115
|
+
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
116
116
|
&base->parked_runqueue : &base->runqueue;
|
117
117
|
|
118
118
|
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
@@ -202,7 +202,6 @@ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
|
202
202
|
}
|
203
203
|
|
204
204
|
inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
205
|
-
OBJ_TAINT(str);
|
206
205
|
rb_enc_associate(str, io_read_encoding(fptr));
|
207
206
|
return str;
|
208
207
|
}
|
@@ -246,6 +245,13 @@ inline double current_time() {
|
|
246
245
|
return t / 1e9;
|
247
246
|
}
|
248
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
|
+
|
249
255
|
inline VALUE backend_timeout_exception(VALUE exception) {
|
250
256
|
if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
|
251
257
|
return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
|
@@ -300,7 +306,7 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
300
306
|
int flags = fcntl(fptr->fd, F_GETFL);
|
301
307
|
if (flags == -1) return;
|
302
308
|
int is_nonblocking = flags & O_NONBLOCK;
|
303
|
-
|
309
|
+
|
304
310
|
if (blocking == Qtrue) {
|
305
311
|
if (!is_nonblocking) return;
|
306
312
|
flags &= ~O_NONBLOCK;
|
@@ -375,7 +381,7 @@ void backend_setup_stats_symbols() {
|
|
375
381
|
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
376
382
|
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
377
383
|
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
378
|
-
|
384
|
+
|
379
385
|
rb_global_variable(&SYM_runqueue_size);
|
380
386
|
rb_global_variable(&SYM_runqueue_length);
|
381
387
|
rb_global_variable(&SYM_runqueue_max_length);
|
@@ -82,7 +82,6 @@ VALUE backend_snooze();
|
|
82
82
|
shrinkable = io_setstrbuf(&str, len); \
|
83
83
|
buf = RSTRING_PTR(str); \
|
84
84
|
total = 0; \
|
85
|
-
OBJ_TAINT(str); \
|
86
85
|
}
|
87
86
|
|
88
87
|
#define READ_LOOP_YIELD_STR() { \
|
@@ -101,6 +100,7 @@ VALUE backend_snooze();
|
|
101
100
|
|
102
101
|
void rectify_io_file_pos(rb_io_t *fptr);
|
103
102
|
double current_time();
|
103
|
+
uint64_t current_time_ns();
|
104
104
|
VALUE backend_timeout_exception(VALUE exception);
|
105
105
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
106
106
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
@@ -127,7 +127,7 @@ void *io_uring_backend_poll_without_gvl(void *ptr) {
|
|
127
127
|
|
128
128
|
// copied from queue.c
|
129
129
|
static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
130
|
-
|
130
|
+
return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
|
131
131
|
}
|
132
132
|
|
133
133
|
static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
@@ -141,13 +141,13 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
141
141
|
context_store_release(&backend->store, ctx);
|
142
142
|
}
|
143
143
|
|
144
|
-
// adapted from io_uring_peek_batch_cqe in queue.c
|
144
|
+
// adapted from io_uring_peek_batch_cqe in queue.c
|
145
145
|
// this peeks at cqes and handles each available cqe
|
146
146
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
147
147
|
struct io_uring *ring = &backend->ring;
|
148
|
-
|
148
|
+
bool overflow_checked = false;
|
149
149
|
struct io_uring_cqe *cqe;
|
150
|
-
|
150
|
+
unsigned head;
|
151
151
|
unsigned cqe_count;
|
152
152
|
|
153
153
|
again:
|
@@ -158,16 +158,16 @@ again:
|
|
158
158
|
}
|
159
159
|
io_uring_cq_advance(ring, cqe_count);
|
160
160
|
|
161
|
-
|
161
|
+
if (overflow_checked) goto done;
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
+
}
|
168
168
|
|
169
169
|
done:
|
170
|
-
|
170
|
+
return;
|
171
171
|
}
|
172
172
|
|
173
173
|
void io_uring_backend_poll(Backend_t *backend) {
|
@@ -200,19 +200,12 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
200
200
|
}
|
201
201
|
|
202
202
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
203
|
-
|
204
|
-
// printf(
|
205
|
-
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
206
|
-
// is_blocking,
|
207
|
-
// backend->base.pending_count,
|
208
|
-
// backend->store.taken_count,
|
209
|
-
// backend->store.available_count,
|
210
|
-
// backend->base.runqueue.entries.count
|
211
|
-
// );
|
203
|
+
|
212
204
|
if (is_blocking) io_uring_backend_poll(backend);
|
213
205
|
io_uring_backend_handle_ready_cqes(backend);
|
214
|
-
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
215
206
|
|
207
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
208
|
+
|
216
209
|
return self;
|
217
210
|
}
|
218
211
|
|
@@ -255,7 +248,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
255
248
|
io_uring_prep_nop(sqe);
|
256
249
|
backend->pending_sqes = 0;
|
257
250
|
io_uring_submit(&backend->ring);
|
258
|
-
|
251
|
+
|
259
252
|
return Qtrue;
|
260
253
|
}
|
261
254
|
|
@@ -340,7 +333,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
340
333
|
rb_io_check_byte_readable(fptr);
|
341
334
|
io_unset_nonblock(fptr, io);
|
342
335
|
rectify_io_file_pos(fptr);
|
343
|
-
OBJ_TAINT(str);
|
344
336
|
|
345
337
|
while (1) {
|
346
338
|
VALUE resume_value = Qnil;
|
@@ -411,7 +403,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
411
403
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
412
404
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
413
405
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
414
|
-
|
406
|
+
|
415
407
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
416
408
|
int completed = context_store_release(&backend->store, ctx);
|
417
409
|
if (!completed) {
|
@@ -461,7 +453,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
461
453
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_READ);
|
462
454
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
463
455
|
io_uring_prep_read(sqe, fptr->fd, buf, len, -1);
|
464
|
-
|
456
|
+
|
465
457
|
ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
466
458
|
int completed = context_store_release(&backend->store, ctx);
|
467
459
|
if (!completed) {
|
@@ -507,7 +499,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
507
499
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITE);
|
508
500
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
509
501
|
io_uring_prep_write(sqe, fptr->fd, buf, left, 0);
|
510
|
-
|
502
|
+
|
511
503
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
512
504
|
int completed = context_store_release(&backend->store, ctx);
|
513
505
|
if (!completed) {
|
@@ -516,7 +508,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
516
508
|
return resume_value;
|
517
509
|
}
|
518
510
|
RB_GC_GUARD(resume_value);
|
519
|
-
|
511
|
+
|
520
512
|
if (result < 0)
|
521
513
|
rb_syserr_fail(-result, strerror(-result));
|
522
514
|
else {
|
@@ -559,7 +551,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
559
551
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_WRITEV);
|
560
552
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
561
553
|
io_uring_prep_writev(sqe, fptr->fd, iov_ptr, iov_count, -1);
|
562
|
-
|
554
|
+
|
563
555
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
564
556
|
int completed = context_store_release(&backend->store, ctx);
|
565
557
|
if (!completed) {
|
@@ -628,14 +620,13 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
628
620
|
rb_io_check_byte_readable(fptr);
|
629
621
|
io_unset_nonblock(fptr, io);
|
630
622
|
rectify_io_file_pos(fptr);
|
631
|
-
OBJ_TAINT(str);
|
632
623
|
|
633
624
|
while (1) {
|
634
625
|
VALUE resume_value = Qnil;
|
635
626
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
636
627
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
637
628
|
io_uring_prep_recv(sqe, fptr->fd, buf, len - total, 0);
|
638
|
-
|
629
|
+
|
639
630
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
640
631
|
int completed = context_store_release(&backend->store, ctx);
|
641
632
|
if (!completed) {
|
@@ -685,7 +676,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
685
676
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
686
677
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
687
678
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
688
|
-
|
679
|
+
|
689
680
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
690
681
|
int completed = context_store_release(&backend->store, ctx);
|
691
682
|
if (!completed) {
|
@@ -734,7 +725,7 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
734
725
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
|
735
726
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
736
727
|
io_uring_prep_recv(sqe, fptr->fd, buf, len, 0);
|
737
|
-
|
728
|
+
|
738
729
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
739
730
|
int completed = context_store_release(&backend->store, ctx);
|
740
731
|
if (!completed) {
|
@@ -780,7 +771,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
780
771
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
781
772
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
782
773
|
io_uring_prep_send(sqe, fptr->fd, buf, left, flags_int);
|
783
|
-
|
774
|
+
|
784
775
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
785
776
|
int completed = context_store_release(&backend->store, ctx);
|
786
777
|
if (!completed) {
|
@@ -817,7 +808,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
817
808
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_ACCEPT);
|
818
809
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
819
810
|
io_uring_prep_accept(sqe, fptr->fd, &addr, &len, 0);
|
820
|
-
|
811
|
+
|
821
812
|
int fd = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
822
813
|
int completed = context_store_release(&backend->store, ctx);
|
823
814
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -838,7 +829,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
838
829
|
rb_io_synchronized(fp);
|
839
830
|
|
840
831
|
// if (rsock_do_not_reverse_lookup) {
|
841
|
-
|
832
|
+
// fp->mode |= FMODE_NOREVLOOKUP;
|
842
833
|
// }
|
843
834
|
if (loop) {
|
844
835
|
rb_yield(socket);
|
@@ -888,7 +879,7 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
|
|
888
879
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
|
889
880
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
890
881
|
io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
|
891
|
-
|
882
|
+
|
892
883
|
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
893
884
|
int completed = context_store_release(&backend->store, ctx);
|
894
885
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -944,7 +935,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
944
935
|
RAISE_IF_EXCEPTION(resume_value);
|
945
936
|
if (!completed) return resume_value;
|
946
937
|
RB_GC_GUARD(resume_value);
|
947
|
-
|
938
|
+
|
948
939
|
if (result < 0) rb_syserr_fail(-result, strerror(-result));
|
949
940
|
return sock;
|
950
941
|
}
|
@@ -969,7 +960,7 @@ inline struct __kernel_timespec double_to_timespec(double duration) {
|
|
969
960
|
double duration_fraction = modf(duration, &duration_integral);
|
970
961
|
struct __kernel_timespec ts;
|
971
962
|
ts.tv_sec = duration_integral;
|
972
|
-
|
963
|
+
ts.tv_nsec = floor(duration_fraction * 1000000000);
|
973
964
|
return ts;
|
974
965
|
}
|
975
966
|
|
@@ -981,7 +972,7 @@ inline struct __kernel_timespec duration_to_timespec(VALUE duration) {
|
|
981
972
|
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
982
973
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
983
974
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
984
|
-
|
975
|
+
|
985
976
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
986
977
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
987
978
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
@@ -1001,29 +992,34 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
1001
992
|
|
1002
993
|
VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
1003
994
|
Backend_t *backend;
|
1004
|
-
|
995
|
+
uint64_t interval_ns = NUM2DBL(interval) * 1e9;
|
996
|
+
uint64_t next_time_ns = 0;
|
997
|
+
VALUE resume_value = Qnil;
|
998
|
+
|
1005
999
|
GetBackend(self, backend);
|
1006
|
-
double next_time = 0.;
|
1007
1000
|
|
1008
1001
|
while (1) {
|
1009
|
-
double
|
1010
|
-
if (
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
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
|
+
}
|
1019
1014
|
|
1020
1015
|
rb_yield(Qnil);
|
1021
1016
|
|
1022
1017
|
while (1) {
|
1023
|
-
|
1024
|
-
if (
|
1018
|
+
next_time_ns += interval_ns;
|
1019
|
+
if (next_time_ns > now_ns) break;
|
1025
1020
|
}
|
1026
1021
|
}
|
1022
|
+
RB_GC_GUARD(resume_value);
|
1027
1023
|
}
|
1028
1024
|
|
1029
1025
|
struct Backend_timeout_ctx {
|
@@ -1051,7 +1047,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1051
1047
|
VALUE exception;
|
1052
1048
|
VALUE move_on_value = Qnil;
|
1053
1049
|
rb_scan_args(argc, argv, "21", &duration, &exception, &move_on_value);
|
1054
|
-
|
1050
|
+
|
1055
1051
|
struct __kernel_timespec ts = duration_to_timespec(duration);
|
1056
1052
|
Backend_t *backend;
|
1057
1053
|
GetBackend(self, backend);
|
@@ -1059,7 +1055,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1059
1055
|
VALUE timeout = rb_funcall(cTimeoutException, ID_new, 0);
|
1060
1056
|
|
1061
1057
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
1062
|
-
|
1058
|
+
|
1063
1059
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1064
1060
|
ctx->resume_value = timeout;
|
1065
1061
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
@@ -1094,7 +1090,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1094
1090
|
RAISE_IF_EXCEPTION(resume_value);
|
1095
1091
|
RB_GC_GUARD(resume_value);
|
1096
1092
|
}
|
1097
|
-
|
1093
|
+
|
1098
1094
|
int status;
|
1099
1095
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1100
1096
|
if (ret < 0) {
|
@@ -1244,7 +1240,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1244
1240
|
}
|
1245
1241
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1246
1242
|
}
|
1247
|
-
|
1243
|
+
|
1248
1244
|
io_uring_sqe_set_data(last_sqe, ctx);
|
1249
1245
|
unsigned int flags = (i == (argc - 1)) ? IOSQE_ASYNC : IOSQE_ASYNC | IOSQE_IO_LINK;
|
1250
1246
|
io_uring_sqe_set_flags(last_sqe, flags);
|
@@ -1259,7 +1255,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1259
1255
|
int completed = context_store_release(&backend->store, ctx);
|
1260
1256
|
if (!completed) {
|
1261
1257
|
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1262
|
-
|
1258
|
+
|
1263
1259
|
// op was not completed (an exception was raised), so we need to cancel it
|
1264
1260
|
ctx->result = -ECANCELED;
|
1265
1261
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
@@ -1269,7 +1265,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1269
1265
|
RAISE_IF_EXCEPTION(resume_value);
|
1270
1266
|
return resume_value;
|
1271
1267
|
}
|
1272
|
-
|
1268
|
+
|
1273
1269
|
RB_GC_GUARD(resume_value);
|
1274
1270
|
return INT2NUM(result);
|
1275
1271
|
}
|
@@ -1404,7 +1400,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1404
1400
|
|
1405
1401
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1406
1402
|
if (chunk_len == 0) break;
|
1407
|
-
|
1403
|
+
|
1408
1404
|
total += chunk_len;
|
1409
1405
|
chunk_len_value = INT2NUM(chunk_len);
|
1410
1406
|
|
@@ -1526,10 +1522,6 @@ void Init_Backend() {
|
|
1526
1522
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1527
1523
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1528
1524
|
|
1529
|
-
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1530
|
-
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1531
|
-
#endif
|
1532
|
-
|
1533
1525
|
SYM_io_uring = ID2SYM(rb_intern("io_uring"));
|
1534
1526
|
SYM_send = ID2SYM(rb_intern("send"));
|
1535
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);
|
@@ -188,7 +188,7 @@ inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
|
188
188
|
Backend_t *backend;
|
189
189
|
GetBackend(self, backend);
|
190
190
|
|
191
|
-
runqueue_delete(&backend->base.runqueue, fiber);
|
191
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
192
192
|
}
|
193
193
|
|
194
194
|
inline VALUE Backend_switch_fiber(VALUE self) {
|
@@ -287,7 +287,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
287
287
|
io_verify_blocking_mode(fptr, io, Qfalse);
|
288
288
|
rectify_io_file_pos(fptr);
|
289
289
|
watcher.fiber = Qnil;
|
290
|
-
OBJ_TAINT(str);
|
291
290
|
|
292
291
|
while (1) {
|
293
292
|
backend->base.op_count++;
|
@@ -971,7 +970,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
971
970
|
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
972
971
|
|
973
972
|
watcher.fiber = Qnil;
|
974
|
-
|
973
|
+
|
975
974
|
while (1) {
|
976
975
|
backend->base.op_count++;
|
977
976
|
ssize_t n = read(src_fptr->fd, buf, len);
|
@@ -1047,7 +1046,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1047
1046
|
|
1048
1047
|
watcher.fiber = Qnil;
|
1049
1048
|
|
1050
|
-
while (1) {
|
1049
|
+
while (1) {
|
1051
1050
|
char *ptr = buf;
|
1052
1051
|
while (1) {
|
1053
1052
|
backend->base.op_count++;
|
@@ -1147,33 +1146,40 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
1147
1146
|
noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
1148
1147
|
Backend_t *backend;
|
1149
1148
|
struct libev_timer watcher;
|
1150
|
-
double interval_d = NUM2DBL(interval);
|
1151
|
-
|
1152
|
-
GetBackend(self, backend);
|
1153
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;
|
1154
1153
|
|
1155
|
-
|
1154
|
+
GetBackend(self, backend);
|
1156
1155
|
|
1157
1156
|
while (1) {
|
1158
|
-
|
1159
|
-
if (
|
1160
|
-
double sleep_duration =
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
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
|
+
}
|
1171
1174
|
|
1172
1175
|
rb_yield(Qnil);
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
+
|
1177
|
+
while (1) {
|
1178
|
+
next_time_ns += interval_ns;
|
1179
|
+
if (next_time_ns > now_ns) break;
|
1180
|
+
}
|
1176
1181
|
}
|
1182
|
+
RB_GC_GUARD(resume_value);
|
1177
1183
|
}
|
1178
1184
|
|
1179
1185
|
struct libev_timeout {
|
@@ -1219,7 +1225,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1219
1225
|
|
1220
1226
|
struct Backend_timeout_ctx timeout_ctx = {backend, &watcher};
|
1221
1227
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
1222
|
-
|
1228
|
+
|
1223
1229
|
if (result == timeout) {
|
1224
1230
|
if (exception == Qnil) return move_on_value;
|
1225
1231
|
RAISE_EXCEPTION(backend_timeout_exception(exception));
|
@@ -1337,7 +1343,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1337
1343
|
else
|
1338
1344
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1339
1345
|
}
|
1340
|
-
|
1346
|
+
|
1341
1347
|
RB_GC_GUARD(result);
|
1342
1348
|
return result;
|
1343
1349
|
}
|
@@ -1386,14 +1392,14 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1386
1392
|
return 0;
|
1387
1393
|
}
|
1388
1394
|
|
1389
|
-
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,
|
1390
1396
|
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1391
1397
|
#ifdef POLYPHONY_LINUX
|
1392
1398
|
backend->base.op_count++;
|
1393
1399
|
while (1) {
|
1394
1400
|
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1395
1401
|
if (*chunk_len >= 0) return 0;
|
1396
|
-
|
1402
|
+
|
1397
1403
|
int err = errno;
|
1398
1404
|
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1399
1405
|
|
@@ -1489,7 +1495,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1489
1495
|
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1490
1496
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1491
1497
|
if (chunk_len == 0) break;
|
1492
|
-
|
1498
|
+
|
1493
1499
|
total += chunk_len;
|
1494
1500
|
chunk_len_value = INT2NUM(chunk_len);
|
1495
1501
|
|