polyphony 0.58 → 0.59
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/ext/polyphony/backend_common.c +95 -4
- data/ext/polyphony/backend_common.h +23 -2
- data/ext/polyphony/backend_io_uring.c +67 -21
- data/ext/polyphony/backend_libev.c +63 -17
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/polyphony.c +0 -7
- data/ext/polyphony/polyphony.h +6 -16
- data/ext/polyphony/polyphony_ext.c +0 -4
- data/ext/polyphony/runqueue.c +17 -82
- data/ext/polyphony/runqueue.h +27 -0
- data/ext/polyphony/thread.c +10 -99
- data/lib/polyphony/extensions/fiber.rb +2 -2
- data/lib/polyphony/extensions/thread.rb +1 -1
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +3 -3
- data/test/test_thread.rb +5 -11
- data/test/test_trace.rb +27 -49
- metadata +3 -4
- data/ext/polyphony/tracing.c +0 -11
- data/lib/polyphony/adapters/trace.rb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 313e33321df0e375d128a79fccfab98e06183adbdbde7916347f6795f56ca369
|
4
|
+
data.tar.gz: 6428c0516544bdb955fa465bf36c40b9b2f162306f3e5689848ff487f24c4440
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40c88f5d1c2aa4307dea78dcf1a2ba8d347ef252e7e56e67d466c291066d39544d051864ccd0138dd94ca0beef7af71f5257052b3556ab0c7294b1b94b517d47
|
7
|
+
data.tar.gz: 109410d6b222846b0c2b3f54061358ef922b57c9b6559c37aec36f27116e7ca389ff51762e988e2e9293a7a1358d97b80ada74daa4e44d7d25c1e5335351d8c6
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,12 +5,103 @@
|
|
5
5
|
#include "polyphony.h"
|
6
6
|
#include "backend_common.h"
|
7
7
|
|
8
|
-
inline void
|
8
|
+
inline void backend_base_initialize(struct Backend_base *base) {
|
9
|
+
runqueue_initialize(&base->runqueue);
|
9
10
|
base->currently_polling = 0;
|
10
11
|
base->pending_count = 0;
|
11
12
|
base->idle_gc_period = 0;
|
12
13
|
base->idle_gc_last_time = 0;
|
13
|
-
base->
|
14
|
+
base->idle_proc = Qnil;
|
15
|
+
base->trace_proc = Qnil;
|
16
|
+
}
|
17
|
+
|
18
|
+
inline void backend_base_finalize(struct Backend_base *base) {
|
19
|
+
runqueue_finalize(&base->runqueue);
|
20
|
+
}
|
21
|
+
|
22
|
+
inline void backend_base_mark(struct Backend_base *base) {
|
23
|
+
if (base->idle_proc != Qnil) rb_gc_mark(base->idle_proc);
|
24
|
+
if (base->trace_proc != Qnil) rb_gc_mark(base->trace_proc);
|
25
|
+
runqueue_mark(&base->runqueue);
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
29
|
+
VALUE current_fiber = rb_fiber_current();
|
30
|
+
runqueue_entry next;
|
31
|
+
unsigned int pending_ops_count = base->pending_count;
|
32
|
+
unsigned int backend_was_polled = 0;
|
33
|
+
unsigned int idle_tasks_run_count = 0;
|
34
|
+
|
35
|
+
if (SHOULD_TRACE(base) && (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse))
|
36
|
+
TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
37
|
+
|
38
|
+
while (1) {
|
39
|
+
next = runqueue_shift(&base->runqueue);
|
40
|
+
if (next.fiber != Qnil) {
|
41
|
+
// Polling for I/O op completion is normally done when the run queue is
|
42
|
+
// empty, but if the runqueue never empties, we'll never get to process
|
43
|
+
// any event completions. In order to prevent this, an anti-starve
|
44
|
+
// mechanism is employed, under the following conditions:
|
45
|
+
// - a blocking poll was not yet performed
|
46
|
+
// - there are pending blocking operations
|
47
|
+
// - the runqueue has signalled that a non-blocking poll should be
|
48
|
+
// performed
|
49
|
+
// - the run queue length high watermark has reached its threshold (currently 128)
|
50
|
+
// - the run queue switch counter has reached its threshold (currently 64)
|
51
|
+
if (!backend_was_polled && pending_ops_count && runqueue_should_poll_nonblocking(&base->runqueue)) {
|
52
|
+
// this prevents event starvation in case the run queue never empties
|
53
|
+
Backend_poll(backend, Qnil);
|
54
|
+
}
|
55
|
+
break;
|
56
|
+
}
|
57
|
+
|
58
|
+
if (!idle_tasks_run_count) {
|
59
|
+
idle_tasks_run_count++;
|
60
|
+
backend_run_idle_tasks(base);
|
61
|
+
}
|
62
|
+
if (pending_ops_count == 0) break;
|
63
|
+
Backend_poll(backend, Qtrue);
|
64
|
+
backend_was_polled = 1;
|
65
|
+
}
|
66
|
+
|
67
|
+
if (next.fiber == Qnil) return Qnil;
|
68
|
+
|
69
|
+
// run next fiber
|
70
|
+
COND_TRACE(base, 3, SYM_fiber_run, next.fiber, next.value);
|
71
|
+
|
72
|
+
rb_ivar_set(next.fiber, ID_ivar_runnable, Qnil);
|
73
|
+
RB_GC_GUARD(next.fiber);
|
74
|
+
RB_GC_GUARD(next.value);
|
75
|
+
return (next.fiber == current_fiber) ?
|
76
|
+
next.value : FIBER_TRANSFER(next.fiber, next.value);
|
77
|
+
}
|
78
|
+
|
79
|
+
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize) {
|
80
|
+
int already_runnable;
|
81
|
+
|
82
|
+
if (rb_fiber_alive_p(fiber) != Qtrue) return;
|
83
|
+
already_runnable = rb_ivar_get(fiber, ID_ivar_runnable) != Qnil;
|
84
|
+
|
85
|
+
COND_TRACE(base, 3, SYM_fiber_schedule, fiber, value);
|
86
|
+
(prioritize ? runqueue_unshift : runqueue_push)(&base->runqueue, fiber, value, already_runnable);
|
87
|
+
if (!already_runnable) {
|
88
|
+
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
89
|
+
if (rb_thread_current() != thread) {
|
90
|
+
// If the fiber scheduling is done across threads, we need to make sure the
|
91
|
+
// target thread is woken up in case it is in the middle of running its
|
92
|
+
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
93
|
+
// happen, not knowing that it there's already a fiber ready to run in its
|
94
|
+
// run queue.
|
95
|
+
Backend_wakeup(backend);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
102
|
+
if (base->trace_proc == Qnil) return;
|
103
|
+
|
104
|
+
rb_funcallv(base->trace_proc, ID_call, argc, argv);
|
14
105
|
}
|
15
106
|
|
16
107
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
@@ -182,8 +273,8 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
182
273
|
}
|
183
274
|
|
184
275
|
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
185
|
-
if (base->
|
186
|
-
rb_funcall(base->
|
276
|
+
if (base->idle_proc != Qnil)
|
277
|
+
rb_funcall(base->idle_proc, ID_call, 0);
|
187
278
|
|
188
279
|
if (base->idle_gc_period == 0) return;
|
189
280
|
|
@@ -3,16 +3,37 @@
|
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
5
|
#include "ruby/io.h"
|
6
|
+
#include "runqueue.h"
|
7
|
+
|
8
|
+
struct backend_stats {
|
9
|
+
int scheduled_fibers;
|
10
|
+
int waiting_fibers;
|
11
|
+
int pending_ops;
|
12
|
+
};
|
6
13
|
|
7
14
|
struct Backend_base {
|
15
|
+
runqueue_t runqueue;
|
8
16
|
unsigned int currently_polling;
|
9
17
|
unsigned int pending_count;
|
10
18
|
double idle_gc_period;
|
11
19
|
double idle_gc_last_time;
|
12
|
-
VALUE
|
20
|
+
VALUE idle_proc;
|
21
|
+
VALUE trace_proc;
|
13
22
|
};
|
14
23
|
|
15
|
-
void
|
24
|
+
void backend_base_initialize(struct Backend_base *base);
|
25
|
+
void backend_base_finalize(struct Backend_base *base);
|
26
|
+
void backend_base_mark(struct Backend_base *base);
|
27
|
+
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
28
|
+
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
29
|
+
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
30
|
+
|
31
|
+
// tracing
|
32
|
+
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
33
|
+
#define TRACE(base, ...) rb_funcall((base)->trace_proc, ID_call, __VA_ARGS__)
|
34
|
+
#define COND_TRACE(base, ...) if (SHOULD_TRACE(base)) { TRACE(base, __VA_ARGS__); }
|
35
|
+
|
36
|
+
|
16
37
|
|
17
38
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
18
39
|
int pidfd_open(pid_t pid, unsigned int flags);
|
@@ -44,8 +44,12 @@ typedef struct Backend_t {
|
|
44
44
|
|
45
45
|
static void Backend_mark(void *ptr) {
|
46
46
|
Backend_t *backend = ptr;
|
47
|
-
|
48
|
-
|
47
|
+
backend_base_mark(&backend->base);
|
48
|
+
}
|
49
|
+
|
50
|
+
static void Backend_free(void *ptr) {
|
51
|
+
Backend_t *backend = ptr;
|
52
|
+
backend_base_finalize(&backend->base);
|
49
53
|
}
|
50
54
|
|
51
55
|
static size_t Backend_size(const void *ptr) {
|
@@ -54,7 +58,7 @@ static size_t Backend_size(const void *ptr) {
|
|
54
58
|
|
55
59
|
static const rb_data_type_t Backend_type = {
|
56
60
|
"IOUringBackend",
|
57
|
-
{Backend_mark,
|
61
|
+
{Backend_mark, Backend_free, Backend_size,},
|
58
62
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
59
63
|
};
|
60
64
|
|
@@ -71,7 +75,7 @@ static VALUE Backend_initialize(VALUE self) {
|
|
71
75
|
Backend_t *backend;
|
72
76
|
GetBackend(self, backend);
|
73
77
|
|
74
|
-
|
78
|
+
backend_base_initialize(&backend->base);
|
75
79
|
backend->pending_sqes = 0;
|
76
80
|
backend->prepared_limit = 2048;
|
77
81
|
|
@@ -106,13 +110,6 @@ VALUE Backend_post_fork(VALUE self) {
|
|
106
110
|
return self;
|
107
111
|
}
|
108
112
|
|
109
|
-
unsigned int Backend_pending_count(VALUE self) {
|
110
|
-
Backend_t *backend;
|
111
|
-
GetBackend(self, backend);
|
112
|
-
|
113
|
-
return backend->base.pending_count;
|
114
|
-
}
|
115
|
-
|
116
113
|
typedef struct poll_context {
|
117
114
|
struct io_uring *ring;
|
118
115
|
struct io_uring_cqe *cqe;
|
@@ -189,24 +186,56 @@ void io_uring_backend_poll(Backend_t *backend) {
|
|
189
186
|
io_uring_cqe_seen(&backend->ring, poll_ctx.cqe);
|
190
187
|
}
|
191
188
|
|
192
|
-
VALUE Backend_poll(VALUE self, VALUE
|
193
|
-
int
|
189
|
+
inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
190
|
+
int is_blocking = blocking == Qtrue;
|
194
191
|
Backend_t *backend;
|
195
192
|
GetBackend(self, backend);
|
196
193
|
|
197
|
-
if (
|
194
|
+
if (!is_blocking && backend->pending_sqes) {
|
198
195
|
backend->pending_sqes = 0;
|
199
196
|
io_uring_submit(&backend->ring);
|
200
197
|
}
|
201
198
|
|
202
|
-
COND_TRACE(2, SYM_fiber_event_poll_enter,
|
203
|
-
if (
|
199
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
200
|
+
if (is_blocking) io_uring_backend_poll(backend);
|
204
201
|
io_uring_backend_handle_ready_cqes(backend);
|
205
|
-
COND_TRACE(2, SYM_fiber_event_poll_leave,
|
202
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
206
203
|
|
207
204
|
return self;
|
208
205
|
}
|
209
206
|
|
207
|
+
inline void Backend_schedule_fiber(VALUE thread, VALUE self, VALUE fiber, VALUE value, int prioritize) {
|
208
|
+
Backend_t *backend;
|
209
|
+
GetBackend(self, backend);
|
210
|
+
|
211
|
+
backend_base_schedule_fiber(thread, self, &backend->base, fiber, value, prioritize);
|
212
|
+
}
|
213
|
+
|
214
|
+
inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
215
|
+
Backend_t *backend;
|
216
|
+
GetBackend(self, backend);
|
217
|
+
|
218
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
219
|
+
}
|
220
|
+
|
221
|
+
inline VALUE Backend_switch_fiber(VALUE self) {
|
222
|
+
Backend_t *backend;
|
223
|
+
GetBackend(self, backend);
|
224
|
+
|
225
|
+
return backend_base_switch_fiber(self, &backend->base);
|
226
|
+
}
|
227
|
+
|
228
|
+
inline struct backend_stats Backend_stats(VALUE self) {
|
229
|
+
Backend_t *backend;
|
230
|
+
GetBackend(self, backend);
|
231
|
+
|
232
|
+
return (struct backend_stats){
|
233
|
+
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
234
|
+
.waiting_fibers = 0,
|
235
|
+
.pending_ops = backend->base.pending_count
|
236
|
+
};
|
237
|
+
}
|
238
|
+
|
210
239
|
VALUE Backend_wakeup(VALUE self) {
|
211
240
|
Backend_t *backend;
|
212
241
|
GetBackend(self, backend);
|
@@ -1187,10 +1216,10 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1187
1216
|
return self;
|
1188
1217
|
}
|
1189
1218
|
|
1190
|
-
VALUE
|
1219
|
+
VALUE Backend_idle_proc_set(VALUE self, VALUE block) {
|
1191
1220
|
Backend_t *backend;
|
1192
1221
|
GetBackend(self, backend);
|
1193
|
-
backend->base.
|
1222
|
+
backend->base.idle_proc = block;
|
1194
1223
|
return self;
|
1195
1224
|
}
|
1196
1225
|
|
@@ -1355,6 +1384,21 @@ error:
|
|
1355
1384
|
return RAISE_EXCEPTION(switchpoint_result);
|
1356
1385
|
}
|
1357
1386
|
|
1387
|
+
VALUE Backend_trace(int argc, VALUE *argv, VALUE self) {
|
1388
|
+
Backend_t *backend;
|
1389
|
+
GetBackend(self, backend);
|
1390
|
+
backend_trace(&backend->base, argc, argv);
|
1391
|
+
return self;
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
1395
|
+
Backend_t *backend;
|
1396
|
+
GetBackend(self, backend);
|
1397
|
+
|
1398
|
+
backend->base.trace_proc = block;
|
1399
|
+
return self;
|
1400
|
+
}
|
1401
|
+
|
1358
1402
|
void Init_Backend() {
|
1359
1403
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
1360
1404
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -1362,13 +1406,15 @@ void Init_Backend() {
|
|
1362
1406
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
1363
1407
|
rb_define_method(cBackend, "finalize", Backend_finalize, 0);
|
1364
1408
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
1409
|
+
rb_define_method(cBackend, "trace", Backend_trace, -1);
|
1410
|
+
rb_define_method(cBackend, "trace_proc=", Backend_trace_proc_set, 1);
|
1365
1411
|
|
1366
|
-
rb_define_method(cBackend, "poll", Backend_poll,
|
1412
|
+
rb_define_method(cBackend, "poll", Backend_poll, 1);
|
1367
1413
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1368
1414
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1369
1415
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1370
1416
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1371
|
-
rb_define_method(cBackend, "
|
1417
|
+
rb_define_method(cBackend, "idle_proc=", Backend_idle_proc_set, 1);
|
1372
1418
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1373
1419
|
|
1374
1420
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
@@ -75,8 +75,12 @@ typedef struct Backend_t {
|
|
75
75
|
|
76
76
|
static void Backend_mark(void *ptr) {
|
77
77
|
Backend_t *backend = ptr;
|
78
|
-
|
79
|
-
|
78
|
+
backend_base_mark(&backend->base);
|
79
|
+
}
|
80
|
+
|
81
|
+
static void Backend_free(void *ptr) {
|
82
|
+
Backend_t *backend = ptr;
|
83
|
+
backend_base_finalize(&backend->base);
|
80
84
|
}
|
81
85
|
|
82
86
|
static size_t Backend_size(const void *ptr) {
|
@@ -85,7 +89,7 @@ static size_t Backend_size(const void *ptr) {
|
|
85
89
|
|
86
90
|
static const rb_data_type_t Backend_type = {
|
87
91
|
"LibevBackend",
|
88
|
-
{Backend_mark,
|
92
|
+
{Backend_mark, Backend_free, Backend_size,},
|
89
93
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
90
94
|
};
|
91
95
|
|
@@ -117,7 +121,7 @@ static VALUE Backend_initialize(VALUE self) {
|
|
117
121
|
|
118
122
|
GetBackend(self, backend);
|
119
123
|
|
120
|
-
|
124
|
+
backend_base_initialize(&backend->base);
|
121
125
|
backend->ev_loop = libev_new_loop();
|
122
126
|
|
123
127
|
// start async watcher used for breaking a poll op (from another thread)
|
@@ -156,24 +160,38 @@ VALUE Backend_post_fork(VALUE self) {
|
|
156
160
|
return self;
|
157
161
|
}
|
158
162
|
|
159
|
-
inline
|
163
|
+
inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
160
164
|
Backend_t *backend;
|
161
165
|
GetBackend(self, backend);
|
162
166
|
|
163
|
-
|
167
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
168
|
+
backend->base.currently_polling = 1;
|
169
|
+
ev_run(backend->ev_loop, blocking == Qtrue ? EVRUN_ONCE : EVRUN_NOWAIT);
|
170
|
+
backend->base.currently_polling = 0;
|
171
|
+
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
172
|
+
|
173
|
+
return self;
|
164
174
|
}
|
165
175
|
|
166
|
-
|
176
|
+
inline void Backend_schedule_fiber(VALUE thread, VALUE self, VALUE fiber, VALUE value, int prioritize) {
|
167
177
|
Backend_t *backend;
|
168
178
|
GetBackend(self, backend);
|
169
179
|
|
170
|
-
|
171
|
-
|
172
|
-
ev_run(backend->ev_loop, nowait == Qtrue ? EVRUN_NOWAIT : EVRUN_ONCE);
|
173
|
-
backend->base.currently_polling = 0;
|
174
|
-
COND_TRACE(2, SYM_fiber_event_poll_leave, current_fiber);
|
180
|
+
backend_base_schedule_fiber(thread, self, &backend->base, fiber, value, prioritize);
|
181
|
+
}
|
175
182
|
|
176
|
-
|
183
|
+
inline void Backend_unschedule_fiber(VALUE self, VALUE fiber) {
|
184
|
+
Backend_t *backend;
|
185
|
+
GetBackend(self, backend);
|
186
|
+
|
187
|
+
runqueue_delete(&backend->base.runqueue, fiber);
|
188
|
+
}
|
189
|
+
|
190
|
+
inline VALUE Backend_switch_fiber(VALUE self) {
|
191
|
+
Backend_t *backend;
|
192
|
+
GetBackend(self, backend);
|
193
|
+
|
194
|
+
return backend_base_switch_fiber(self, &backend->base);
|
177
195
|
}
|
178
196
|
|
179
197
|
VALUE Backend_wakeup(VALUE self) {
|
@@ -193,6 +211,17 @@ VALUE Backend_wakeup(VALUE self) {
|
|
193
211
|
return Qnil;
|
194
212
|
}
|
195
213
|
|
214
|
+
inline struct backend_stats Backend_stats(VALUE self) {
|
215
|
+
Backend_t *backend;
|
216
|
+
GetBackend(self, backend);
|
217
|
+
|
218
|
+
return (struct backend_stats){
|
219
|
+
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
220
|
+
.waiting_fibers = 0,
|
221
|
+
.pending_ops = backend->base.pending_count
|
222
|
+
};
|
223
|
+
}
|
224
|
+
|
196
225
|
struct libev_io {
|
197
226
|
struct ev_io io;
|
198
227
|
VALUE fiber;
|
@@ -1293,10 +1322,10 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1293
1322
|
return self;
|
1294
1323
|
}
|
1295
1324
|
|
1296
|
-
VALUE
|
1325
|
+
VALUE Backend_idle_proc_set(VALUE self, VALUE block) {
|
1297
1326
|
Backend_t *backend;
|
1298
1327
|
GetBackend(self, backend);
|
1299
|
-
backend->base.
|
1328
|
+
backend->base.idle_proc = block;
|
1300
1329
|
return self;
|
1301
1330
|
}
|
1302
1331
|
|
@@ -1443,6 +1472,21 @@ error:
|
|
1443
1472
|
return RAISE_EXCEPTION(result);
|
1444
1473
|
}
|
1445
1474
|
|
1475
|
+
VALUE Backend_trace(int argc, VALUE *argv, VALUE self) {
|
1476
|
+
Backend_t *backend;
|
1477
|
+
GetBackend(self, backend);
|
1478
|
+
backend_trace(&backend->base, argc, argv);
|
1479
|
+
return self;
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
VALUE Backend_trace_proc_set(VALUE self, VALUE block) {
|
1483
|
+
Backend_t *backend;
|
1484
|
+
GetBackend(self, backend);
|
1485
|
+
|
1486
|
+
backend->base.trace_proc = block;
|
1487
|
+
return self;
|
1488
|
+
}
|
1489
|
+
|
1446
1490
|
void Init_Backend() {
|
1447
1491
|
ev_set_allocator(xrealloc);
|
1448
1492
|
|
@@ -1452,13 +1496,15 @@ void Init_Backend() {
|
|
1452
1496
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
1453
1497
|
rb_define_method(cBackend, "finalize", Backend_finalize, 0);
|
1454
1498
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
1499
|
+
rb_define_method(cBackend, "trace", Backend_trace, -1);
|
1500
|
+
rb_define_method(cBackend, "trace_proc=", Backend_trace_proc_set, 1);
|
1455
1501
|
|
1456
|
-
rb_define_method(cBackend, "poll", Backend_poll,
|
1502
|
+
rb_define_method(cBackend, "poll", Backend_poll, 1);
|
1457
1503
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1458
1504
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1459
1505
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1460
1506
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1461
|
-
rb_define_method(cBackend, "
|
1507
|
+
rb_define_method(cBackend, "idle_proc=", Backend_idle_proc_set, 1);
|
1462
1508
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1463
1509
|
|
1464
1510
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|