polyphony 0.57.0 → 0.58
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/ext/polyphony/backend_common.c +11 -0
- data/ext/polyphony/backend_common.h +3 -0
- data/ext/polyphony/backend_io_uring.c +17 -7
- data/ext/polyphony/backend_io_uring_context.c +2 -3
- data/ext/polyphony/backend_libev.c +17 -6
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +29 -0
- data/test/test_thread.rb +52 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8002b8c0e03afa8e915b5ed67d64c1fc288a5fa220dfb2c32d3966a78046eee
|
4
|
+
data.tar.gz: c3a46eeae1f048f4adee9d3130f5dd3593936e843c1874d928f742d1fa83053f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6681155761daee35b73c9674e69aa505786e576814db0c909028cb576d8609f99bccc79f80b7d06d90c7658747bc2589c9837d3bdb3419782147e573d39f278
|
7
|
+
data.tar.gz: 90197a8db54405ca37492a54a20adf00c85f142af606cad26ad823161825ccf6bd9a414adcbbf3e27eaf93eea1d94a7cbc50a2fb5982ee4ce48969d4378400cd
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,6 +5,14 @@
|
|
5
5
|
#include "polyphony.h"
|
6
6
|
#include "backend_common.h"
|
7
7
|
|
8
|
+
inline void initialize_backend_base(struct Backend_base *base) {
|
9
|
+
base->currently_polling = 0;
|
10
|
+
base->pending_count = 0;
|
11
|
+
base->idle_gc_period = 0;
|
12
|
+
base->idle_gc_last_time = 0;
|
13
|
+
base->idle_block = Qnil;
|
14
|
+
}
|
15
|
+
|
8
16
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
9
17
|
#ifndef __NR_pidfd_open
|
10
18
|
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
@@ -174,6 +182,9 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
174
182
|
}
|
175
183
|
|
176
184
|
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
185
|
+
if (base->idle_block != Qnil)
|
186
|
+
rb_funcall(base->idle_block, ID_call, 0);
|
187
|
+
|
177
188
|
if (base->idle_gc_period == 0) return;
|
178
189
|
|
179
190
|
double now = current_time();
|
@@ -9,8 +9,11 @@ struct Backend_base {
|
|
9
9
|
unsigned int pending_count;
|
10
10
|
double idle_gc_period;
|
11
11
|
double idle_gc_last_time;
|
12
|
+
VALUE idle_block;
|
12
13
|
};
|
13
14
|
|
15
|
+
void initialize_backend_base(struct Backend_base *base);
|
16
|
+
|
14
17
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
15
18
|
int pidfd_open(pid_t pid, unsigned int flags);
|
16
19
|
#endif
|
@@ -42,13 +42,19 @@ typedef struct Backend_t {
|
|
42
42
|
int event_fd;
|
43
43
|
} Backend_t;
|
44
44
|
|
45
|
+
static void Backend_mark(void *ptr) {
|
46
|
+
Backend_t *backend = ptr;
|
47
|
+
if (backend->base.idle_block != Qnil)
|
48
|
+
rb_gc_mark(backend->base.idle_block);
|
49
|
+
}
|
50
|
+
|
45
51
|
static size_t Backend_size(const void *ptr) {
|
46
52
|
return sizeof(Backend_t);
|
47
53
|
}
|
48
54
|
|
49
55
|
static const rb_data_type_t Backend_type = {
|
50
56
|
"IOUringBackend",
|
51
|
-
{
|
57
|
+
{Backend_mark, 0, Backend_size,},
|
52
58
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
53
59
|
};
|
54
60
|
|
@@ -65,11 +71,7 @@ static VALUE Backend_initialize(VALUE self) {
|
|
65
71
|
Backend_t *backend;
|
66
72
|
GetBackend(self, backend);
|
67
73
|
|
68
|
-
backend->base
|
69
|
-
backend->base.pending_count = 0;
|
70
|
-
backend->base.idle_gc_period = 0;
|
71
|
-
backend->base.idle_gc_last_time = 0;
|
72
|
-
|
74
|
+
initialize_backend_base(&backend->base);
|
73
75
|
backend->pending_sqes = 0;
|
74
76
|
backend->prepared_limit = 2048;
|
75
77
|
|
@@ -134,6 +136,7 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
134
136
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
135
137
|
if (!ctx) return;
|
136
138
|
|
139
|
+
// 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);
|
137
140
|
ctx->result = cqe->res;
|
138
141
|
if (ctx->ref_count == 2 && ctx->result != -ECANCELED && ctx->fiber)
|
139
142
|
Fiber_make_runnable(ctx->fiber, ctx->resume_value);
|
@@ -908,7 +911,6 @@ int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duratio
|
|
908
911
|
|
909
912
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
910
913
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
911
|
-
|
912
914
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
913
915
|
return context_store_release(&backend->store, ctx);
|
914
916
|
}
|
@@ -1185,6 +1187,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1185
1187
|
return self;
|
1186
1188
|
}
|
1187
1189
|
|
1190
|
+
VALUE Backend_idle_block_set(VALUE self, VALUE block) {
|
1191
|
+
Backend_t *backend;
|
1192
|
+
GetBackend(self, backend);
|
1193
|
+
backend->base.idle_block = block;
|
1194
|
+
return self;
|
1195
|
+
}
|
1196
|
+
|
1188
1197
|
inline VALUE Backend_run_idle_tasks(VALUE self) {
|
1189
1198
|
Backend_t *backend;
|
1190
1199
|
GetBackend(self, backend);
|
@@ -1359,6 +1368,7 @@ void Init_Backend() {
|
|
1359
1368
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1360
1369
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1361
1370
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1371
|
+
rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
|
1362
1372
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1363
1373
|
|
1364
1374
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
@@ -37,8 +37,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
37
37
|
ctx = malloc(sizeof(op_context_t));
|
38
38
|
}
|
39
39
|
ctx->id = (++store->last_id);
|
40
|
-
// printf("acquire %d (%s)\n", ctx->id, op_type_to_str(type));
|
41
|
-
|
40
|
+
// printf("acquire %p %d (%s)\n", ctx, ctx->id, op_type_to_str(type));
|
42
41
|
ctx->prev = NULL;
|
43
42
|
ctx->next = store->taken;
|
44
43
|
if (store->taken) store->taken->prev = ctx;
|
@@ -55,7 +54,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
55
54
|
|
56
55
|
// returns true if ctx was released
|
57
56
|
inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
58
|
-
// printf("release %d (%s, ref_count: %d)\n", ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
57
|
+
// printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
59
58
|
|
60
59
|
assert(ctx->ref_count);
|
61
60
|
|
@@ -73,13 +73,19 @@ typedef struct Backend_t {
|
|
73
73
|
struct ev_async break_async;
|
74
74
|
} Backend_t;
|
75
75
|
|
76
|
+
static void Backend_mark(void *ptr) {
|
77
|
+
Backend_t *backend = ptr;
|
78
|
+
if (backend->base.idle_block != Qnil)
|
79
|
+
rb_gc_mark(backend->base.idle_block);
|
80
|
+
}
|
81
|
+
|
76
82
|
static size_t Backend_size(const void *ptr) {
|
77
83
|
return sizeof(Backend_t);
|
78
84
|
}
|
79
85
|
|
80
86
|
static const rb_data_type_t Backend_type = {
|
81
87
|
"LibevBackend",
|
82
|
-
{
|
88
|
+
{Backend_mark, 0, Backend_size,},
|
83
89
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
84
90
|
};
|
85
91
|
|
@@ -110,6 +116,8 @@ static VALUE Backend_initialize(VALUE self) {
|
|
110
116
|
Backend_t *backend;
|
111
117
|
|
112
118
|
GetBackend(self, backend);
|
119
|
+
|
120
|
+
initialize_backend_base(&backend->base);
|
113
121
|
backend->ev_loop = libev_new_loop();
|
114
122
|
|
115
123
|
// start async watcher used for breaking a poll op (from another thread)
|
@@ -119,11 +127,6 @@ static VALUE Backend_initialize(VALUE self) {
|
|
119
127
|
// block when no other watcher is active
|
120
128
|
ev_unref(backend->ev_loop);
|
121
129
|
|
122
|
-
backend->base.currently_polling = 0;
|
123
|
-
backend->base.pending_count = 0;
|
124
|
-
backend->base.idle_gc_period = 0;
|
125
|
-
backend->base.idle_gc_last_time = 0;
|
126
|
-
|
127
130
|
return Qnil;
|
128
131
|
}
|
129
132
|
|
@@ -1290,6 +1293,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1290
1293
|
return self;
|
1291
1294
|
}
|
1292
1295
|
|
1296
|
+
VALUE Backend_idle_block_set(VALUE self, VALUE block) {
|
1297
|
+
Backend_t *backend;
|
1298
|
+
GetBackend(self, backend);
|
1299
|
+
backend->base.idle_block = block;
|
1300
|
+
return self;
|
1301
|
+
}
|
1302
|
+
|
1293
1303
|
inline VALUE Backend_run_idle_tasks(VALUE self) {
|
1294
1304
|
Backend_t *backend;
|
1295
1305
|
GetBackend(self, backend);
|
@@ -1448,6 +1458,7 @@ void Init_Backend() {
|
|
1448
1458
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1449
1459
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1450
1460
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1461
|
+
rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
|
1451
1462
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1452
1463
|
|
1453
1464
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -340,9 +340,38 @@ class BackendTest < MiniTest::Test
|
|
340
340
|
# GC period.
|
341
341
|
sleep 0.05
|
342
342
|
assert_equal count + 1, GC.count
|
343
|
+
|
344
|
+
@backend.idle_gc_period = 0
|
345
|
+
count = GC.count
|
346
|
+
sleep 0.001
|
347
|
+
sleep 0.002
|
348
|
+
sleep 0.003
|
349
|
+
assert_equal count, GC.count
|
343
350
|
ensure
|
344
351
|
GC.enable
|
345
352
|
end
|
353
|
+
|
354
|
+
def test_idle_block
|
355
|
+
counter = 0
|
356
|
+
|
357
|
+
@backend.idle_block = proc { counter += 1 }
|
358
|
+
|
359
|
+
3.times { snooze }
|
360
|
+
assert_equal 0, counter
|
361
|
+
|
362
|
+
sleep 0.01
|
363
|
+
assert_equal 1, counter
|
364
|
+
sleep 0.01
|
365
|
+
assert_equal 2, counter
|
366
|
+
|
367
|
+
assert_equal 2, counter
|
368
|
+
3.times { snooze }
|
369
|
+
assert_equal 2, counter
|
370
|
+
|
371
|
+
@backend.idle_block = nil
|
372
|
+
sleep 0.01
|
373
|
+
assert_equal 2, counter
|
374
|
+
end
|
346
375
|
end
|
347
376
|
|
348
377
|
class BackendChainTest < MiniTest::Test
|
data/test/test_thread.rb
CHANGED
@@ -171,4 +171,56 @@ class ThreadTest < MiniTest::Test
|
|
171
171
|
t&.kill
|
172
172
|
t&.join
|
173
173
|
end
|
174
|
+
|
175
|
+
def test_idle_gc
|
176
|
+
GC.disable
|
177
|
+
|
178
|
+
count = GC.count
|
179
|
+
snooze
|
180
|
+
assert_equal count, GC.count
|
181
|
+
sleep 0.01
|
182
|
+
assert_equal count, GC.count
|
183
|
+
|
184
|
+
Thread.current.idle_gc_period = 0.1
|
185
|
+
snooze
|
186
|
+
assert_equal count, GC.count
|
187
|
+
sleep 0.05
|
188
|
+
assert_equal count, GC.count
|
189
|
+
# The idle tasks are ran at most once per fiber switch, before the backend
|
190
|
+
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
191
|
+
# only 0.05s have passed since the gc period was set.
|
192
|
+
sleep 0.07
|
193
|
+
assert_equal count, GC.count
|
194
|
+
# Upon the third sleep the GC should be triggered, at 0.12s post setting the
|
195
|
+
# GC period.
|
196
|
+
sleep 0.05
|
197
|
+
assert_equal count + 1, GC.count
|
198
|
+
|
199
|
+
Thread.current.idle_gc_period = 0
|
200
|
+
count = GC.count
|
201
|
+
sleep 0.001
|
202
|
+
sleep 0.002
|
203
|
+
sleep 0.003
|
204
|
+
assert_equal count, GC.count
|
205
|
+
ensure
|
206
|
+
GC.enable
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_on_idle
|
210
|
+
counter = 0
|
211
|
+
|
212
|
+
Thread.current.on_idle { counter += 1 }
|
213
|
+
|
214
|
+
3.times { snooze }
|
215
|
+
assert_equal 0, counter
|
216
|
+
|
217
|
+
sleep 0.01
|
218
|
+
assert_equal 1, counter
|
219
|
+
sleep 0.01
|
220
|
+
assert_equal 2, counter
|
221
|
+
|
222
|
+
assert_equal 2, counter
|
223
|
+
3.times { snooze }
|
224
|
+
assert_equal 2, counter
|
225
|
+
end
|
174
226
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.58'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|