polyphony 1.5 → 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 +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
|
}
|