polyphony 1.4 → 1.6
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +22 -0
- data/TODO.md +5 -14
- data/examples/pipes/http_server.rb +42 -12
- data/examples/pipes/http_server2.rb +45 -0
- data/ext/polyphony/backend_common.h +5 -0
- data/ext/polyphony/backend_io_uring.c +174 -121
- data/ext/polyphony/backend_io_uring_context.c +24 -18
- data/ext/polyphony/backend_io_uring_context.h +4 -2
- data/ext/polyphony/backend_libev.c +46 -22
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +25 -19
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/pipe.c +1 -1
- data/ext/polyphony/polyphony.c +2 -20
- data/ext/polyphony/polyphony.h +5 -5
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +1 -0
- data/ext/polyphony/thread.c +63 -0
- data/ext/polyphony/win_uio.h +18 -0
- data/lib/polyphony/adapters/open3.rb +190 -0
- data/lib/polyphony/core/sync.rb +83 -13
- data/lib/polyphony/core/timer.rb +7 -25
- data/lib/polyphony/extensions/exception.rb +15 -0
- data/lib/polyphony/extensions/fiber.rb +14 -13
- data/lib/polyphony/extensions/io.rb +56 -14
- data/lib/polyphony/extensions/kernel.rb +1 -1
- data/lib/polyphony/extensions/object.rb +1 -13
- data/lib/polyphony/extensions/process.rb +76 -1
- data/lib/polyphony/extensions/socket.rb +0 -14
- data/lib/polyphony/extensions/thread.rb +19 -27
- data/lib/polyphony/extensions/timeout.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +11 -5
- data/test/helper.rb +46 -4
- data/test/open3/envutil.rb +380 -0
- data/test/open3/find_executable.rb +24 -0
- data/test/stress.rb +11 -7
- data/test/test_backend.rb +11 -4
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +16 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +17 -16
- data/test/test_io.rb +39 -0
- data/test/test_kernel.rb +2 -2
- data/test/test_monitor.rb +356 -0
- data/test/test_open3.rb +338 -0
- data/test/test_signal.rb +5 -1
- data/test/test_socket.rb +6 -98
- data/test/test_sync.rb +46 -0
- data/test/test_thread.rb +10 -1
- data/test/test_thread_pool.rb +5 -0
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +8 -2
- data/test/test_trace.rb +2 -0
- data/vendor/liburing/.github/workflows/build.yml +8 -0
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +8 -0
- data/vendor/liburing/configure +17 -25
- data/vendor/liburing/debian/liburing-dev.manpages +2 -0
- data/vendor/liburing/debian/rules +2 -1
- data/vendor/liburing/examples/Makefile +2 -1
- data/vendor/liburing/examples/io_uring-udp.c +11 -3
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/make-debs.sh +4 -2
- data/vendor/liburing/src/Makefile +5 -5
- data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
- data/vendor/liburing/src/include/liburing.h +86 -11
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/liburing-ffi.map +12 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/register.c +7 -2
- data/vendor/liburing/src/setup.c +373 -81
- data/vendor/liburing/test/232c93d07b74.c +3 -3
- data/vendor/liburing/test/Makefile +10 -3
- data/vendor/liburing/test/accept.c +2 -1
- data/vendor/liburing/test/buf-ring.c +35 -75
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/coredump.c +59 -0
- data/vendor/liburing/test/fallocate.c +9 -0
- data/vendor/liburing/test/fd-pass.c +34 -3
- data/vendor/liburing/test/file-verify.c +27 -6
- data/vendor/liburing/test/helpers.c +3 -1
- data/vendor/liburing/test/io_uring_register.c +25 -28
- data/vendor/liburing/test/io_uring_setup.c +1 -1
- data/vendor/liburing/test/poll-cancel-all.c +29 -5
- data/vendor/liburing/test/poll-race-mshot.c +6 -22
- data/vendor/liburing/test/read-write.c +53 -0
- data/vendor/liburing/test/recv-msgall.c +21 -23
- data/vendor/liburing/test/reg-fd-only.c +55 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/ringbuf-read.c +2 -10
- data/vendor/liburing/test/send_recvmsg.c +5 -16
- data/vendor/liburing/test/shutdown.c +2 -1
- data/vendor/liburing/test/socket-io-cmd.c +215 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -1
- data/vendor/liburing/test/socket-rw-offset.c +2 -1
- data/vendor/liburing/test/socket-rw.c +2 -1
- data/vendor/liburing/test/timeout.c +276 -0
- data/vendor/liburing/test/xattr.c +38 -25
- metadata +20 -7
- data/vendor/liburing/test/timeout-overflow.c +0 -204
@@ -6,20 +6,23 @@
|
|
6
6
|
|
7
7
|
const char *op_type_to_str(enum op_type type) {
|
8
8
|
switch (type) {
|
9
|
-
case OP_ACCEPT:
|
10
|
-
case OP_CHAIN:
|
11
|
-
case OP_CLOSE:
|
12
|
-
case OP_CONNECT:
|
13
|
-
case OP_POLL:
|
14
|
-
case OP_READ:
|
15
|
-
case OP_RECV:
|
16
|
-
case OP_RECVMSG:
|
17
|
-
case OP_SEND:
|
18
|
-
case OP_SENDMSG:
|
19
|
-
case OP_SPLICE:
|
20
|
-
case OP_TIMEOUT:
|
21
|
-
case OP_WRITEV:
|
22
|
-
case OP_WRITE:
|
9
|
+
case OP_ACCEPT: return "ACCEPT";
|
10
|
+
case OP_CHAIN: return "CHAIN";
|
11
|
+
case OP_CLOSE: return "CLOSE";
|
12
|
+
case OP_CONNECT: return "CONNECT";
|
13
|
+
case OP_POLL: return "POLL";
|
14
|
+
case OP_READ: return "READ";
|
15
|
+
case OP_RECV: return "RECV";
|
16
|
+
case OP_RECVMSG: return "RECVMSG";
|
17
|
+
case OP_SEND: return "SEND";
|
18
|
+
case OP_SENDMSG: return "SENDMSG";
|
19
|
+
case OP_SPLICE: return "SPLICE";
|
20
|
+
case OP_TIMEOUT: return "TIMEOUT";
|
21
|
+
case OP_WRITEV: return "WRITEV";
|
22
|
+
case OP_WRITE: return "WRITE";
|
23
|
+
|
24
|
+
case OP_MULTISHOT_ACCEPT: return "ACCEPT MULTISHOT";
|
25
|
+
case OP_MULTISHOT_TIMEOUT: return "ACCEPT MULTISHOT";
|
23
26
|
|
24
27
|
default: return "";
|
25
28
|
};
|
@@ -71,14 +74,15 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
71
74
|
|
72
75
|
// If a multishot ctx is released, we pretend its ref count is 1, so it will
|
73
76
|
// be returned to the store.
|
74
|
-
if (ctx->ref_count == MULTISHOT_REFCOUNT)
|
75
|
-
ctx->ref_count = 1;
|
76
|
-
}
|
77
|
+
if (ctx->ref_count == MULTISHOT_REFCOUNT) ctx->ref_count = 1;
|
77
78
|
|
78
79
|
ctx->ref_count--;
|
79
80
|
if (ctx->ref_count) return 0;
|
80
81
|
|
81
|
-
if (ctx->buffer_count > 1)
|
82
|
+
if (ctx->buffer_count > 1) {
|
83
|
+
TRACE_FREE(ctx->buffers);
|
84
|
+
free(ctx->buffers);
|
85
|
+
}
|
82
86
|
|
83
87
|
store->taken_count--;
|
84
88
|
store->available_count++;
|
@@ -97,11 +101,13 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
97
101
|
void context_store_free(op_context_store_t *store) {
|
98
102
|
while (store->available) {
|
99
103
|
op_context_t *next = store->available->next;
|
104
|
+
TRACE_FREE(store->available);
|
100
105
|
free(store->available);
|
101
106
|
store->available = next;
|
102
107
|
}
|
103
108
|
while (store->taken) {
|
104
109
|
op_context_t *next = store->taken->next;
|
110
|
+
TRACE_FREE(store->taken);
|
105
111
|
free(store->taken);
|
106
112
|
store->taken = next;
|
107
113
|
}
|
@@ -8,7 +8,6 @@ enum op_type {
|
|
8
8
|
OP_CHAIN,
|
9
9
|
OP_CLOSE,
|
10
10
|
OP_CONNECT,
|
11
|
-
OP_MULTISHOT_ACCEPT,
|
12
11
|
OP_NONE,
|
13
12
|
OP_POLL,
|
14
13
|
OP_READ,
|
@@ -19,7 +18,9 @@ enum op_type {
|
|
19
18
|
OP_SPLICE,
|
20
19
|
OP_TIMEOUT,
|
21
20
|
OP_WRITEV,
|
22
|
-
OP_WRITE
|
21
|
+
OP_WRITE,
|
22
|
+
OP_MULTISHOT_ACCEPT,
|
23
|
+
OP_MULTISHOT_TIMEOUT
|
23
24
|
};
|
24
25
|
|
25
26
|
#define MULTISHOT_REFCOUNT 0xFFFF
|
@@ -36,6 +37,7 @@ typedef struct op_context {
|
|
36
37
|
unsigned int buffer_count;
|
37
38
|
VALUE buffer0;
|
38
39
|
VALUE *buffers;
|
40
|
+
double ts; // timestamp for tracing
|
39
41
|
} op_context_t;
|
40
42
|
|
41
43
|
typedef struct op_context_store {
|
@@ -42,21 +42,24 @@ thread.
|
|
42
42
|
#define _GNU_SOURCE 1
|
43
43
|
#endif
|
44
44
|
|
45
|
-
#include <netdb.h>
|
46
|
-
#include <sys/socket.h>
|
47
|
-
#include <sys/uio.h>
|
48
45
|
#include <unistd.h>
|
49
|
-
#include <netinet/in.h>
|
50
|
-
#include <arpa/inet.h>
|
51
46
|
#include <stdnoreturn.h>
|
52
47
|
#include <sys/types.h>
|
48
|
+
|
49
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
53
50
|
#include <sys/wait.h>
|
51
|
+
#endif
|
52
|
+
|
54
53
|
#include <fcntl.h>
|
55
54
|
|
56
55
|
#include "polyphony.h"
|
57
56
|
#include "../libev/ev.h"
|
58
57
|
#include "ruby/io.h"
|
59
58
|
|
59
|
+
#ifndef POLYPHONY_WINDOWS
|
60
|
+
#include <sys/uio.h>
|
61
|
+
#endif
|
62
|
+
|
60
63
|
#include "../libev/ev.h"
|
61
64
|
#include "backend_common.h"
|
62
65
|
|
@@ -267,21 +270,25 @@ VALUE libev_wait_fd(Backend_t *backend, int fd, int events, int raise_exception)
|
|
267
270
|
}
|
268
271
|
|
269
272
|
static inline int fd_from_io(VALUE io, rb_io_t **fptr, int write_mode, int rectify_file_pos) {
|
273
|
+
if (TYPE(io) == T_FIXNUM) {
|
274
|
+
*fptr = NULL;
|
275
|
+
return FIX2INT(io);
|
276
|
+
}
|
277
|
+
|
270
278
|
if (rb_obj_class(io) == cPipe) {
|
271
279
|
*fptr = NULL;
|
272
280
|
Pipe_verify_blocking_mode(io, Qfalse);
|
273
281
|
return Pipe_get_fd(io, write_mode);
|
274
282
|
}
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
}
|
283
|
+
|
284
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
285
|
+
if (underlying_io != Qnil) io = underlying_io;
|
286
|
+
|
287
|
+
GetOpenFile(io, *fptr);
|
288
|
+
int fd = rb_io_descriptor(io);
|
289
|
+
io_verify_blocking_mode(io, fd, Qfalse);
|
290
|
+
if (rectify_file_pos) rectify_io_file_pos(*fptr);
|
291
|
+
return fd;
|
285
292
|
}
|
286
293
|
|
287
294
|
VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eof, VALUE pos) {
|
@@ -558,6 +565,7 @@ error:
|
|
558
565
|
return RAISE_EXCEPTION(switchpoint_result);
|
559
566
|
}
|
560
567
|
|
568
|
+
#ifndef POLYPHONY_WINDOWS
|
561
569
|
VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
562
570
|
Backend_t *backend;
|
563
571
|
struct libev_io watcher;
|
@@ -629,15 +637,23 @@ error:
|
|
629
637
|
free(iov);
|
630
638
|
return RAISE_EXCEPTION(switchpoint_result);
|
631
639
|
}
|
640
|
+
#endif
|
632
641
|
|
633
642
|
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
634
643
|
if (argc < 2)
|
635
644
|
// TODO: raise ArgumentError
|
636
645
|
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
637
646
|
|
647
|
+
#ifdef POLYPHONY_WINDOWS
|
648
|
+
int total = 0;
|
649
|
+
for (int i = 1; i < argc; i++)
|
650
|
+
total += FIX2INT(Backend_write(self, argv[0], argv[i]));
|
651
|
+
return INT2FIX(total);
|
652
|
+
#else
|
638
653
|
return (argc == 2) ?
|
639
654
|
Backend_write(self, argv[0], argv[1]) :
|
640
655
|
Backend_writev(self, argv[0], argc - 1, argv + 1);
|
656
|
+
#endif
|
641
657
|
}
|
642
658
|
|
643
659
|
VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
@@ -1155,7 +1171,7 @@ VALUE Backend_close(VALUE self, VALUE io) {
|
|
1155
1171
|
RAISE_IF_EXCEPTION(resume_value);
|
1156
1172
|
RB_GC_GUARD(resume_value);
|
1157
1173
|
|
1158
|
-
fptr_finalize(fptr);
|
1174
|
+
if (fptr) fptr_finalize(fptr);
|
1159
1175
|
// fd = -1;
|
1160
1176
|
return io;
|
1161
1177
|
}
|
@@ -1309,7 +1325,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1309
1325
|
int e = errno;
|
1310
1326
|
rb_syserr_fail(e, strerror(e));
|
1311
1327
|
}
|
1312
|
-
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(
|
1328
|
+
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(status));
|
1313
1329
|
}
|
1314
1330
|
#else
|
1315
1331
|
struct libev_child {
|
@@ -1317,16 +1333,18 @@ struct libev_child {
|
|
1317
1333
|
VALUE fiber;
|
1318
1334
|
};
|
1319
1335
|
|
1336
|
+
#ifndef POLYPHONY_WINDOWS
|
1320
1337
|
void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
1321
1338
|
struct libev_child *watcher = (struct libev_child *)w;
|
1322
|
-
|
1323
|
-
VALUE status;
|
1324
|
-
|
1325
|
-
status = rb_ary_new_from_args(2, INT2FIX(w->rpid), INT2FIX(exit_status));
|
1339
|
+
VALUE status = rb_ary_new_from_args(2, INT2FIX(w->rpid), INT2FIX(w->rstatus));
|
1326
1340
|
Fiber_make_runnable(watcher->fiber, status);
|
1327
1341
|
}
|
1342
|
+
#endif
|
1328
1343
|
|
1329
1344
|
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
1345
|
+
#ifdef POLYPHONY_WINDOWS
|
1346
|
+
rb_raise(rb_eStandardError, "Not implemented");
|
1347
|
+
#else
|
1330
1348
|
Backend_t *backend;
|
1331
1349
|
struct libev_child watcher;
|
1332
1350
|
VALUE switchpoint_result = Qnil;
|
@@ -1344,8 +1362,9 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1344
1362
|
RB_GC_GUARD(watcher.fiber);
|
1345
1363
|
RB_GC_GUARD(switchpoint_result);
|
1346
1364
|
return switchpoint_result;
|
1365
|
+
#endif // #ifdef POLYPHONY_WINDOWS
|
1347
1366
|
}
|
1348
|
-
#endif
|
1367
|
+
#endif // #ifdef POLYPHONY_USE_PIDFD_OPEN
|
1349
1368
|
|
1350
1369
|
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
1351
1370
|
|
@@ -1497,6 +1516,7 @@ done:
|
|
1497
1516
|
#endif
|
1498
1517
|
}
|
1499
1518
|
|
1519
|
+
#ifdef POLYPHONY_LINUX
|
1500
1520
|
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1501
1521
|
Backend_t *backend;
|
1502
1522
|
GetBackend(self, backend);
|
@@ -1586,6 +1606,7 @@ error:
|
|
1586
1606
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1587
1607
|
return RAISE_EXCEPTION(result);
|
1588
1608
|
}
|
1609
|
+
#endif
|
1589
1610
|
|
1590
1611
|
VALUE Backend_trace(int argc, VALUE *argv, VALUE self) {
|
1591
1612
|
Backend_t *backend;
|
@@ -1651,7 +1672,10 @@ void Init_Backend(void) {
|
|
1651
1672
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1652
1673
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1653
1674
|
rb_define_method(cBackend, "idle_proc=", Backend_idle_proc_set, 1);
|
1675
|
+
|
1676
|
+
#ifdef POLYPHONY_LINUX
|
1654
1677
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1678
|
+
#endif
|
1655
1679
|
|
1656
1680
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1657
1681
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
data/ext/polyphony/event.c
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
typedef struct event {
|
5
5
|
VALUE waiting_fiber;
|
6
|
+
int signaled;
|
7
|
+
VALUE result;
|
6
8
|
} Event_t;
|
7
9
|
|
8
10
|
VALUE cEvent = Qnil;
|
@@ -10,6 +12,7 @@ VALUE cEvent = Qnil;
|
|
10
12
|
static void Event_mark(void *ptr) {
|
11
13
|
Event_t *event = ptr;
|
12
14
|
rb_gc_mark(event->waiting_fiber);
|
15
|
+
rb_gc_mark(event->result);
|
13
16
|
}
|
14
17
|
|
15
18
|
static void Event_free(void *ptr) {
|
@@ -41,6 +44,8 @@ static VALUE Event_initialize(VALUE self) {
|
|
41
44
|
GetEvent(self, event);
|
42
45
|
|
43
46
|
event->waiting_fiber = Qnil;
|
47
|
+
event->signaled = 0;
|
48
|
+
event->result = Qnil;
|
44
49
|
|
45
50
|
return self;
|
46
51
|
}
|
@@ -50,10 +55,17 @@ VALUE Event_signal(int argc, VALUE *argv, VALUE self) {
|
|
50
55
|
Event_t *event;
|
51
56
|
GetEvent(self, event);
|
52
57
|
|
58
|
+
if (event->signaled) goto done;
|
59
|
+
|
60
|
+
event->signaled = 1;
|
61
|
+
event->result = value;
|
62
|
+
|
53
63
|
if (event->waiting_fiber != Qnil) {
|
54
64
|
Fiber_make_runnable(event->waiting_fiber, value);
|
55
65
|
event->waiting_fiber = Qnil;
|
56
66
|
}
|
67
|
+
|
68
|
+
done:
|
57
69
|
return self;
|
58
70
|
}
|
59
71
|
|
@@ -67,10 +79,19 @@ VALUE Event_await(VALUE self) {
|
|
67
79
|
if (event->waiting_fiber != Qnil)
|
68
80
|
rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
|
69
81
|
|
82
|
+
if (event->signaled) {
|
83
|
+
VALUE result = event->result;
|
84
|
+
event->signaled = 0;
|
85
|
+
event->result = Qnil;
|
86
|
+
return result;
|
87
|
+
}
|
88
|
+
|
70
89
|
backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
71
90
|
event->waiting_fiber = rb_fiber_current();
|
72
91
|
switchpoint_result = Backend_wait_event(backend, Qnil);
|
73
92
|
event->waiting_fiber = Qnil;
|
93
|
+
event->signaled = 0;
|
94
|
+
event->result = Qnil;
|
74
95
|
|
75
96
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
76
97
|
RB_GC_GUARD(backend);
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'mkmf'
|
5
|
+
require 'rbconfig'
|
5
6
|
|
6
7
|
dir_config 'polyphony_ext'
|
7
8
|
|
8
9
|
KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
|
9
10
|
def get_config
|
10
11
|
config = { linux: !!(RUBY_PLATFORM =~ /linux/) }
|
12
|
+
config[:windows] = !!(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
|
11
13
|
return config if !config[:linux]
|
12
14
|
|
13
15
|
kernel_info = `uname -sr`
|
@@ -17,11 +19,13 @@ def get_config
|
|
17
19
|
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[4]
|
18
20
|
|
19
21
|
combined_version = version.to_i * 100 + major_revision.to_i
|
20
|
-
|
22
|
+
|
23
|
+
config[:kernel_version] = combined_version
|
21
24
|
config[:pidfd_open] = combined_version > 503
|
25
|
+
config[:multishot_accept] = combined_version >= 519
|
22
26
|
config[:multishot_recv] = combined_version >= 600
|
23
27
|
config[:multishot_recvmsg] = combined_version >= 600
|
24
|
-
config[:
|
28
|
+
config[:multishot_timeout] = combined_version >= 640
|
25
29
|
config[:submit_all_flag] = combined_version >= 518
|
26
30
|
config[:coop_taskrun_flag] = combined_version >= 519
|
27
31
|
|
@@ -31,7 +35,7 @@ def get_config
|
|
31
35
|
end
|
32
36
|
|
33
37
|
config = get_config
|
34
|
-
puts "Building Polyphony
|
38
|
+
puts "Building Polyphony (\n#{config.map { |(k, v)| " #{k}: #{v}\n"}.join})"
|
35
39
|
|
36
40
|
require_relative 'zlib_conf'
|
37
41
|
|
@@ -59,20 +63,22 @@ end
|
|
59
63
|
|
60
64
|
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
61
65
|
if config[:io_uring]
|
62
|
-
$defs <<
|
63
|
-
$defs <<
|
64
|
-
$defs <<
|
65
|
-
$defs <<
|
66
|
-
$defs <<
|
67
|
-
$defs <<
|
68
|
-
$defs <<
|
69
|
-
$defs <<
|
70
|
-
$
|
66
|
+
$defs << '-DPOLYPHONY_BACKEND_LIBURING'
|
67
|
+
$defs << '-DPOLYPHONY_LINUX'
|
68
|
+
$defs << '-DPOLYPHONY_UNSET_NONBLOCK' if RUBY_VERSION =~ /^3/
|
69
|
+
$defs << '-DHAVE_IO_URING_PREP_MULTISHOT_ACCEPT' if config[:multishot_accept]
|
70
|
+
$defs << '-DHAVE_IO_URING_PREP_RECV_MULTISHOT' if config[:multishot_recv]
|
71
|
+
$defs << '-DHAVE_IO_URING_PREP_RECVMSG_MULTISHOT' if config[:multishot_recvmsg]
|
72
|
+
$defs << '-DHAVE_IO_URING_TIMEOUT_MULTISHOT' if config[:multishot_timeout]
|
73
|
+
$defs << '-DHAVE_IORING_SETUP_SUBMIT_ALL' if config[:submit_all_flag]
|
74
|
+
$defs << '-DHAVE_IORING_SETUP_COOP_TASKRUN' if config[:coop_taskrun_flag]
|
75
|
+
$CFLAGS << ' -Wno-pointer-arith'
|
71
76
|
else
|
72
|
-
$defs <<
|
73
|
-
$defs <<
|
77
|
+
$defs << '-DPOLYPHONY_BACKEND_LIBEV'
|
78
|
+
$defs << '-DPOLYPHONY_LINUX' if config[:linux]
|
79
|
+
$defs << '-DPOLYPHONY_WINDOWS' if config[:windows]
|
74
80
|
|
75
|
-
$defs <<
|
81
|
+
$defs << '-DEV_STANDALONE' # prevent libev from assuming "config.h" exists
|
76
82
|
|
77
83
|
define_bool('EV_USE_EPOLL', have_header('sys/epoll.h'))
|
78
84
|
define_bool('EV_USE_KQUEUE', have_header('sys/event.h') && have_header('sys/queue.h'))
|
@@ -84,10 +90,10 @@ else
|
|
84
90
|
|
85
91
|
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
86
92
|
|
87
|
-
$CFLAGS <<
|
88
|
-
$CFLAGS <<
|
89
|
-
$CFLAGS <<
|
90
|
-
$CFLAGS <<
|
93
|
+
$CFLAGS << ' -Wno-comment'
|
94
|
+
$CFLAGS << ' -Wno-unused-result'
|
95
|
+
$CFLAGS << ' -Wno-dangling-else'
|
96
|
+
$CFLAGS << ' -Wno-parentheses'
|
91
97
|
end
|
92
98
|
|
93
99
|
$defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
|
data/ext/polyphony/fiber.c
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
ID ID_ivar_auto_watcher;
|
5
5
|
ID ID_ivar_mailbox;
|
6
|
-
ID ID_ivar_result;
|
7
6
|
ID ID_ivar_waiting_fibers;
|
8
7
|
|
9
8
|
VALUE SYM_dead;
|
@@ -239,7 +238,6 @@ void Init_Fiber(void) {
|
|
239
238
|
|
240
239
|
ID_ivar_auto_watcher = rb_intern("@auto_watcher");
|
241
240
|
ID_ivar_mailbox = rb_intern("@mailbox");
|
242
|
-
ID_ivar_result = rb_intern("@result");
|
243
241
|
ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
|
244
242
|
|
245
243
|
SYM_spin = ID2SYM(rb_intern("spin"));
|
data/ext/polyphony/pipe.c
CHANGED
@@ -97,8 +97,8 @@ VALUE Pipe_close(VALUE self) {
|
|
97
97
|
if (pipe->w_closed)
|
98
98
|
rb_raise(rb_eRuntimeError, "Pipe is already closed for writing");
|
99
99
|
|
100
|
+
Backend_close(BACKEND(), INT2FIX(pipe->fds[1]));
|
100
101
|
pipe->w_closed = 1;
|
101
|
-
close(pipe->fds[1]);
|
102
102
|
return self;
|
103
103
|
}
|
104
104
|
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -13,6 +13,7 @@ ID ID_ivar_blocking_mode;
|
|
13
13
|
ID ID_ivar_io;
|
14
14
|
ID ID_ivar_multishot_accept_queue;
|
15
15
|
ID ID_ivar_parked;
|
16
|
+
ID ID_ivar_result;
|
16
17
|
ID ID_ivar_runnable;
|
17
18
|
ID ID_ivar_running;
|
18
19
|
ID ID_ivar_thread;
|
@@ -80,20 +81,6 @@ VALUE Polyphony_backend_accept_loop(VALUE self, VALUE server_socket, VALUE socke
|
|
80
81
|
return Backend_accept_loop(BACKEND(), server_socket, socket_class);
|
81
82
|
}
|
82
83
|
|
83
|
-
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
84
|
-
/* Starts a multishot accept operation on the given server socket. This API is
|
85
|
-
* available only for the io_uring backend.
|
86
|
-
*
|
87
|
-
* @param server_socket [Socket] socket to accept on
|
88
|
-
* @return [any] block return value
|
89
|
-
*/
|
90
|
-
|
91
|
-
VALUE Polyphony_backend_multishot_accept(VALUE self, VALUE server_socket) {
|
92
|
-
return Backend_multishot_accept(BACKEND(), server_socket);
|
93
|
-
}
|
94
|
-
#endif
|
95
|
-
|
96
|
-
|
97
84
|
/* Connects the given socket to the given address and port.
|
98
85
|
*
|
99
86
|
* @param io [Socket] socket to connect
|
@@ -433,12 +420,6 @@ void Init_Polyphony(void) {
|
|
433
420
|
rb_define_singleton_method(mPolyphony, "backend_accept_loop", Polyphony_backend_accept_loop, 2);
|
434
421
|
rb_define_singleton_method(mPolyphony, "backend_connect", Polyphony_backend_connect, 3);
|
435
422
|
rb_define_singleton_method(mPolyphony, "backend_feed_loop", Polyphony_backend_feed_loop, 3);
|
436
|
-
|
437
|
-
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
438
|
-
rb_define_singleton_method(mPolyphony, "backend_multishot_accept", Polyphony_backend_multishot_accept, 1);
|
439
|
-
#endif
|
440
|
-
|
441
|
-
|
442
423
|
rb_define_singleton_method(mPolyphony, "backend_read", Polyphony_backend_read, 5);
|
443
424
|
rb_define_singleton_method(mPolyphony, "backend_read_loop", Polyphony_backend_read_loop, 2);
|
444
425
|
rb_define_singleton_method(mPolyphony, "backend_recv", Polyphony_backend_recv, 4);
|
@@ -494,6 +475,7 @@ void Init_Polyphony(void) {
|
|
494
475
|
ID_ivar_io = rb_intern("@io");
|
495
476
|
ID_ivar_multishot_accept_queue = rb_intern("@multishot_accept_queue");
|
496
477
|
ID_ivar_parked = rb_intern("@parked");
|
478
|
+
ID_ivar_result = rb_intern("@result");
|
497
479
|
ID_ivar_runnable = rb_intern("@runnable");
|
498
480
|
ID_ivar_running = rb_intern("@running");
|
499
481
|
ID_ivar_thread = rb_intern("@thread");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
|
11
11
|
#define CALLER() rb_funcall(rb_mKernel, rb_intern("caller"), 0)
|
12
12
|
#define TRACE_CALLER() INSPECT("caller: ", CALLER())
|
13
|
+
#define TRACE_FREE(ptr) //printf("Free %p %s:%d\n", ptr, __FILE__, __LINE__)
|
13
14
|
|
14
15
|
// exceptions
|
15
16
|
#define TEST_EXCEPTION(ret) (rb_obj_is_kind_of(ret, rb_eException) == Qtrue)
|
@@ -47,6 +48,7 @@ extern ID ID_ivar_blocking_mode;
|
|
47
48
|
extern ID ID_ivar_io;
|
48
49
|
extern ID ID_ivar_multishot_accept_queue;
|
49
50
|
extern ID ID_ivar_parked;
|
51
|
+
extern ID ID_ivar_result;
|
50
52
|
extern ID ID_ivar_runnable;
|
51
53
|
extern ID ID_ivar_running;
|
52
54
|
extern ID ID_ivar_thread;
|
@@ -101,11 +103,6 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class);
|
|
101
103
|
VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class);
|
102
104
|
VALUE Backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port);
|
103
105
|
VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
|
104
|
-
|
105
|
-
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
106
|
-
VALUE Backend_multishot_accept(VALUE self, VALUE io);
|
107
|
-
#endif
|
108
|
-
|
109
106
|
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos);
|
110
107
|
VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen);
|
111
108
|
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos);
|
@@ -152,6 +149,9 @@ void Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
|
152
149
|
void Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
|
153
150
|
VALUE Thread_switch_fiber(VALUE thread);
|
154
151
|
|
152
|
+
VALUE Event_signal(int argc, VALUE *argv, VALUE event);
|
153
|
+
VALUE Event_await(VALUE event);
|
154
|
+
|
155
155
|
VALUE Polyphony_snooze(VALUE self);
|
156
156
|
|
157
157
|
#endif /* POLYPHONY_H */
|
data/ext/polyphony/ring_buffer.c
CHANGED
data/ext/polyphony/thread.c
CHANGED
@@ -3,9 +3,12 @@
|
|
3
3
|
|
4
4
|
ID ID_deactivate_all_watchers_post_fork;
|
5
5
|
ID ID_ivar_backend;
|
6
|
+
ID ID_ivar_done;
|
6
7
|
ID ID_ivar_join_wait_queue;
|
7
8
|
ID ID_ivar_main_fiber;
|
9
|
+
ID ID_ivar_ready;
|
8
10
|
ID ID_ivar_terminated;
|
11
|
+
ID ID_ivar_waiters;
|
9
12
|
ID ID_stop;
|
10
13
|
|
11
14
|
/* :nop-doc: */
|
@@ -83,20 +86,80 @@ VALUE Thread_class_backend(VALUE _self) {
|
|
83
86
|
return rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
84
87
|
}
|
85
88
|
|
89
|
+
|
90
|
+
VALUE Thread_done_p(VALUE self)
|
91
|
+
{
|
92
|
+
return rb_ivar_get(self, ID_ivar_done);
|
93
|
+
}
|
94
|
+
|
95
|
+
VALUE Thread_kill_safe(VALUE self)
|
96
|
+
{
|
97
|
+
static VALUE eTerminate = Qnil;
|
98
|
+
if (rb_ivar_get(self, ID_ivar_done) == Qtrue) return self;
|
99
|
+
|
100
|
+
if (eTerminate == Qnil)
|
101
|
+
eTerminate = rb_const_get(mPolyphony, rb_intern("Terminate"));
|
102
|
+
|
103
|
+
while (rb_ivar_get(self, ID_ivar_ready) != Qtrue)
|
104
|
+
rb_thread_schedule();
|
105
|
+
|
106
|
+
VALUE main_fiber = rb_ivar_get(self, ID_ivar_main_fiber);
|
107
|
+
VALUE exception = rb_funcall(eTerminate, ID_new, 0);
|
108
|
+
Thread_schedule_fiber(self, main_fiber, exception);
|
109
|
+
return self;
|
110
|
+
}
|
111
|
+
|
112
|
+
VALUE Thread_mark_as_done(VALUE self, VALUE result)
|
113
|
+
{
|
114
|
+
rb_ivar_set(self, ID_ivar_done, Qtrue);
|
115
|
+
VALUE waiters = rb_ivar_get(self, ID_ivar_waiters);
|
116
|
+
if (waiters == Qnil) return self;
|
117
|
+
|
118
|
+
int len = RARRAY_LEN(waiters);
|
119
|
+
for (int i = 0; i < len; i++) {
|
120
|
+
VALUE waiter = RARRAY_AREF(waiters, i);
|
121
|
+
Event_signal(1, &result, waiter);
|
122
|
+
}
|
123
|
+
return self;
|
124
|
+
}
|
125
|
+
|
126
|
+
VALUE Thread_await_done(VALUE self)
|
127
|
+
{
|
128
|
+
if (Thread_done_p(self) == Qtrue) return rb_ivar_get(self, ID_ivar_result);
|
129
|
+
|
130
|
+
VALUE waiter = Fiber_auto_watcher(rb_fiber_current());
|
131
|
+
VALUE waiters = rb_ivar_get(self, ID_ivar_waiters);
|
132
|
+
if (waiters == Qnil) {
|
133
|
+
waiters = rb_ary_new();
|
134
|
+
rb_ivar_set(self, ID_ivar_waiters, waiters);
|
135
|
+
}
|
136
|
+
rb_ary_push(waiters, waiter);
|
137
|
+
|
138
|
+
return Event_await(waiter);
|
139
|
+
}
|
140
|
+
|
86
141
|
void Init_Thread(void) {
|
87
142
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
88
143
|
rb_define_method(rb_cThread, "schedule_and_wakeup", Thread_fiber_schedule_and_wakeup, 2);
|
89
144
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
90
145
|
rb_define_method(rb_cThread, "fiber_unschedule", Thread_fiber_unschedule, 1);
|
91
146
|
|
147
|
+
rb_define_method(rb_cThread, "done?", Thread_done_p, 0);
|
148
|
+
rb_define_method(rb_cThread, "kill_safe", Thread_kill_safe, 0);
|
149
|
+
rb_define_method(rb_cThread, "mark_as_done", Thread_mark_as_done, 1);
|
150
|
+
rb_define_method(rb_cThread, "await_done", Thread_await_done, 0);
|
151
|
+
|
92
152
|
rb_define_singleton_method(rb_cThread, "backend", Thread_class_backend, 0);
|
93
153
|
|
94
154
|
rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
|
95
155
|
|
96
156
|
ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
|
97
157
|
ID_ivar_backend = rb_intern("@backend");
|
158
|
+
ID_ivar_done = rb_intern("@done");
|
98
159
|
ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
|
99
160
|
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
161
|
+
ID_ivar_ready = rb_intern("@ready");
|
100
162
|
ID_ivar_terminated = rb_intern("@terminated");
|
163
|
+
ID_ivar_waiters = rb_intern("@waiters");
|
101
164
|
ID_stop = rb_intern("stop");
|
102
165
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
// source: https://stackoverflow.com/questions/57897314/fatal-error-when-compiling-include-sys-uio-h-on-project-windows
|
2
|
+
|
3
|
+
#ifndef SYS_UIO_H
|
4
|
+
#define SYS_UIO_H
|
5
|
+
|
6
|
+
#include <inttypes.h>
|
7
|
+
#include <unistd.h>
|
8
|
+
|
9
|
+
struct iovec
|
10
|
+
{
|
11
|
+
void *iov_base; /* Base address of a memory region for input or output */
|
12
|
+
size_t iov_len; /* The size of the memory pointed to by iov_base */
|
13
|
+
};
|
14
|
+
|
15
|
+
ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);
|
16
|
+
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);
|
17
|
+
|
18
|
+
#endif /* SYS_UIO_H */
|