polyphony 1.5 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/TODO.md +0 -4
- data/ext/polyphony/backend_io_uring.c +34 -1
- 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 +4 -7
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +20 -18
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -0
- 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/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/thread.rb +19 -27
- 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 +7 -2
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +2 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +13 -12
- 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 -3
- 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 +14 -3
- data/vendor/liburing/test/timeout-overflow.c +0 -204
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bed700ffe759bddcee9727be8e3c11d194f45fe44f05a0a879c92c7b221c6c5
|
4
|
+
data.tar.gz: 0f864fa278709cb00c6b2fae7e3725ef581b05f2b111661a7b5a8d4be1696346
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e94ad30b3e9392f8afc0ae85a22afbe6ee6ab4b60c6fa1c412ab6d571d51ebec6e7bf8280106f6d0d7ad6c479dd8b6d748f4aed70b8dc2791f16a1d650fd7667
|
7
|
+
data.tar.gz: 2d8a3f5f2b9dd4d5107dedba344d5e4c46efc43546878779918997e3cb81c9087428e4872e70a631169a0b9d2ff3f1b8b745aa3668817a30475f921106b117e9
|
data/.rubocop.yml
CHANGED
@@ -81,6 +81,8 @@ Metrics/MethodLength:
|
|
81
81
|
Exclude:
|
82
82
|
- lib/polyphony/extensions/io.rb
|
83
83
|
- lib/polyphony/extensions/fiber.rb
|
84
|
+
- lib/polyphony/extensions/thread.rb
|
85
|
+
- lib/polyphony/adapters/open3.rb
|
84
86
|
- test/**/*.rb
|
85
87
|
- examples/**/*.rb
|
86
88
|
|
@@ -94,6 +96,7 @@ Metrics/ClassLength:
|
|
94
96
|
- lib/polyphony/extensions/io.rb
|
95
97
|
- lib/polyphony/extensions/fiber.rb
|
96
98
|
- lib/polyphony/extensions/object.rb
|
99
|
+
- lib/polyphony/extensions/thread.rb
|
97
100
|
- test/**/*.rb
|
98
101
|
- examples/**/*.rb
|
99
102
|
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 1.6 2023-08-05
|
2
|
+
|
3
|
+
- Refactor exception instantiation
|
4
|
+
- Fix race condition in `Thread#join`
|
5
|
+
- Fix race condition in `Event` class
|
6
|
+
- Add support for open3 API
|
7
|
+
- Update liburing to version 2.4
|
8
|
+
- Various fixes to `IO` instance methods
|
9
|
+
- Fix `IO#double_splice` on non-Linux OSes
|
10
|
+
- Implement `IO.copy_stream`
|
11
|
+
- Add `Fiber#value` as alias to `Fiber#await`
|
12
|
+
- Implement fiber-aware `Monitor` class (#113)
|
13
|
+
- Implement Thread#value
|
14
|
+
|
1
15
|
## 1.5 2023-07-28
|
2
16
|
|
3
17
|
- Refactor backend_await in io_uring backend
|
data/TODO.md
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
- Look at RPC benchmark more closely: is there a way to reduce the overhead of
|
2
|
-
the `backend_base_switch_fiber` function?
|
3
|
-
|
4
1
|
- io_uring backend:
|
5
2
|
- if `io_uring_get_sqe` returns null, call `io_uring_submit`, (snooze fiber)?
|
6
3
|
and try again
|
@@ -25,7 +22,6 @@
|
|
25
22
|
|
26
23
|
## Roadmap for Polyphony 2
|
27
24
|
|
28
|
-
- allow backend selection at runtime?
|
29
25
|
- Debugging
|
30
26
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
31
27
|
test fails
|
@@ -186,10 +186,30 @@ static void handle_multishot_accept_completion(op_context_t *ctx, struct io_urin
|
|
186
186
|
}
|
187
187
|
}
|
188
188
|
|
189
|
+
static void handle_multishot_timeout_completion(
|
190
|
+
op_context_t *ctx, struct io_uring_cqe *cqe, Backend_t *backend
|
191
|
+
)
|
192
|
+
{
|
193
|
+
if (ctx->result == -ECANCELED) {
|
194
|
+
context_store_release(&backend->store, ctx);
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
int has_more = cqe->flags & IORING_CQE_F_MORE;
|
198
|
+
if (!has_more) {
|
199
|
+
context_store_release(&backend->store, ctx);
|
200
|
+
}
|
201
|
+
if (ctx->fiber) {
|
202
|
+
Fiber_make_runnable(ctx->fiber, has_more ? Qtrue : Qnil);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
189
207
|
static void handle_multishot_completion(op_context_t *ctx, struct io_uring_cqe *cqe, Backend_t *backend) {
|
190
208
|
switch (ctx->type) {
|
191
209
|
case OP_MULTISHOT_ACCEPT:
|
192
210
|
return handle_multishot_accept_completion(ctx, cqe, backend);
|
211
|
+
case OP_MULTISHOT_TIMEOUT:
|
212
|
+
return handle_multishot_timeout_completion(ctx, cqe, backend);
|
193
213
|
default:
|
194
214
|
printf("Unexpected multishot completion for op type %d\n", ctx->type);
|
195
215
|
}
|
@@ -199,6 +219,12 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
199
219
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
200
220
|
if (!ctx) return;
|
201
221
|
|
222
|
+
// if (ctx->type == OP_TIMEOUT) {
|
223
|
+
// double now = current_time_ns() / 1e9;
|
224
|
+
// double elapsed = now - ctx->ts;
|
225
|
+
// printf("%13.6f CQE timeout %p:%d (elapsed: %9.6f)\n", now, ctx, ctx->id, elapsed);
|
226
|
+
// }
|
227
|
+
|
202
228
|
// 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);
|
203
229
|
ctx->result = cqe->res;
|
204
230
|
if (ctx->ref_count == MULTISHOT_REFCOUNT) {
|
@@ -663,6 +689,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
663
689
|
result = io_uring_backend_defer_submit_and_await(self, backend, sqe, ctx, &resume_value);
|
664
690
|
completed = context_store_release(&backend->store, ctx);
|
665
691
|
if (!completed) {
|
692
|
+
TRACE_FREE(iov);
|
666
693
|
free(iov);
|
667
694
|
context_attach_buffers(ctx, argc, argv);
|
668
695
|
RAISE_IF_EXCEPTION(resume_value);
|
@@ -671,6 +698,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
671
698
|
RB_GC_GUARD(resume_value);
|
672
699
|
|
673
700
|
if (result < 0) {
|
701
|
+
TRACE_FREE(iov);
|
674
702
|
free(iov);
|
675
703
|
rb_syserr_fail(-result, strerror(-result));
|
676
704
|
}
|
@@ -693,6 +721,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
693
721
|
}
|
694
722
|
}
|
695
723
|
|
724
|
+
TRACE_FREE(iov);
|
696
725
|
free(iov);
|
697
726
|
return INT2FIX(total_written);
|
698
727
|
}
|
@@ -1433,6 +1462,10 @@ int io_uring_backend_submit_timeout_and_await(VALUE self, Backend_t *backend, do
|
|
1433
1462
|
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
1434
1463
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1435
1464
|
|
1465
|
+
// double now = current_time_ns() / 1e9;
|
1466
|
+
// ctx->ts = now;
|
1467
|
+
// printf("%13.6f SQE timeout %p:%d (%g)\n", now, ctx, ctx->id, duration);
|
1468
|
+
|
1436
1469
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
1437
1470
|
io_uring_backend_defer_submit_and_await(self, backend, sqe, ctx, resume_value);
|
1438
1471
|
return context_store_release(&backend->store, ctx);
|
@@ -1572,7 +1605,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1572
1605
|
else
|
1573
1606
|
rb_syserr_fail(e, strerror(e));
|
1574
1607
|
}
|
1575
|
-
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(
|
1608
|
+
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(status));
|
1576
1609
|
}
|
1577
1610
|
|
1578
1611
|
/*
|
@@ -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 {
|
@@ -1325,7 +1325,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1325
1325
|
int e = errno;
|
1326
1326
|
rb_syserr_fail(e, strerror(e));
|
1327
1327
|
}
|
1328
|
-
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(
|
1328
|
+
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(status));
|
1329
1329
|
}
|
1330
1330
|
#else
|
1331
1331
|
struct libev_child {
|
@@ -1336,10 +1336,7 @@ struct libev_child {
|
|
1336
1336
|
#ifndef POLYPHONY_WINDOWS
|
1337
1337
|
void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
1338
1338
|
struct libev_child *watcher = (struct libev_child *)w;
|
1339
|
-
|
1340
|
-
VALUE status;
|
1341
|
-
|
1342
|
-
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));
|
1343
1340
|
Fiber_make_runnable(watcher->fiber, status);
|
1344
1341
|
}
|
1345
1342
|
#endif
|
@@ -1365,9 +1362,9 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1365
1362
|
RB_GC_GUARD(watcher.fiber);
|
1366
1363
|
RB_GC_GUARD(switchpoint_result);
|
1367
1364
|
return switchpoint_result;
|
1368
|
-
#endif
|
1365
|
+
#endif // #ifdef POLYPHONY_WINDOWS
|
1369
1366
|
}
|
1370
|
-
#endif
|
1367
|
+
#endif // #ifdef POLYPHONY_USE_PIDFD_OPEN
|
1371
1368
|
|
1372
1369
|
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
1373
1370
|
|
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
@@ -22,9 +22,10 @@ def get_config
|
|
22
22
|
|
23
23
|
config[:kernel_version] = combined_version
|
24
24
|
config[:pidfd_open] = combined_version > 503
|
25
|
+
config[:multishot_accept] = combined_version >= 519
|
25
26
|
config[:multishot_recv] = combined_version >= 600
|
26
27
|
config[:multishot_recvmsg] = combined_version >= 600
|
27
|
-
config[:
|
28
|
+
config[:multishot_timeout] = combined_version >= 640
|
28
29
|
config[:submit_all_flag] = combined_version >= 518
|
29
30
|
config[:coop_taskrun_flag] = combined_version >= 519
|
30
31
|
|
@@ -62,21 +63,22 @@ end
|
|
62
63
|
|
63
64
|
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
64
65
|
if config[:io_uring]
|
65
|
-
$defs <<
|
66
|
-
$defs <<
|
67
|
-
$defs <<
|
68
|
-
$defs <<
|
69
|
-
$defs <<
|
70
|
-
$defs <<
|
71
|
-
$defs <<
|
72
|
-
$defs <<
|
73
|
-
$
|
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'
|
74
76
|
else
|
75
|
-
$defs <<
|
76
|
-
$defs <<
|
77
|
-
$defs <<
|
77
|
+
$defs << '-DPOLYPHONY_BACKEND_LIBEV'
|
78
|
+
$defs << '-DPOLYPHONY_LINUX' if config[:linux]
|
79
|
+
$defs << '-DPOLYPHONY_WINDOWS' if config[:windows]
|
78
80
|
|
79
|
-
$defs <<
|
81
|
+
$defs << '-DEV_STANDALONE' # prevent libev from assuming "config.h" exists
|
80
82
|
|
81
83
|
define_bool('EV_USE_EPOLL', have_header('sys/epoll.h'))
|
82
84
|
define_bool('EV_USE_KQUEUE', have_header('sys/event.h') && have_header('sys/queue.h'))
|
@@ -88,10 +90,10 @@ else
|
|
88
90
|
|
89
91
|
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
90
92
|
|
91
|
-
$CFLAGS <<
|
92
|
-
$CFLAGS <<
|
93
|
-
$CFLAGS <<
|
94
|
-
$CFLAGS <<
|
93
|
+
$CFLAGS << ' -Wno-comment'
|
94
|
+
$CFLAGS << ' -Wno-unused-result'
|
95
|
+
$CFLAGS << ' -Wno-dangling-else'
|
96
|
+
$CFLAGS << ' -Wno-parentheses'
|
95
97
|
end
|
96
98
|
|
97
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/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;
|
@@ -474,6 +475,7 @@ void Init_Polyphony(void) {
|
|
474
475
|
ID_ivar_io = rb_intern("@io");
|
475
476
|
ID_ivar_multishot_accept_queue = rb_intern("@multishot_accept_queue");
|
476
477
|
ID_ivar_parked = rb_intern("@parked");
|
478
|
+
ID_ivar_result = rb_intern("@result");
|
477
479
|
ID_ivar_runnable = rb_intern("@runnable");
|
478
480
|
ID_ivar_running = rb_intern("@running");
|
479
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;
|
@@ -147,6 +149,9 @@ void Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
|
147
149
|
void Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
|
148
150
|
VALUE Thread_switch_fiber(VALUE thread);
|
149
151
|
|
152
|
+
VALUE Event_signal(int argc, VALUE *argv, VALUE event);
|
153
|
+
VALUE Event_await(VALUE event);
|
154
|
+
|
150
155
|
VALUE Polyphony_snooze(VALUE self);
|
151
156
|
|
152
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
|
}
|