polyphony 0.99 → 0.99.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 -1
- data/.rubocop.yml +3 -3
- data/.yardopts +30 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +1 -1
- data/README.md +63 -29
- data/Rakefile +1 -5
- data/TODO.md +0 -4
- data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
- data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
- data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
- data/docs/{main-concepts/extending.md → extending.md} +2 -9
- data/docs/faq.md +3 -16
- data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
- data/docs/link_rewriter.rb +16 -0
- data/docs/{getting-started/overview.md → overview.md} +1 -30
- data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
- data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
- data/examples/adapters/redis_client.rb +3 -2
- data/examples/io/echo_server.rb +1 -1
- data/examples/io/echo_server_plain_ruby.rb +26 -0
- data/ext/polyphony/backend_io_uring.c +154 -9
- data/ext/polyphony/backend_io_uring_context.c +21 -12
- data/ext/polyphony/backend_io_uring_context.h +12 -7
- data/ext/polyphony/backend_libev.c +1 -1
- data/ext/polyphony/extconf.rb +24 -8
- data/ext/polyphony/fiber.c +79 -2
- data/ext/polyphony/io_extensions.c +53 -0
- data/ext/polyphony/pipe.c +42 -2
- data/ext/polyphony/polyphony.c +345 -31
- data/ext/polyphony/polyphony.h +9 -2
- data/ext/polyphony/queue.c +181 -0
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/runqueue.c +8 -1
- data/ext/polyphony/runqueue_ring_buffer.c +13 -0
- data/ext/polyphony/runqueue_ring_buffer.h +2 -1
- data/ext/polyphony/socket_extensions.c +6 -0
- data/ext/polyphony/thread.c +34 -2
- data/lib/polyphony/adapters/process.rb +11 -1
- data/lib/polyphony/adapters/sequel.rb +1 -1
- data/lib/polyphony/core/channel.rb +2 -0
- data/lib/polyphony/core/debug.rb +1 -1
- data/lib/polyphony/core/global_api.rb +25 -24
- data/lib/polyphony/core/resource_pool.rb +7 -6
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +3 -3
- data/lib/polyphony/core/timer.rb +8 -8
- data/lib/polyphony/extensions/exception.rb +2 -0
- data/lib/polyphony/extensions/fiber.rb +15 -13
- data/lib/polyphony/extensions/io.rb +127 -5
- data/lib/polyphony/extensions/kernel.rb +20 -2
- data/lib/polyphony/extensions/openssl.rb +100 -11
- data/lib/polyphony/extensions/pipe.rb +103 -7
- data/lib/polyphony/extensions/process.rb +13 -1
- data/lib/polyphony/extensions/socket.rb +93 -27
- data/lib/polyphony/extensions/thread.rb +9 -1
- data/lib/polyphony/extensions/timeout.rb +1 -1
- data/lib/polyphony/version.rb +2 -1
- data/lib/polyphony.rb +27 -7
- data/polyphony.gemspec +1 -8
- data/test/stress.rb +1 -1
- data/test/test_global_api.rb +45 -7
- data/test/test_socket.rb +96 -0
- data/test/test_timer.rb +5 -5
- metadata +17 -40
- data/docs/_config.yml +0 -64
- data/docs/_includes/head.html +0 -40
- data/docs/_includes/title.html +0 -1
- data/docs/_sass/custom/custom.scss +0 -10
- data/docs/_sass/overrides.scss +0 -0
- data/docs/api-reference/exception.md +0 -31
- data/docs/api-reference/fiber.md +0 -425
- data/docs/api-reference/index.md +0 -9
- data/docs/api-reference/io.md +0 -36
- data/docs/api-reference/object.md +0 -99
- data/docs/api-reference/polyphony-baseexception.md +0 -33
- data/docs/api-reference/polyphony-cancel.md +0 -26
- data/docs/api-reference/polyphony-moveon.md +0 -24
- data/docs/api-reference/polyphony-net.md +0 -20
- data/docs/api-reference/polyphony-process.md +0 -28
- data/docs/api-reference/polyphony-resourcepool.md +0 -59
- data/docs/api-reference/polyphony-restart.md +0 -18
- data/docs/api-reference/polyphony-terminate.md +0 -18
- data/docs/api-reference/polyphony-threadpool.md +0 -67
- data/docs/api-reference/polyphony-throttler.md +0 -77
- data/docs/api-reference/polyphony.md +0 -36
- data/docs/api-reference/thread.md +0 -88
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +0 -10
- data/docs/getting-started/installing.md +0 -34
- /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
- /data/{docs → assets}/polyphony-logo.png +0 -0
- /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
|
@@ -90,8 +90,16 @@ static VALUE Backend_initialize(VALUE self) {
|
|
|
90
90
|
context_store_initialize(&backend->store);
|
|
91
91
|
|
|
92
92
|
backend->prepared_limit = 1024;
|
|
93
|
+
int flags = 0;
|
|
94
|
+
#ifdef HAVE_IORING_SETUP_SUBMIT_ALL
|
|
95
|
+
flags |= IORING_SETUP_SUBMIT_ALL;
|
|
96
|
+
#endif
|
|
97
|
+
#ifdef HAVE_IORING_SETUP_COOP_TASKRUN
|
|
98
|
+
flags |= IORING_SETUP_COOP_TASKRUN;
|
|
99
|
+
#endif
|
|
100
|
+
|
|
93
101
|
while (1) {
|
|
94
|
-
int ret = io_uring_queue_init(backend->prepared_limit, &backend->ring,
|
|
102
|
+
int ret = io_uring_queue_init(backend->prepared_limit, &backend->ring, flags);
|
|
95
103
|
if (!ret) break;
|
|
96
104
|
|
|
97
105
|
// if ENOMEM is returned, use a smaller limit
|
|
@@ -141,23 +149,53 @@ void *io_uring_backend_poll_without_gvl(void *ptr) {
|
|
|
141
149
|
return NULL;
|
|
142
150
|
}
|
|
143
151
|
|
|
144
|
-
// copied from queue.c
|
|
152
|
+
// copied from liburing/queue.c
|
|
145
153
|
static inline bool cq_ring_needs_flush(struct io_uring *ring) {
|
|
146
154
|
return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
|
|
147
155
|
}
|
|
148
156
|
|
|
157
|
+
static void handle_multishot_accept_completion(op_context_t *ctx, struct io_uring_cqe *cqe, Backend_t *backend) {
|
|
158
|
+
// printf("handle_multishot_accept_completion result: %d\n", ctx->result);
|
|
159
|
+
if (ctx->result == -ECANCELED) {
|
|
160
|
+
context_store_release(&backend->store, ctx);
|
|
161
|
+
rb_ivar_set(ctx->resume_value, ID_ivar_multishot_accept_queue, Qnil);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
if (!(cqe->flags & IORING_CQE_F_MORE)) {
|
|
165
|
+
context_store_release(&backend->store, ctx);
|
|
166
|
+
}
|
|
167
|
+
VALUE queue = rb_ivar_get(ctx->resume_value, ID_ivar_multishot_accept_queue);
|
|
168
|
+
if (queue != Qnil)
|
|
169
|
+
Queue_push(queue, INT2NUM(ctx->result));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static void handle_multishot_completion(op_context_t *ctx, struct io_uring_cqe *cqe, Backend_t *backend) {
|
|
174
|
+
switch (ctx->type) {
|
|
175
|
+
case OP_MULTISHOT_ACCEPT:
|
|
176
|
+
return handle_multishot_accept_completion(ctx, cqe, backend);
|
|
177
|
+
default:
|
|
178
|
+
printf("Unexpected multishot completion for op type %d\n", ctx->type);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
149
182
|
static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
|
|
150
183
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
|
151
184
|
if (!ctx) return;
|
|
152
185
|
|
|
153
186
|
// printf("cqe ctx %p id: %d result: %d (%s, ref_count: %d)\n", ctx, ctx->id, cqe->res, op_type_to_str(ctx->type), ctx->ref_count);
|
|
154
187
|
ctx->result = cqe->res;
|
|
155
|
-
if (ctx->ref_count ==
|
|
156
|
-
|
|
157
|
-
|
|
188
|
+
if (ctx->ref_count == MULTISHOT_REFCOUNT) {
|
|
189
|
+
handle_multishot_completion(ctx, cqe, backend);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
if (ctx->ref_count == 2 && ctx->result != -ECANCELED && ctx->fiber)
|
|
193
|
+
Fiber_make_runnable(ctx->fiber, ctx->resume_value);
|
|
194
|
+
context_store_release(&backend->store, ctx);
|
|
195
|
+
}
|
|
158
196
|
}
|
|
159
197
|
|
|
160
|
-
// adapted from io_uring_peek_batch_cqe in queue.c
|
|
198
|
+
// adapted from io_uring_peek_batch_cqe in liburing/queue.c
|
|
161
199
|
// this peeks at cqes and handles each available cqe
|
|
162
200
|
void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
|
|
163
201
|
struct io_uring *ring = &backend->ring;
|
|
@@ -701,7 +739,7 @@ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE po
|
|
|
701
739
|
|
|
702
740
|
while (1) {
|
|
703
741
|
VALUE resume_value = Qnil;
|
|
704
|
-
op_context_t *ctx = context_store_acquire(&backend->store,
|
|
742
|
+
op_context_t *ctx = context_store_acquire(&backend->store, OP_RECVMSG);
|
|
705
743
|
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
|
706
744
|
int result;
|
|
707
745
|
int completed;
|
|
@@ -904,7 +942,7 @@ VALUE Backend_sendmsg(VALUE self, VALUE io, VALUE buffer, VALUE flags, VALUE des
|
|
|
904
942
|
|
|
905
943
|
while (left > 0) {
|
|
906
944
|
VALUE resume_value = Qnil;
|
|
907
|
-
op_context_t *ctx = context_store_acquire(&backend->store,
|
|
945
|
+
op_context_t *ctx = context_store_acquire(&backend->store, OP_SENDMSG);
|
|
908
946
|
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
|
909
947
|
int result;
|
|
910
948
|
int completed;
|
|
@@ -985,12 +1023,114 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
|
|
|
985
1023
|
}
|
|
986
1024
|
|
|
987
1025
|
VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
1026
|
+
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
|
1027
|
+
VALUE accept_queue = rb_ivar_get(server_socket, ID_ivar_multishot_accept_queue);
|
|
1028
|
+
if (accept_queue != Qnil) {
|
|
1029
|
+
VALUE next = Queue_shift(0, 0, accept_queue);
|
|
1030
|
+
int fd = NUM2INT(next);
|
|
1031
|
+
if (fd < 0)
|
|
1032
|
+
rb_syserr_fail(-fd, strerror(-fd));
|
|
1033
|
+
else {
|
|
1034
|
+
rb_io_t *fp;
|
|
1035
|
+
|
|
1036
|
+
VALUE socket = rb_obj_alloc(socket_class);
|
|
1037
|
+
MakeOpenFile(socket, fp);
|
|
1038
|
+
rb_update_max_fd(fd);
|
|
1039
|
+
fp->fd = fd;
|
|
1040
|
+
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
|
1041
|
+
rb_io_ascii8bit_binmode(socket);
|
|
1042
|
+
rb_io_synchronized(fp);
|
|
1043
|
+
return socket;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
#endif
|
|
1047
|
+
|
|
988
1048
|
Backend_t *backend;
|
|
989
1049
|
GetBackend(self, backend);
|
|
990
1050
|
return io_uring_backend_accept(backend, server_socket, socket_class, 0);
|
|
991
1051
|
}
|
|
992
1052
|
|
|
1053
|
+
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
|
1054
|
+
|
|
1055
|
+
struct multishot_accept_ctx {
|
|
1056
|
+
Backend_t *backend;
|
|
1057
|
+
VALUE server_socket;
|
|
1058
|
+
op_context_t *op_ctx;
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
VALUE multishot_accept_start(struct multishot_accept_ctx *ctx) {
|
|
1062
|
+
int server_fd;
|
|
1063
|
+
rb_io_t *server_fptr;
|
|
1064
|
+
server_fd = fd_from_io(ctx->server_socket, &server_fptr, 0, 0);
|
|
1065
|
+
VALUE accept_queue = rb_funcall(cQueue, ID_new, 0);
|
|
1066
|
+
rb_ivar_set(ctx->server_socket, ID_ivar_multishot_accept_queue, accept_queue);
|
|
1067
|
+
|
|
1068
|
+
ctx->op_ctx = context_store_acquire(&ctx->backend->store, OP_MULTISHOT_ACCEPT);
|
|
1069
|
+
ctx->op_ctx->ref_count = -1;
|
|
1070
|
+
ctx->op_ctx->resume_value = ctx->server_socket;
|
|
1071
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(ctx->backend);
|
|
1072
|
+
io_uring_prep_multishot_accept(sqe, server_fd, 0, 0, 0);
|
|
1073
|
+
io_uring_sqe_set_data(sqe, ctx->op_ctx);
|
|
1074
|
+
io_uring_backend_defer_submit(ctx->backend);
|
|
1075
|
+
|
|
1076
|
+
rb_yield(ctx->server_socket);
|
|
1077
|
+
|
|
1078
|
+
return Qnil;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
VALUE multishot_accept_cleanup(struct multishot_accept_ctx *ctx) {
|
|
1082
|
+
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(ctx->backend);
|
|
1083
|
+
io_uring_prep_cancel(sqe, ctx->op_ctx, 0);
|
|
1084
|
+
io_uring_sqe_set_data(sqe, NULL);
|
|
1085
|
+
io_uring_backend_defer_submit(ctx->backend);
|
|
1086
|
+
|
|
1087
|
+
rb_ivar_set(ctx->server_socket, ID_ivar_multishot_accept_queue, Qnil);
|
|
1088
|
+
|
|
1089
|
+
return Qnil;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
VALUE Backend_multishot_accept(VALUE self, VALUE server_socket) {
|
|
1093
|
+
Backend_t *backend;
|
|
1094
|
+
GetBackend(self, backend);
|
|
1095
|
+
|
|
1096
|
+
struct multishot_accept_ctx ctx;
|
|
1097
|
+
ctx.backend = backend;
|
|
1098
|
+
ctx.server_socket = server_socket;
|
|
1099
|
+
|
|
1100
|
+
return rb_ensure(
|
|
1101
|
+
SAFE(multishot_accept_start), (VALUE)&ctx,
|
|
1102
|
+
SAFE(multishot_accept_cleanup), (VALUE)&ctx
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
#endif
|
|
1107
|
+
|
|
993
1108
|
VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
1109
|
+
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
|
1110
|
+
VALUE accept_queue = rb_ivar_get(server_socket, ID_ivar_multishot_accept_queue);
|
|
1111
|
+
if (accept_queue != Qnil) {
|
|
1112
|
+
while (true) {
|
|
1113
|
+
VALUE next = Queue_shift(0, 0, accept_queue);
|
|
1114
|
+
int fd = NUM2INT(next);
|
|
1115
|
+
if (fd < 0)
|
|
1116
|
+
rb_syserr_fail(-fd, strerror(-fd));
|
|
1117
|
+
else {
|
|
1118
|
+
rb_io_t *fp;
|
|
1119
|
+
|
|
1120
|
+
VALUE socket = rb_obj_alloc(socket_class);
|
|
1121
|
+
MakeOpenFile(socket, fp);
|
|
1122
|
+
rb_update_max_fd(fd);
|
|
1123
|
+
fp->fd = fd;
|
|
1124
|
+
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
|
1125
|
+
rb_io_ascii8bit_binmode(socket);
|
|
1126
|
+
rb_io_synchronized(fp);
|
|
1127
|
+
rb_yield(socket);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return self;
|
|
1131
|
+
}
|
|
1132
|
+
#endif
|
|
1133
|
+
|
|
994
1134
|
Backend_t *backend;
|
|
995
1135
|
GetBackend(self, backend);
|
|
996
1136
|
io_uring_backend_accept(backend, server_socket, socket_class, 1);
|
|
@@ -1801,7 +1941,7 @@ VALUE Backend_snooze(VALUE self) {
|
|
|
1801
1941
|
GetBackend(self, backend);
|
|
1802
1942
|
|
|
1803
1943
|
Fiber_make_runnable(fiber, Qnil);
|
|
1804
|
-
ret =
|
|
1944
|
+
ret = backend_base_switch_fiber(self, &backend->base);
|
|
1805
1945
|
|
|
1806
1946
|
COND_TRACE(&backend->base, 4, SYM_unblock, rb_fiber_current(), ret, CALLER());
|
|
1807
1947
|
|
|
@@ -1847,6 +1987,11 @@ void Init_Backend(void) {
|
|
|
1847
1987
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
|
1848
1988
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
|
1849
1989
|
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
|
1990
|
+
|
|
1991
|
+
#ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
|
|
1992
|
+
rb_define_method(cBackend, "multishot_accept", Backend_multishot_accept, 1);
|
|
1993
|
+
#endif
|
|
1994
|
+
|
|
1850
1995
|
rb_define_method(cBackend, "read", Backend_read, 5);
|
|
1851
1996
|
rb_define_method(cBackend, "read_loop", Backend_read_loop, 2);
|
|
1852
1997
|
rb_define_method(cBackend, "recv", Backend_recv, 4);
|
|
@@ -6,18 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
const char *op_type_to_str(enum op_type type) {
|
|
8
8
|
switch (type) {
|
|
9
|
-
case
|
|
10
|
-
case
|
|
11
|
-
case
|
|
12
|
-
case
|
|
13
|
-
case
|
|
14
|
-
case
|
|
15
|
-
case
|
|
16
|
-
case
|
|
17
|
-
case
|
|
18
|
-
case
|
|
19
|
-
case
|
|
20
|
-
case
|
|
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
|
+
|
|
21
24
|
default: return "";
|
|
22
25
|
};
|
|
23
26
|
}
|
|
@@ -66,6 +69,12 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
|
66
69
|
|
|
67
70
|
assert(ctx->ref_count);
|
|
68
71
|
|
|
72
|
+
// If a multishot ctx is released, we pretend its ref count is 1, so it will
|
|
73
|
+
// be returned to the store.
|
|
74
|
+
if (ctx->ref_count == MULTISHOT_REFCOUNT) {
|
|
75
|
+
ctx->ref_count = 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
ctx->ref_count--;
|
|
70
79
|
if (ctx->ref_count) return 0;
|
|
71
80
|
|
|
@@ -4,21 +4,26 @@
|
|
|
4
4
|
#include "ruby.h"
|
|
5
5
|
|
|
6
6
|
enum op_type {
|
|
7
|
+
OP_ACCEPT,
|
|
8
|
+
OP_CHAIN,
|
|
9
|
+
OP_CLOSE,
|
|
10
|
+
OP_CONNECT,
|
|
11
|
+
OP_MULTISHOT_ACCEPT,
|
|
7
12
|
OP_NONE,
|
|
13
|
+
OP_POLL,
|
|
8
14
|
OP_READ,
|
|
9
|
-
OP_WRITEV,
|
|
10
|
-
OP_WRITE,
|
|
11
15
|
OP_RECV,
|
|
16
|
+
OP_RECVMSG,
|
|
12
17
|
OP_SEND,
|
|
18
|
+
OP_SENDMSG,
|
|
13
19
|
OP_SPLICE,
|
|
14
20
|
OP_TIMEOUT,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
OP_CONNECT,
|
|
18
|
-
OP_CHAIN,
|
|
19
|
-
OP_CLOSE
|
|
21
|
+
OP_WRITEV,
|
|
22
|
+
OP_WRITE
|
|
20
23
|
};
|
|
21
24
|
|
|
25
|
+
#define MULTISHOT_REFCOUNT 0xFFFF
|
|
26
|
+
|
|
22
27
|
typedef struct op_context {
|
|
23
28
|
struct op_context *prev;
|
|
24
29
|
struct op_context *next;
|
|
@@ -1584,7 +1584,7 @@ VALUE Backend_snooze(VALUE self) {
|
|
|
1584
1584
|
GetBackend(self, backend);
|
|
1585
1585
|
|
|
1586
1586
|
Fiber_make_runnable(fiber, Qnil);
|
|
1587
|
-
ret =
|
|
1587
|
+
ret = backend_base_switch_fiber(self, &backend->base);
|
|
1588
1588
|
|
|
1589
1589
|
COND_TRACE(&backend->base, 4, SYM_unblock, rb_fiber_current(), ret, CALLER());
|
|
1590
1590
|
|
data/ext/polyphony/extconf.rb
CHANGED
|
@@ -18,7 +18,12 @@ def get_config
|
|
|
18
18
|
|
|
19
19
|
combined_version = version.to_i * 100 + major_revision.to_i
|
|
20
20
|
|
|
21
|
-
config[:pidfd_open]
|
|
21
|
+
config[:pidfd_open] = combined_version > 503
|
|
22
|
+
config[:multishot_recv] = combined_version >= 600
|
|
23
|
+
config[:multishot_recvmsg] = combined_version >= 600
|
|
24
|
+
config[:multishot_accept] = combined_version >= 519
|
|
25
|
+
config[:submit_all_flag] = combined_version >= 518
|
|
26
|
+
config[:coop_taskrun_flag] = combined_version >= 519
|
|
22
27
|
|
|
23
28
|
force_libev = ENV['POLYPHONY_LIBEV'] != nil
|
|
24
29
|
config[:io_uring] = !force_libev && (combined_version >= 506) && (distribution != 'linuxkit')
|
|
@@ -46,24 +51,35 @@ if config[:io_uring]
|
|
|
46
51
|
$LDFLAGS << " -L#{File.expand_path('../../vendor/liburing/src', __dir__)} -l uring"
|
|
47
52
|
end
|
|
48
53
|
|
|
54
|
+
def define_bool(name, value)
|
|
55
|
+
$defs << "-D#{name}=#{value ? 1 : 0 }"
|
|
56
|
+
end
|
|
57
|
+
|
|
49
58
|
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
|
50
59
|
if config[:io_uring]
|
|
51
60
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
|
52
61
|
$defs << "-DPOLYPHONY_LINUX"
|
|
53
62
|
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
|
63
|
+
$defs << "-DHAVE_IO_URING_PREP_MULTISHOT_ACCEPT" if config[:multishot_accept]
|
|
64
|
+
$defs << "-DHAVE_IO_URING_PREP_RECV_MULTISHOT" if config[:multishot_recv]
|
|
65
|
+
$defs << "-DHAVE_IO_URING_PREP_RECVMSG_MULTISHOT" if config[:multishot_recvmsg]
|
|
66
|
+
$defs << "-DHAVE_IORING_SETUP_SUBMIT_ALL" if config[:submit_all_flag]
|
|
67
|
+
$defs << "-DHAVE_IORING_SETUP_COOP_TASKRUN" if config[:coop_taskrun_flag]
|
|
54
68
|
$CFLAGS << " -Wno-pointer-arith"
|
|
55
69
|
else
|
|
56
70
|
$defs << "-DPOLYPHONY_BACKEND_LIBEV"
|
|
57
71
|
$defs << "-DPOLYPHONY_LINUX" if config[:linux]
|
|
58
72
|
|
|
59
73
|
$defs << "-DEV_STANDALONE" # prevent libev from assuming "config.h" exists
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
|
|
75
|
+
define_bool('EV_USE_EPOLL', have_header('sys/epoll.h'))
|
|
76
|
+
define_bool('EV_USE_KQUEUE', have_header('sys/event.h') && have_header('sys/queue.h'))
|
|
77
|
+
define_bool('EV_USE_LINUXAIO', have_header('linux/aio_abi.h'))
|
|
78
|
+
define_bool('EV_USE_POLL', have_type('port_event_t', 'poll.h'))
|
|
79
|
+
define_bool('EV_USE_PORT', have_type('port_event_t', 'port.h'))
|
|
80
|
+
define_bool('EV_USE_SELECT', have_header('sys/select.h'))
|
|
81
|
+
define_bool('EV_USE_IOCP', false)
|
|
82
|
+
|
|
67
83
|
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
|
68
84
|
|
|
69
85
|
$CFLAGS << " -Wno-comment"
|
data/ext/polyphony/fiber.c
CHANGED
|
@@ -18,6 +18,8 @@ VALUE SYM_schedule;
|
|
|
18
18
|
VALUE SYM_block;
|
|
19
19
|
VALUE SYM_terminate;
|
|
20
20
|
|
|
21
|
+
/* @!visibility private */
|
|
22
|
+
|
|
21
23
|
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
|
22
24
|
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
|
23
25
|
VALUE ret = FIBER_TRANSFER(self, arg);
|
|
@@ -27,6 +29,8 @@ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
|
|
27
29
|
return ret;
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
/* @!visibility private */
|
|
33
|
+
|
|
30
34
|
inline VALUE Fiber_auto_watcher(VALUE self) {
|
|
31
35
|
VALUE watcher;
|
|
32
36
|
|
|
@@ -38,6 +42,8 @@ inline VALUE Fiber_auto_watcher(VALUE self) {
|
|
|
38
42
|
return watcher;
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
/* @!visibility private */
|
|
46
|
+
|
|
41
47
|
inline void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
|
42
48
|
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
|
43
49
|
if (thread == Qnil) rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
|
@@ -45,6 +51,8 @@ inline void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
|
|
45
51
|
Thread_schedule_fiber(thread, fiber, value);
|
|
46
52
|
}
|
|
47
53
|
|
|
54
|
+
/* @!visibility private */
|
|
55
|
+
|
|
48
56
|
inline void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
|
|
49
57
|
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
|
50
58
|
if (thread == Qnil) rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
|
@@ -52,18 +60,46 @@ inline void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
|
|
|
52
60
|
Thread_schedule_fiber_with_priority(thread, fiber, value);
|
|
53
61
|
}
|
|
54
62
|
|
|
63
|
+
/* call-seq:
|
|
64
|
+
* fiber.schedule
|
|
65
|
+
* fiber.schedule(value)
|
|
66
|
+
*
|
|
67
|
+
* Adds the fiber to the runqueue with the given resume value or `nil`.
|
|
68
|
+
*
|
|
69
|
+
* @return [void]
|
|
70
|
+
*/
|
|
71
|
+
|
|
55
72
|
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
|
56
73
|
VALUE value = (argc == 0) ? Qnil : argv[0];
|
|
57
74
|
Fiber_make_runnable(self, value);
|
|
58
75
|
return self;
|
|
59
76
|
}
|
|
60
77
|
|
|
78
|
+
/* call-seq:
|
|
79
|
+
* fiber.schedule_with_priority
|
|
80
|
+
* fiber.schedule_with_priority(value)
|
|
81
|
+
*
|
|
82
|
+
* Adds the fiber to the head of the runqueue with the given resume value or
|
|
83
|
+
* `nil`.
|
|
84
|
+
*
|
|
85
|
+
* @return [void]
|
|
86
|
+
*/
|
|
87
|
+
|
|
61
88
|
static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
|
|
62
89
|
VALUE value = (argc == 0) ? Qnil : argv[0];
|
|
63
90
|
Fiber_make_runnable_with_priority(self, value);
|
|
64
91
|
return self;
|
|
65
92
|
}
|
|
66
93
|
|
|
94
|
+
/* call-seq:
|
|
95
|
+
* fiber.state -> sym
|
|
96
|
+
*
|
|
97
|
+
* Returns the current state for the fiber, one of `:running`, `:runnable`,
|
|
98
|
+
* `:waiting`, `:dead`.
|
|
99
|
+
*
|
|
100
|
+
* @return [Symbol]
|
|
101
|
+
*/
|
|
102
|
+
|
|
67
103
|
static VALUE Fiber_state(VALUE self) {
|
|
68
104
|
if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
|
|
69
105
|
return SYM_dead;
|
|
@@ -73,16 +109,35 @@ static VALUE Fiber_state(VALUE self) {
|
|
|
73
109
|
return SYM_waiting;
|
|
74
110
|
}
|
|
75
111
|
|
|
76
|
-
|
|
112
|
+
/* call-seq:
|
|
113
|
+
* fiber.send(msg)
|
|
114
|
+
*
|
|
115
|
+
* Sends a message to the given fiber. The message will be added to the fiber's
|
|
116
|
+
* mailbox.
|
|
117
|
+
*
|
|
118
|
+
* @param msg [any]
|
|
119
|
+
* @return [void]
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
VALUE Fiber_send(VALUE self, VALUE msg) {
|
|
77
123
|
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
78
124
|
if (mailbox == Qnil) {
|
|
79
125
|
mailbox = rb_funcall(cQueue, ID_new, 0);
|
|
80
126
|
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
|
81
127
|
}
|
|
82
|
-
Queue_push(mailbox,
|
|
128
|
+
Queue_push(mailbox, msg);
|
|
83
129
|
return self;
|
|
84
130
|
}
|
|
85
131
|
|
|
132
|
+
/* call-seq:
|
|
133
|
+
* fiber.receive -> msg
|
|
134
|
+
*
|
|
135
|
+
* Receive's a message from the fiber's mailbox. If no message is available,
|
|
136
|
+
* waits for a message to be sent to it.
|
|
137
|
+
*
|
|
138
|
+
* @return [any] received message
|
|
139
|
+
*/
|
|
140
|
+
|
|
86
141
|
VALUE Fiber_receive(VALUE self) {
|
|
87
142
|
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
88
143
|
if (mailbox == Qnil) {
|
|
@@ -92,6 +147,14 @@ VALUE Fiber_receive(VALUE self) {
|
|
|
92
147
|
return Queue_shift(0, 0, mailbox);
|
|
93
148
|
}
|
|
94
149
|
|
|
150
|
+
/* call-seq:
|
|
151
|
+
* fiber.mailbox -> queue
|
|
152
|
+
*
|
|
153
|
+
* Returns the fiber's mailbox.
|
|
154
|
+
*
|
|
155
|
+
* @return [Queue]
|
|
156
|
+
*/
|
|
157
|
+
|
|
95
158
|
VALUE Fiber_mailbox(VALUE self) {
|
|
96
159
|
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
97
160
|
if (mailbox == Qnil) {
|
|
@@ -101,23 +164,37 @@ VALUE Fiber_mailbox(VALUE self) {
|
|
|
101
164
|
return mailbox;
|
|
102
165
|
}
|
|
103
166
|
|
|
167
|
+
/* call-seq:
|
|
168
|
+
* fiber.receive_all_pending -> ary
|
|
169
|
+
*
|
|
170
|
+
* Receives all messages currently in the fiber's mailbox.
|
|
171
|
+
*
|
|
172
|
+
* @return [Array]
|
|
173
|
+
*/
|
|
174
|
+
|
|
104
175
|
VALUE Fiber_receive_all_pending(VALUE self) {
|
|
105
176
|
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
106
177
|
return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
|
|
107
178
|
}
|
|
108
179
|
|
|
180
|
+
/* @!visibility private */
|
|
181
|
+
|
|
109
182
|
VALUE Fiber_park(VALUE self) {
|
|
110
183
|
rb_ivar_set(self, ID_ivar_parked, Qtrue);
|
|
111
184
|
Backend_park_fiber(BACKEND(), self);
|
|
112
185
|
return self;
|
|
113
186
|
}
|
|
114
187
|
|
|
188
|
+
/* @!visibility private */
|
|
189
|
+
|
|
115
190
|
VALUE Fiber_unpark(VALUE self) {
|
|
116
191
|
rb_ivar_set(self, ID_ivar_parked, Qnil);
|
|
117
192
|
Backend_unpark_fiber(BACKEND(), self);
|
|
118
193
|
return self;
|
|
119
194
|
}
|
|
120
195
|
|
|
196
|
+
/* @!visibility private */
|
|
197
|
+
|
|
121
198
|
VALUE Fiber_parked_p(VALUE self) {
|
|
122
199
|
return rb_ivar_get(self, ID_ivar_parked);
|
|
123
200
|
}
|
|
@@ -507,6 +507,16 @@ static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
|
|
|
507
507
|
#define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
|
|
508
508
|
rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
|
|
509
509
|
|
|
510
|
+
/* call-seq:
|
|
511
|
+
* IO.gzip(src, dest) -> bytes_written
|
|
512
|
+
* IO.gzip(src, dest, opt) -> bytes_written
|
|
513
|
+
*
|
|
514
|
+
* Gzips data from the source IO to the destination IO, returning the number
|
|
515
|
+
* bytes written to the destination IO.
|
|
516
|
+
*
|
|
517
|
+
* @return [Integer]
|
|
518
|
+
*/
|
|
519
|
+
|
|
510
520
|
VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
|
511
521
|
VALUE src;
|
|
512
522
|
VALUE dest;
|
|
@@ -538,6 +548,16 @@ VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
|
|
538
548
|
|
|
539
549
|
# define FIX2TIME(v) (rb_funcall(rb_cTime, ID_at, 1, v))
|
|
540
550
|
|
|
551
|
+
/* call-seq:
|
|
552
|
+
* IO.gunzip(src, dest) -> bytes_written
|
|
553
|
+
* IO.gunzip(src, dest, opt) -> bytes_written
|
|
554
|
+
*
|
|
555
|
+
* Gunzips data from the source IO to the destination IO, returning the number
|
|
556
|
+
* bytes written to the destination IO.
|
|
557
|
+
*
|
|
558
|
+
* @return [Integer]
|
|
559
|
+
*/
|
|
560
|
+
|
|
541
561
|
VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
|
542
562
|
VALUE src;
|
|
543
563
|
VALUE dest;
|
|
@@ -574,6 +594,16 @@ VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
|
|
574
594
|
return INT2FIX(ctx.out_total);
|
|
575
595
|
}
|
|
576
596
|
|
|
597
|
+
/* call-seq:
|
|
598
|
+
* IO.deflate(src, dest) -> bytes_written
|
|
599
|
+
* IO.deflate(src, dest, opt) -> bytes_written
|
|
600
|
+
*
|
|
601
|
+
* Defaltes data from the source IO to the destination IO, returning the number
|
|
602
|
+
* bytes written to the destination IO.
|
|
603
|
+
*
|
|
604
|
+
* @return [Integer]
|
|
605
|
+
*/
|
|
606
|
+
|
|
577
607
|
VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
|
578
608
|
struct z_stream_ctx ctx;
|
|
579
609
|
int level = DEFAULT_LEVEL;
|
|
@@ -589,6 +619,16 @@ VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
|
|
589
619
|
return INT2FIX(ctx.out_total);
|
|
590
620
|
}
|
|
591
621
|
|
|
622
|
+
/* call-seq:
|
|
623
|
+
* IO.inflate(src, dest) -> bytes_written
|
|
624
|
+
* IO.inflate(src, dest, opt) -> bytes_written
|
|
625
|
+
*
|
|
626
|
+
* Inflates data from the source IO to the destination IO, returning the number
|
|
627
|
+
* bytes written to the destination IO.
|
|
628
|
+
*
|
|
629
|
+
* @return [Integer]
|
|
630
|
+
*/
|
|
631
|
+
|
|
592
632
|
VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
|
593
633
|
struct z_stream_ctx ctx;
|
|
594
634
|
int ret;
|
|
@@ -603,6 +643,19 @@ VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
|
|
603
643
|
return INT2FIX(ctx.out_total);
|
|
604
644
|
}
|
|
605
645
|
|
|
646
|
+
/* call-seq:
|
|
647
|
+
* IO.http1_splice_chunked(src, dest, maxlen)
|
|
648
|
+
*
|
|
649
|
+
* Splices data from the source IO to the destination IO, writing it in HTTP1
|
|
650
|
+
* chunked encoding. A pipe is automatically created to buffer data between
|
|
651
|
+
* source and destination.
|
|
652
|
+
*
|
|
653
|
+
* @param src [IO] source
|
|
654
|
+
* @param dest [IO] destination
|
|
655
|
+
* @param maxlen [Integer] maximum bytes to splice
|
|
656
|
+
* @return [Integer] bytes spliced
|
|
657
|
+
*/
|
|
658
|
+
|
|
606
659
|
VALUE IO_http1_splice_chunked(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
607
660
|
enum write_method method = detect_write_method(dest);
|
|
608
661
|
VALUE backend = BACKEND();
|