polyphony 0.64 → 0.68
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/workflows/test.yml +1 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +10 -40
- data/bin/pdbg +112 -0
- data/examples/core/await.rb +9 -1
- data/ext/polyphony/backend_common.c +14 -1
- data/ext/polyphony/backend_common.h +3 -1
- data/ext/polyphony/backend_io_uring.c +85 -25
- data/ext/polyphony/backend_io_uring_context.c +42 -0
- data/ext/polyphony/backend_io_uring_context.h +6 -9
- data/ext/polyphony/backend_libev.c +85 -39
- data/ext/polyphony/fiber.c +20 -0
- data/ext/polyphony/polyphony.c +2 -0
- data/ext/polyphony/polyphony.h +5 -2
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +7 -3
- data/ext/polyphony/runqueue.h +4 -3
- data/ext/polyphony/runqueue_ring_buffer.c +25 -14
- data/ext/polyphony/runqueue_ring_buffer.h +2 -0
- data/ext/polyphony/thread.c +2 -8
- data/lib/polyphony.rb +6 -0
- data/lib/polyphony/debugger.rb +225 -0
- data/lib/polyphony/extensions/debug.rb +1 -1
- data/lib/polyphony/extensions/fiber.rb +64 -71
- data/lib/polyphony/extensions/io.rb +4 -2
- data/lib/polyphony/extensions/openssl.rb +66 -0
- data/lib/polyphony/extensions/socket.rb +8 -2
- data/lib/polyphony/net.rb +1 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +6 -5
- data/test/stress.rb +6 -2
- data/test/test_backend.rb +13 -4
- data/test/test_fiber.rb +35 -11
- data/test/test_global_api.rb +9 -4
- data/test/test_io.rb +2 -0
- data/test/test_socket.rb +14 -11
- data/test/test_supervise.rb +24 -24
- data/test/test_thread.rb +3 -0
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +2 -2
- data/test/test_timer.rb +5 -3
- metadata +5 -3
@@ -50,6 +50,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
50
50
|
ctx->resume_value = Qnil;
|
51
51
|
ctx->ref_count = 2;
|
52
52
|
ctx->result = 0;
|
53
|
+
ctx->buffer_count = 0;
|
53
54
|
|
54
55
|
store->taken_count++;
|
55
56
|
|
@@ -67,6 +68,8 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
67
68
|
ctx->ref_count--;
|
68
69
|
if (ctx->ref_count) return 0;
|
69
70
|
|
71
|
+
if (ctx->buffer_count > 1) free(ctx->buffers);
|
72
|
+
|
70
73
|
store->taken_count--;
|
71
74
|
store->available_count++;
|
72
75
|
|
@@ -93,3 +96,42 @@ void context_store_free(op_context_store_t *store) {
|
|
93
96
|
store->taken = next;
|
94
97
|
}
|
95
98
|
}
|
99
|
+
|
100
|
+
inline void context_store_mark_taken_buffers(op_context_store_t *store) {
|
101
|
+
op_context_t *ctx = store->taken;
|
102
|
+
while (ctx) {
|
103
|
+
for (unsigned int i = 0; i < ctx->buffer_count; i++)
|
104
|
+
rb_gc_mark(i == 0 ? ctx->buffer0 : ctx->buffers[i - 1]);
|
105
|
+
ctx = ctx->next;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
inline void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers) {
|
110
|
+
// attaching buffers to the context is done in order to ensure that any GC
|
111
|
+
// pass done before the context is released will mark those buffers, even if
|
112
|
+
// the fiber has already been resumed and the buffers are not in use anymore.
|
113
|
+
// This is done in order to prevent a possible race condition where on the
|
114
|
+
// kernel side the buffers are still in use, but in userspace they have
|
115
|
+
// effectively been freed after a GC pass.
|
116
|
+
ctx->buffer_count = count;
|
117
|
+
if (count > 1)
|
118
|
+
ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
|
119
|
+
for (unsigned int i = 0; i < count; i++)
|
120
|
+
if (!i) ctx->buffer0 = buffers[0];
|
121
|
+
else ctx->buffers[i - 1] = buffers[i];
|
122
|
+
}
|
123
|
+
|
124
|
+
inline void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...) {
|
125
|
+
va_list values;
|
126
|
+
|
127
|
+
va_start(values, count);
|
128
|
+
|
129
|
+
ctx->buffer_count = count;
|
130
|
+
if (count > 1)
|
131
|
+
ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
|
132
|
+
for (unsigned int i = 0; i < count; i++)
|
133
|
+
if (!i) ctx->buffer0 = va_arg(values, VALUE);
|
134
|
+
else ctx->buffers[i - 1] = va_arg(values, VALUE);
|
135
|
+
|
136
|
+
va_end(values);
|
137
|
+
}
|
@@ -27,6 +27,9 @@ typedef struct op_context {
|
|
27
27
|
int result;
|
28
28
|
VALUE fiber;
|
29
29
|
VALUE resume_value;
|
30
|
+
unsigned int buffer_count;
|
31
|
+
VALUE buffer0;
|
32
|
+
VALUE *buffers;
|
30
33
|
} op_context_t;
|
31
34
|
|
32
35
|
typedef struct op_context_store {
|
@@ -43,14 +46,8 @@ void context_store_initialize(op_context_store_t *store);
|
|
43
46
|
op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type);
|
44
47
|
int context_store_release(op_context_store_t *store, op_context_t *ctx);
|
45
48
|
void context_store_free(op_context_store_t *store);
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if (ctx->ref_count)
|
50
|
-
ctx->ref_count -= 1;
|
51
|
-
else
|
52
|
-
context_store_release(store, ctx);
|
53
|
-
return completed;
|
54
|
-
}
|
49
|
+
void context_store_mark_taken_buffers(op_context_store_t *store);
|
50
|
+
void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers);
|
51
|
+
void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...);
|
55
52
|
|
56
53
|
#endif /* BACKEND_IO_URING_CONTEXT_H */
|
@@ -941,9 +941,8 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
941
941
|
error:
|
942
942
|
return RAISE_EXCEPTION(switchpoint_result);
|
943
943
|
}
|
944
|
-
#
|
945
|
-
|
946
|
-
VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
944
|
+
#else
|
945
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
947
946
|
Backend_t *backend;
|
948
947
|
struct libev_io watcher;
|
949
948
|
VALUE switchpoint_result = Qnil;
|
@@ -1018,7 +1017,7 @@ error:
|
|
1018
1017
|
return RAISE_EXCEPTION(switchpoint_result);
|
1019
1018
|
}
|
1020
1019
|
|
1021
|
-
VALUE
|
1020
|
+
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
1022
1021
|
Backend_t *backend;
|
1023
1022
|
struct libev_io watcher;
|
1024
1023
|
VALUE switchpoint_result = Qnil;
|
@@ -1097,6 +1096,7 @@ done:
|
|
1097
1096
|
error:
|
1098
1097
|
return RAISE_EXCEPTION(switchpoint_result);
|
1099
1098
|
}
|
1099
|
+
#endif
|
1100
1100
|
|
1101
1101
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
1102
1102
|
Backend_t *backend;
|
@@ -1384,6 +1384,64 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1384
1384
|
return 0;
|
1385
1385
|
}
|
1386
1386
|
|
1387
|
+
static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
|
1388
|
+
struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
|
1389
|
+
#ifdef POLYPHONY_LINUX
|
1390
|
+
backend->base.op_count++;
|
1391
|
+
while (1) {
|
1392
|
+
*chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
|
1393
|
+
if (*chunk_len >= 0) return 0;
|
1394
|
+
|
1395
|
+
int err = errno;
|
1396
|
+
if (err != EWOULDBLOCK && err != EAGAIN) return err;
|
1397
|
+
|
1398
|
+
*result = libev_wait_rw_fd_with_watcher(backend, src_fd, dest_fd, watcher);
|
1399
|
+
if (TEST_EXCEPTION(*result)) return -1;
|
1400
|
+
}
|
1401
|
+
#else
|
1402
|
+
char *buf = malloc(maxlen);
|
1403
|
+
int ret;
|
1404
|
+
|
1405
|
+
backend->base.op_count++;
|
1406
|
+
while (1) {
|
1407
|
+
*chunk_len = read(src_fd, buf, maxlen);
|
1408
|
+
if (*chunk_len >= 0) break;
|
1409
|
+
|
1410
|
+
ret = errno;
|
1411
|
+
if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
|
1412
|
+
|
1413
|
+
*result = libev_wait_rw_fd_with_watcher(backend, src_fd, -1, watcher);
|
1414
|
+
if (TEST_EXCEPTION(*result)) goto exception;
|
1415
|
+
}
|
1416
|
+
|
1417
|
+
backend->base.op_count++;
|
1418
|
+
char *ptr = buf;
|
1419
|
+
int left = *chunk_len;
|
1420
|
+
while (left > 0) {
|
1421
|
+
ssize_t n = write(dest_fd, ptr, left);
|
1422
|
+
if (n < 0) {
|
1423
|
+
ret = errno;
|
1424
|
+
if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
|
1425
|
+
|
1426
|
+
*result = libev_wait_rw_fd_with_watcher(backend, -1, dest_fd, watcher);
|
1427
|
+
|
1428
|
+
if (TEST_EXCEPTION(*result)) goto exception;
|
1429
|
+
}
|
1430
|
+
else {
|
1431
|
+
ptr += n;
|
1432
|
+
left -= n;
|
1433
|
+
}
|
1434
|
+
}
|
1435
|
+
ret = 0;
|
1436
|
+
goto done;
|
1437
|
+
exception:
|
1438
|
+
ret = -1;
|
1439
|
+
done:
|
1440
|
+
free(buf);
|
1441
|
+
return ret;
|
1442
|
+
#endif
|
1443
|
+
}
|
1444
|
+
|
1387
1445
|
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1388
1446
|
Backend_t *backend;
|
1389
1447
|
GetBackend(self, backend);
|
@@ -1421,26 +1479,13 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1421
1479
|
fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
|
1422
1480
|
|
1423
1481
|
if (prefix != Qnil) {
|
1424
|
-
|
1482
|
+
err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
|
1425
1483
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1426
1484
|
}
|
1427
1485
|
while (1) {
|
1428
|
-
int chunk_len;
|
1429
|
-
|
1430
|
-
|
1431
|
-
backend->base.op_count++;
|
1432
|
-
chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
|
1433
|
-
if (chunk_len < 0) {
|
1434
|
-
err = errno;
|
1435
|
-
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1436
|
-
|
1437
|
-
result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, pipefd[1], &watcher);
|
1438
|
-
if (TEST_EXCEPTION(result)) goto error;
|
1439
|
-
}
|
1440
|
-
else {
|
1441
|
-
break;
|
1442
|
-
}
|
1443
|
-
}
|
1486
|
+
int chunk_len = 0;
|
1487
|
+
err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
|
1488
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1444
1489
|
if (chunk_len == 0) break;
|
1445
1490
|
|
1446
1491
|
total += chunk_len;
|
@@ -1453,20 +1498,12 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1453
1498
|
}
|
1454
1499
|
|
1455
1500
|
int left = chunk_len;
|
1456
|
-
while (
|
1457
|
-
|
1458
|
-
|
1459
|
-
if (
|
1460
|
-
err = errno;
|
1461
|
-
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1501
|
+
while (left > 0) {
|
1502
|
+
int len;
|
1503
|
+
err = splice_chunks_splice(backend, pipefd[0], dest_fptr->fd, left, &watcher, &result, &len);
|
1504
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1462
1505
|
|
1463
|
-
|
1464
|
-
if (TEST_EXCEPTION(result)) goto error;
|
1465
|
-
}
|
1466
|
-
else {
|
1467
|
-
left -= n;
|
1468
|
-
if (left == 0) break;
|
1469
|
-
}
|
1506
|
+
left -= len;
|
1470
1507
|
}
|
1471
1508
|
|
1472
1509
|
if (chunk_postfix != Qnil) {
|
@@ -1516,6 +1553,20 @@ VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
|
1516
1553
|
return self;
|
1517
1554
|
}
|
1518
1555
|
|
1556
|
+
void Backend_park_fiber(VALUE self, VALUE fiber) {
|
1557
|
+
Backend_t *backend;
|
1558
|
+
GetBackend(self, backend);
|
1559
|
+
|
1560
|
+
backend_base_park_fiber(&backend->base, fiber);
|
1561
|
+
}
|
1562
|
+
|
1563
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber) {
|
1564
|
+
Backend_t *backend;
|
1565
|
+
GetBackend(self, backend);
|
1566
|
+
|
1567
|
+
backend_base_unpark_fiber(&backend->base, fiber);
|
1568
|
+
}
|
1569
|
+
|
1519
1570
|
void Init_Backend() {
|
1520
1571
|
ev_set_allocator(xrealloc);
|
1521
1572
|
|
@@ -1550,13 +1601,8 @@ void Init_Backend() {
|
|
1550
1601
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1551
1602
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
1552
1603
|
|
1553
|
-
#ifdef POLYPHONY_LINUX
|
1554
1604
|
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1555
1605
|
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1556
|
-
#else
|
1557
|
-
rb_define_method(cBackend, "splice", Backend_fake_splice, 3);
|
1558
|
-
rb_define_method(cBackend, "splice_to_eof", Backend_fake_splice_to_eof, 3);
|
1559
|
-
#endif
|
1560
1606
|
|
1561
1607
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
1562
1608
|
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
data/ext/polyphony/fiber.c
CHANGED
@@ -114,6 +114,22 @@ VALUE Fiber_receive_all_pending(VALUE self) {
|
|
114
114
|
return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
|
115
115
|
}
|
116
116
|
|
117
|
+
VALUE Fiber_park(VALUE self) {
|
118
|
+
rb_ivar_set(self, ID_ivar_parked, Qtrue);
|
119
|
+
Backend_park_fiber(BACKEND(), self);
|
120
|
+
return self;
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE Fiber_unpark(VALUE self) {
|
124
|
+
rb_ivar_set(self, ID_ivar_parked, Qnil);
|
125
|
+
Backend_unpark_fiber(BACKEND(), self);
|
126
|
+
return self;
|
127
|
+
}
|
128
|
+
|
129
|
+
VALUE Fiber_parked_p(VALUE self) {
|
130
|
+
return rb_ivar_get(self, ID_ivar_parked);
|
131
|
+
}
|
132
|
+
|
117
133
|
void Init_Fiber() {
|
118
134
|
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
119
135
|
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
@@ -128,6 +144,10 @@ void Init_Fiber() {
|
|
128
144
|
rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
|
129
145
|
rb_define_method(cFiber, "mailbox", Fiber_mailbox, 0);
|
130
146
|
|
147
|
+
rb_define_method(cFiber, "__park__", Fiber_park, 0);
|
148
|
+
rb_define_method(cFiber, "__unpark__", Fiber_unpark, 0);
|
149
|
+
rb_define_method(cFiber, "__parked__?", Fiber_parked_p, 0);
|
150
|
+
|
131
151
|
SYM_dead = ID2SYM(rb_intern("dead"));
|
132
152
|
SYM_running = ID2SYM(rb_intern("running"));
|
133
153
|
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -12,6 +12,7 @@ ID ID_invoke;
|
|
12
12
|
ID ID_new;
|
13
13
|
ID ID_ivar_blocking_mode;
|
14
14
|
ID ID_ivar_io;
|
15
|
+
ID ID_ivar_parked;
|
15
16
|
ID ID_ivar_runnable;
|
16
17
|
ID ID_ivar_running;
|
17
18
|
ID ID_ivar_thread;
|
@@ -160,6 +161,7 @@ void Init_Polyphony() {
|
|
160
161
|
ID_invoke = rb_intern("invoke");
|
161
162
|
ID_ivar_blocking_mode = rb_intern("@blocking_mode");
|
162
163
|
ID_ivar_io = rb_intern("@io");
|
164
|
+
ID_ivar_parked = rb_intern("@parked");
|
163
165
|
ID_ivar_runnable = rb_intern("@runnable");
|
164
166
|
ID_ivar_running = rb_intern("@running");
|
165
167
|
ID_ivar_thread = rb_intern("@thread");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -44,6 +44,7 @@ extern ID ID_invoke;
|
|
44
44
|
extern ID ID_ivar_backend;
|
45
45
|
extern ID ID_ivar_blocking_mode;
|
46
46
|
extern ID ID_ivar_io;
|
47
|
+
extern ID ID_ivar_parked;
|
47
48
|
extern ID ID_ivar_runnable;
|
48
49
|
extern ID ID_ivar_running;
|
49
50
|
extern ID ID_ivar_thread;
|
@@ -115,9 +116,11 @@ VALUE Backend_run_idle_tasks(VALUE self);
|
|
115
116
|
VALUE Backend_switch_fiber(VALUE self);
|
116
117
|
void Backend_schedule_fiber(VALUE thread, VALUE self, VALUE fiber, VALUE value, int prioritize);
|
117
118
|
void Backend_unschedule_fiber(VALUE self, VALUE fiber);
|
119
|
+
void Backend_park_fiber(VALUE self, VALUE fiber);
|
120
|
+
void Backend_unpark_fiber(VALUE self, VALUE fiber);
|
118
121
|
|
119
|
-
|
120
|
-
|
122
|
+
void Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
123
|
+
void Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
|
121
124
|
VALUE Thread_switch_fiber(VALUE thread);
|
122
125
|
|
123
126
|
VALUE Polyphony_snooze(VALUE self);
|
data/ext/polyphony/queue.c
CHANGED
@@ -78,7 +78,7 @@ inline void queue_schedule_blocked_fibers_to_capacity(Queue_t *queue) {
|
|
78
78
|
}
|
79
79
|
}
|
80
80
|
|
81
|
-
inline void capped_queue_block_push(Queue_t *queue) {
|
81
|
+
static inline void capped_queue_block_push(Queue_t *queue) {
|
82
82
|
VALUE fiber = rb_fiber_current();
|
83
83
|
VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
84
84
|
VALUE switchpoint_result;
|
data/ext/polyphony/runqueue.c
CHANGED
@@ -40,19 +40,23 @@ inline int runqueue_index_of(runqueue_t *runqueue, VALUE fiber) {
|
|
40
40
|
return runqueue_ring_buffer_index_of(&runqueue->entries, fiber);
|
41
41
|
}
|
42
42
|
|
43
|
+
inline void runqueue_migrate(runqueue_t *src, runqueue_t *dest, VALUE fiber) {
|
44
|
+
runqueue_ring_buffer_migrate(&src->entries, &dest->entries, fiber);
|
45
|
+
}
|
46
|
+
|
43
47
|
inline void runqueue_clear(runqueue_t *runqueue) {
|
44
48
|
runqueue_ring_buffer_clear(&runqueue->entries);
|
45
49
|
}
|
46
50
|
|
47
|
-
inline
|
51
|
+
inline unsigned int runqueue_size(runqueue_t *runqueue) {
|
48
52
|
return runqueue->entries.size;
|
49
53
|
}
|
50
54
|
|
51
|
-
inline
|
55
|
+
inline unsigned int runqueue_len(runqueue_t *runqueue) {
|
52
56
|
return runqueue->entries.count;
|
53
57
|
}
|
54
58
|
|
55
|
-
inline
|
59
|
+
inline unsigned int runqueue_max_len(runqueue_t *runqueue) {
|
56
60
|
unsigned int max_len = runqueue->high_watermark;
|
57
61
|
runqueue->high_watermark = 0;
|
58
62
|
return max_len;
|
data/ext/polyphony/runqueue.h
CHANGED
@@ -18,10 +18,11 @@ void runqueue_unshift(runqueue_t *runqueue, VALUE fiber, VALUE value, int resche
|
|
18
18
|
runqueue_entry runqueue_shift(runqueue_t *runqueue);
|
19
19
|
void runqueue_delete(runqueue_t *runqueue, VALUE fiber);
|
20
20
|
int runqueue_index_of(runqueue_t *runqueue, VALUE fiber);
|
21
|
+
void runqueue_migrate(runqueue_t *src, runqueue_t *dest, VALUE fiber);
|
21
22
|
void runqueue_clear(runqueue_t *runqueue);
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
unsigned int runqueue_size(runqueue_t *runqueue);
|
24
|
+
unsigned int runqueue_len(runqueue_t *runqueue);
|
25
|
+
unsigned int runqueue_max_len(runqueue_t *runqueue);
|
25
26
|
int runqueue_empty_p(runqueue_t *runqueue);
|
26
27
|
|
27
28
|
#endif /* RUNQUEUE_H */
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#include "polyphony.h"
|
2
2
|
#include "runqueue_ring_buffer.h"
|
3
3
|
|
4
|
-
void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
4
|
+
inline void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
5
5
|
buffer->size = 1;
|
6
6
|
buffer->count = 0;
|
7
7
|
buffer->entries = malloc(buffer->size * sizeof(runqueue_entry));
|
@@ -9,17 +9,21 @@ void runqueue_ring_buffer_init(runqueue_ring_buffer *buffer) {
|
|
9
9
|
buffer->tail = 0;
|
10
10
|
}
|
11
11
|
|
12
|
-
void runqueue_ring_buffer_free(runqueue_ring_buffer *buffer) {
|
12
|
+
inline void runqueue_ring_buffer_free(runqueue_ring_buffer *buffer) {
|
13
13
|
free(buffer->entries);
|
14
14
|
}
|
15
15
|
|
16
|
-
int runqueue_ring_buffer_empty_p(runqueue_ring_buffer *buffer) {
|
16
|
+
inline int runqueue_ring_buffer_empty_p(runqueue_ring_buffer *buffer) {
|
17
17
|
return buffer->count == 0;
|
18
18
|
}
|
19
19
|
|
20
|
+
inline void runqueue_ring_buffer_clear(runqueue_ring_buffer *buffer) {
|
21
|
+
buffer->count = buffer->head = buffer->tail = 0;
|
22
|
+
}
|
23
|
+
|
20
24
|
static runqueue_entry nil_runqueue_entry = {(Qnil), (Qnil)};
|
21
25
|
|
22
|
-
runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
26
|
+
inline runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
23
27
|
if (buffer->count == 0) return nil_runqueue_entry;
|
24
28
|
|
25
29
|
runqueue_entry value = buffer->entries[buffer->head];
|
@@ -28,7 +32,7 @@ runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
|
28
32
|
return value;
|
29
33
|
}
|
30
34
|
|
31
|
-
void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
35
|
+
inline void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
32
36
|
unsigned int old_size = buffer->size;
|
33
37
|
buffer->size = old_size == 1 ? 4 : old_size * 2;
|
34
38
|
buffer->entries = realloc(buffer->entries, buffer->size * sizeof(runqueue_entry));
|
@@ -37,7 +41,7 @@ void runqueue_ring_buffer_resize(runqueue_ring_buffer *buffer) {
|
|
37
41
|
buffer->tail = buffer->head + buffer->count;
|
38
42
|
}
|
39
43
|
|
40
|
-
void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
44
|
+
inline void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
41
45
|
if (buffer->count == buffer->size) runqueue_ring_buffer_resize(buffer);
|
42
46
|
|
43
47
|
buffer->head = (buffer->head - 1) % buffer->size;
|
@@ -46,7 +50,7 @@ void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VAL
|
|
46
50
|
buffer->count++;
|
47
51
|
}
|
48
52
|
|
49
|
-
void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
53
|
+
inline void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value) {
|
50
54
|
if (buffer->count == buffer->size) runqueue_ring_buffer_resize(buffer);
|
51
55
|
|
52
56
|
buffer->entries[buffer->tail].fiber = fiber;
|
@@ -55,14 +59,14 @@ void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE
|
|
55
59
|
buffer->count++;
|
56
60
|
}
|
57
61
|
|
58
|
-
void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
62
|
+
inline void runqueue_ring_buffer_mark(runqueue_ring_buffer *buffer) {
|
59
63
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
60
64
|
rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].fiber);
|
61
65
|
rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size].value);
|
62
66
|
}
|
63
67
|
}
|
64
68
|
|
65
|
-
void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int idx) {
|
69
|
+
inline void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int idx) {
|
66
70
|
for (unsigned int idx2 = idx; idx2 != buffer->tail; idx2 = (idx2 + 1) % buffer->size) {
|
67
71
|
buffer->entries[idx2] = buffer->entries[(idx2 + 1) % buffer->size];
|
68
72
|
}
|
@@ -70,7 +74,7 @@ void runqueue_ring_buffer_delete_at(runqueue_ring_buffer *buffer, unsigned int i
|
|
70
74
|
buffer->tail = (buffer->tail - 1) % buffer->size;
|
71
75
|
}
|
72
76
|
|
73
|
-
void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
77
|
+
inline void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
74
78
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
75
79
|
unsigned int idx = (buffer->head + i) % buffer->size;
|
76
80
|
if (buffer->entries[idx].fiber == fiber) {
|
@@ -80,7 +84,7 @@ void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber) {
|
|
80
84
|
}
|
81
85
|
}
|
82
86
|
|
83
|
-
int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
87
|
+
inline int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
84
88
|
for (unsigned int i = 0; i < buffer->count; i++) {
|
85
89
|
unsigned int idx = (buffer->head + i) % buffer->size;
|
86
90
|
if (buffer->entries[idx].fiber == fiber)
|
@@ -89,6 +93,13 @@ int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
|
|
89
93
|
return -1;
|
90
94
|
}
|
91
95
|
|
92
|
-
void
|
93
|
-
|
94
|
-
|
96
|
+
inline void runqueue_ring_buffer_migrate(runqueue_ring_buffer *src, runqueue_ring_buffer *dest, VALUE fiber) {
|
97
|
+
for (unsigned int i = 0; i < src->count; i++) {
|
98
|
+
unsigned int idx = (src->head + i) % src->size;
|
99
|
+
if (src->entries[idx].fiber == fiber) {
|
100
|
+
runqueue_ring_buffer_push(dest, src->entries[idx].fiber, src->entries[idx].value);
|
101
|
+
runqueue_ring_buffer_delete_at(src, idx);
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|