polyphony 0.71 → 0.74
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 +15 -11
- data/.github/workflows/test_io_uring.yml +32 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +33 -4
- data/Gemfile.lock +16 -13
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- 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 +88 -18
- data/ext/polyphony/backend_common.h +8 -1
- data/ext/polyphony/backend_io_uring.c +280 -164
- data/ext/polyphony/backend_io_uring_context.c +2 -1
- data/ext/polyphony/backend_io_uring_context.h +3 -2
- data/ext/polyphony/backend_libev.c +42 -38
- data/ext/polyphony/event.c +5 -2
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.c +10 -1
- data/ext/polyphony/polyphony.h +7 -1
- data/ext/polyphony/queue.c +12 -7
- data/ext/polyphony/runqueue_ring_buffer.c +6 -3
- data/ext/polyphony/socket_extensions.c +5 -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 +87 -11
- 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 +20 -9
- data/lib/polyphony/extensions/thread.rb +9 -3
- 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 -4
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/test_backend.rb +15 -17
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +31 -7
- data/test/test_global_api.rb +23 -14
- data/test/test_io.rb +5 -5
- data/test/test_kernel.rb +2 -2
- 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 +45 -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 +2 -2
- data/test/test_throttler.rb +3 -3
- data/test/test_timer.rb +3 -3
- data/test/test_trace.rb +1 -1
- metadata +19 -9
|
@@ -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);
|
|
@@ -106,14 +106,14 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
|
106
106
|
|
|
107
107
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize) {
|
|
108
108
|
int already_runnable;
|
|
109
|
+
runqueue_t *runqueue;
|
|
109
110
|
|
|
110
111
|
if (rb_fiber_alive_p(fiber) != Qtrue) return;
|
|
111
112
|
already_runnable = rb_ivar_get(fiber, ID_ivar_runnable) != Qnil;
|
|
112
113
|
|
|
113
114
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
&base->parked_runqueue : &base->runqueue;
|
|
116
|
+
runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ? &base->parked_runqueue : &base->runqueue;
|
|
117
117
|
|
|
118
118
|
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
|
119
119
|
if (!already_runnable) {
|
|
@@ -202,11 +202,40 @@ 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
|
}
|
|
209
208
|
|
|
209
|
+
static inline void free_io_buffer(rb_io_buffer_t *buf)
|
|
210
|
+
{
|
|
211
|
+
if (buf->ptr) {
|
|
212
|
+
ruby_xfree(buf->ptr);
|
|
213
|
+
buf->ptr = NULL;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static inline void clear_codeconv(rb_io_t *fptr) {
|
|
218
|
+
if (fptr->readconv) {
|
|
219
|
+
rb_econv_close(fptr->readconv);
|
|
220
|
+
fptr->readconv = NULL;
|
|
221
|
+
}
|
|
222
|
+
free_io_buffer(&fptr->cbuf);
|
|
223
|
+
|
|
224
|
+
if (fptr->writeconv) {
|
|
225
|
+
rb_econv_close(fptr->writeconv);
|
|
226
|
+
fptr->writeconv = NULL;
|
|
227
|
+
}
|
|
228
|
+
fptr->writeconv_initialized = 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void fptr_finalize(rb_io_t *fptr) {
|
|
232
|
+
fptr->fd = -1;
|
|
233
|
+
fptr->stdio_file = 0;
|
|
234
|
+
free_io_buffer(&fptr->rbuf);
|
|
235
|
+
free_io_buffer(&fptr->wbuf);
|
|
236
|
+
clear_codeconv(fptr);
|
|
237
|
+
}
|
|
238
|
+
|
|
210
239
|
//////////////////////////////////////////////////////////////////////
|
|
211
240
|
//////////////////////////////////////////////////////////////////////
|
|
212
241
|
|
|
@@ -239,13 +268,25 @@ inline void rectify_io_file_pos(rb_io_t *fptr) {
|
|
|
239
268
|
|
|
240
269
|
inline double current_time() {
|
|
241
270
|
struct timespec ts;
|
|
271
|
+
double t;
|
|
272
|
+
uint64_t ns;
|
|
273
|
+
|
|
242
274
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
243
|
-
|
|
275
|
+
ns = ts.tv_sec;
|
|
244
276
|
ns = ns * 1e9 + ts.tv_nsec;
|
|
245
|
-
|
|
277
|
+
t = ns;
|
|
246
278
|
return t / 1e9;
|
|
247
279
|
}
|
|
248
280
|
|
|
281
|
+
inline uint64_t current_time_ns() {
|
|
282
|
+
struct timespec ts;
|
|
283
|
+
uint64_t ns;
|
|
284
|
+
|
|
285
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
286
|
+
ns = ts.tv_sec;
|
|
287
|
+
return ns * 1e9 + ts.tv_nsec;
|
|
288
|
+
}
|
|
289
|
+
|
|
249
290
|
inline VALUE backend_timeout_exception(VALUE exception) {
|
|
250
291
|
if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
|
|
251
292
|
return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
|
|
@@ -270,6 +311,9 @@ VALUE Backend_timeout_ensure_safe(VALUE arg) {
|
|
|
270
311
|
static VALUE empty_string = Qnil;
|
|
271
312
|
|
|
272
313
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
|
|
314
|
+
VALUE joined;
|
|
315
|
+
VALUE result;
|
|
316
|
+
|
|
273
317
|
switch (RARRAY_LEN(ary)) {
|
|
274
318
|
case 0:
|
|
275
319
|
return Qnil;
|
|
@@ -280,14 +324,16 @@ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
|
|
|
280
324
|
empty_string = rb_str_new_literal("");
|
|
281
325
|
rb_global_variable(&empty_string);
|
|
282
326
|
}
|
|
283
|
-
|
|
284
|
-
|
|
327
|
+
joined = rb_ary_join(ary, empty_string);
|
|
328
|
+
result = Backend_send(self, io, joined, flags);
|
|
285
329
|
RB_GC_GUARD(joined);
|
|
286
330
|
return result;
|
|
287
331
|
}
|
|
288
332
|
}
|
|
289
333
|
|
|
290
334
|
inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
335
|
+
int flags;
|
|
336
|
+
int is_nonblocking;
|
|
291
337
|
VALUE blocking_mode = rb_ivar_get(io, ID_ivar_blocking_mode);
|
|
292
338
|
if (blocking == blocking_mode) return;
|
|
293
339
|
|
|
@@ -297,10 +343,10 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
|
297
343
|
if (blocking != Qtrue)
|
|
298
344
|
rb_w32_set_nonblock(fptr->fd);
|
|
299
345
|
#elif defined(F_GETFL)
|
|
300
|
-
|
|
346
|
+
flags = fcntl(fptr->fd, F_GETFL);
|
|
301
347
|
if (flags == -1) return;
|
|
302
|
-
|
|
303
|
-
|
|
348
|
+
is_nonblocking = flags & O_NONBLOCK;
|
|
349
|
+
|
|
304
350
|
if (blocking == Qtrue) {
|
|
305
351
|
if (!is_nonblocking) return;
|
|
306
352
|
flags &= ~O_NONBLOCK;
|
|
@@ -313,12 +359,14 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
|
313
359
|
}
|
|
314
360
|
|
|
315
361
|
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
|
362
|
+
double now;
|
|
363
|
+
|
|
316
364
|
if (base->idle_proc != Qnil)
|
|
317
365
|
rb_funcall(base->idle_proc, ID_call, 0);
|
|
318
366
|
|
|
319
367
|
if (base->idle_gc_period == 0) return;
|
|
320
368
|
|
|
321
|
-
|
|
369
|
+
now = current_time();
|
|
322
370
|
if (now - base->idle_gc_last_time < base->idle_gc_period) return;
|
|
323
371
|
|
|
324
372
|
base->idle_gc_last_time = now;
|
|
@@ -375,7 +423,7 @@ void backend_setup_stats_symbols() {
|
|
|
375
423
|
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
|
376
424
|
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
|
377
425
|
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
|
378
|
-
|
|
426
|
+
|
|
379
427
|
rb_global_variable(&SYM_runqueue_size);
|
|
380
428
|
rb_global_variable(&SYM_runqueue_length);
|
|
381
429
|
rb_global_variable(&SYM_runqueue_max_length);
|
|
@@ -383,4 +431,26 @@ void backend_setup_stats_symbols() {
|
|
|
383
431
|
rb_global_variable(&SYM_switch_count);
|
|
384
432
|
rb_global_variable(&SYM_poll_count);
|
|
385
433
|
rb_global_variable(&SYM_pending_ops);
|
|
386
|
-
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
int backend_getaddrinfo(VALUE host, VALUE port, struct sockaddr **ai_addr) {
|
|
437
|
+
VALUE port_string;
|
|
438
|
+
struct addrinfo hints;
|
|
439
|
+
struct addrinfo *addrinfo_result;
|
|
440
|
+
int ret;
|
|
441
|
+
|
|
442
|
+
memset(&hints, 0, sizeof(struct addrinfo));
|
|
443
|
+
hints.ai_family = AF_UNSPEC; /* allow IPv4 or IPv6 */
|
|
444
|
+
hints.ai_socktype = SOCK_STREAM;
|
|
445
|
+
|
|
446
|
+
port_string = rb_funcall(port, ID_to_s, 0);
|
|
447
|
+
ret = getaddrinfo(StringValueCStr(host), StringValueCStr(port_string), &hints, &addrinfo_result);
|
|
448
|
+
RB_GC_GUARD(port_string);
|
|
449
|
+
if (ret != 0) {
|
|
450
|
+
VALUE msg = rb_str_new2(gai_strerror(ret));
|
|
451
|
+
rb_funcall(rb_mKernel, ID_raise, 1, msg);
|
|
452
|
+
RB_GC_GUARD(msg);
|
|
453
|
+
}
|
|
454
|
+
*ai_addr = addrinfo_result->ai_addr;
|
|
455
|
+
return addrinfo_result->ai_addrlen;
|
|
456
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#ifndef BACKEND_COMMON_H
|
|
2
2
|
#define BACKEND_COMMON_H
|
|
3
3
|
|
|
4
|
+
#include <sys/types.h>
|
|
5
|
+
#include <arpa/inet.h>
|
|
6
|
+
#include <netinet/in.h>
|
|
7
|
+
#include <netdb.h>
|
|
8
|
+
|
|
4
9
|
#include "ruby.h"
|
|
5
10
|
#include "ruby/io.h"
|
|
6
11
|
#include "runqueue.h"
|
|
@@ -68,6 +73,7 @@ void io_shrink_read_string(VALUE str, long n);
|
|
|
68
73
|
void io_set_read_length(VALUE str, long n, int shrinkable);
|
|
69
74
|
rb_encoding* io_read_encoding(rb_io_t *fptr);
|
|
70
75
|
VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
|
76
|
+
void fptr_finalize(rb_io_t *fptr);
|
|
71
77
|
|
|
72
78
|
//////////////////////////////////////////////////////////////////////
|
|
73
79
|
//////////////////////////////////////////////////////////////////////
|
|
@@ -82,7 +88,6 @@ VALUE backend_snooze();
|
|
|
82
88
|
shrinkable = io_setstrbuf(&str, len); \
|
|
83
89
|
buf = RSTRING_PTR(str); \
|
|
84
90
|
total = 0; \
|
|
85
|
-
OBJ_TAINT(str); \
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
#define READ_LOOP_YIELD_STR() { \
|
|
@@ -101,6 +106,7 @@ VALUE backend_snooze();
|
|
|
101
106
|
|
|
102
107
|
void rectify_io_file_pos(rb_io_t *fptr);
|
|
103
108
|
double current_time();
|
|
109
|
+
uint64_t current_time_ns();
|
|
104
110
|
VALUE backend_timeout_exception(VALUE exception);
|
|
105
111
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
|
106
112
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
|
@@ -109,5 +115,6 @@ VALUE Backend_stats(VALUE self);
|
|
|
109
115
|
void backend_run_idle_tasks(struct Backend_base *base);
|
|
110
116
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
|
111
117
|
void backend_setup_stats_symbols();
|
|
118
|
+
int backend_getaddrinfo(VALUE host, VALUE port, struct sockaddr **ai_addr);
|
|
112
119
|
|
|
113
120
|
#endif /* BACKEND_COMMON_H */
|