polyphony 0.44.0 → 0.45.0
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 +7 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +9 -11
- data/Rakefile +1 -1
- data/TODO.md +12 -7
- data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
- data/docs/api-reference/thread.md +1 -1
- data/docs/getting-started/overview.md +14 -14
- data/docs/getting-started/tutorial.md +1 -1
- data/examples/core/{xx-agent.rb → xx-backend.rb} +5 -5
- data/examples/io/xx-pry.rb +18 -0
- data/examples/io/xx-rack_server.rb +71 -0
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/ext/polyphony/backend.h +41 -0
- data/ext/polyphony/event.c +3 -3
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +175 -175
- data/ext/polyphony/polyphony.c +1 -1
- data/ext/polyphony/polyphony.h +4 -4
- data/ext/polyphony/polyphony_ext.c +2 -2
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/thread.c +21 -21
- data/lib/polyphony.rb +13 -12
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -2
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/sequel.rb +1 -1
- data/lib/polyphony/core/global_api.rb +11 -6
- data/lib/polyphony/core/resource_pool.rb +2 -2
- data/lib/polyphony/core/sync.rb +38 -2
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +31 -20
- data/lib/polyphony/extensions/fiber.rb +1 -1
- data/lib/polyphony/extensions/io.rb +7 -8
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +4 -14
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +4 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +4 -4
- data/test/test_io.rb +1 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_signal.rb +3 -3
- data/test/test_sync.rb +52 -0
- metadata +40 -30
- data/.gitbook.yaml +0 -4
- data/ext/polyphony/agent.h +0 -41
@@ -0,0 +1,41 @@
|
|
1
|
+
#ifndef BACKEND_H
|
2
|
+
#define BACKEND_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
// backend interface function signatures
|
7
|
+
|
8
|
+
// VALUE LibevBackend_accept(VALUE self, VALUE sock);
|
9
|
+
// VALUE LibevBackend_accept_loop(VALUE self, VALUE sock);
|
10
|
+
// VALUE libev_backend_await(VALUE self);
|
11
|
+
// VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port);
|
12
|
+
// VALUE LibevBackend_finalize(VALUE self);
|
13
|
+
// VALUE LibevBackend_post_fork(VALUE self);
|
14
|
+
// VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof);
|
15
|
+
// VALUE LibevBackend_read_loop(VALUE self, VALUE io);
|
16
|
+
// VALUE LibevBackend_sleep(VALUE self, VALUE duration);
|
17
|
+
// VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write);
|
18
|
+
// VALUE LibevBackend_wait_pid(VALUE self, VALUE pid);
|
19
|
+
// VALUE LibevBackend_write(int argc, VALUE *argv, VALUE self);
|
20
|
+
|
21
|
+
typedef VALUE (* backend_pending_count_t)(VALUE self);
|
22
|
+
typedef VALUE (*backend_poll_t)(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
|
23
|
+
typedef VALUE (* backend_ref_t)(VALUE self);
|
24
|
+
typedef int (* backend_ref_count_t)(VALUE self);
|
25
|
+
typedef void (* backend_reset_ref_count_t)(VALUE self);
|
26
|
+
typedef VALUE (* backend_unref_t)(VALUE self);
|
27
|
+
typedef VALUE (* backend_wait_event_t)(VALUE self, VALUE raise_on_exception);
|
28
|
+
typedef VALUE (* backend_wakeup_t)(VALUE self);
|
29
|
+
|
30
|
+
typedef struct backend_interface {
|
31
|
+
backend_pending_count_t pending_count;
|
32
|
+
backend_poll_t poll;
|
33
|
+
backend_ref_t ref;
|
34
|
+
backend_ref_count_t ref_count;
|
35
|
+
backend_reset_ref_count_t reset_ref_count;
|
36
|
+
backend_unref_t unref;
|
37
|
+
backend_wait_event_t wait_event;
|
38
|
+
backend_wakeup_t wakeup;
|
39
|
+
} backend_interface_t;
|
40
|
+
|
41
|
+
#endif /* BACKEND_H */
|
data/ext/polyphony/event.c
CHANGED
@@ -64,13 +64,13 @@ VALUE Event_await(VALUE self) {
|
|
64
64
|
if (event->waiting_fiber != Qnil)
|
65
65
|
rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
|
66
66
|
|
67
|
-
VALUE
|
67
|
+
VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
68
68
|
event->waiting_fiber = rb_fiber_current();
|
69
|
-
VALUE switchpoint_result =
|
69
|
+
VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
|
70
70
|
event->waiting_fiber = Qnil;
|
71
71
|
|
72
72
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
73
|
-
RB_GC_GUARD(
|
73
|
+
RB_GC_GUARD(backend);
|
74
74
|
RB_GC_GUARD(switchpoint_result);
|
75
75
|
|
76
76
|
return switchpoint_result;
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -11,155 +11,155 @@
|
|
11
11
|
|
12
12
|
VALUE cTCPSocket;
|
13
13
|
|
14
|
-
typedef struct
|
14
|
+
typedef struct LibevBackend_t {
|
15
15
|
struct ev_loop *ev_loop;
|
16
16
|
struct ev_async break_async;
|
17
17
|
int running;
|
18
18
|
int ref_count;
|
19
19
|
int run_no_wait_count;
|
20
|
-
}
|
20
|
+
} LibevBackend_t;
|
21
21
|
|
22
|
-
static size_t
|
23
|
-
return sizeof(
|
22
|
+
static size_t LibevBackend_size(const void *ptr) {
|
23
|
+
return sizeof(LibevBackend_t);
|
24
24
|
}
|
25
25
|
|
26
|
-
static const rb_data_type_t
|
26
|
+
static const rb_data_type_t LibevBackend_type = {
|
27
27
|
"Libev",
|
28
|
-
{0, 0,
|
28
|
+
{0, 0, LibevBackend_size,},
|
29
29
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
30
30
|
};
|
31
31
|
|
32
|
-
static VALUE
|
33
|
-
|
32
|
+
static VALUE LibevBackend_allocate(VALUE klass) {
|
33
|
+
LibevBackend_t *backend = ALLOC(LibevBackend_t);
|
34
34
|
|
35
|
-
return TypedData_Wrap_Struct(klass, &
|
35
|
+
return TypedData_Wrap_Struct(klass, &LibevBackend_type, backend);
|
36
36
|
}
|
37
37
|
|
38
|
-
#define
|
39
|
-
TypedData_Get_Struct((obj),
|
38
|
+
#define GetLibevBackend(obj, backend) \
|
39
|
+
TypedData_Get_Struct((obj), LibevBackend_t, &LibevBackend_type, (backend))
|
40
40
|
|
41
41
|
void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
|
42
42
|
// This callback does nothing, the break async is used solely for breaking out
|
43
43
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
44
44
|
}
|
45
45
|
|
46
|
-
static VALUE
|
47
|
-
|
46
|
+
static VALUE LibevBackend_initialize(VALUE self) {
|
47
|
+
LibevBackend_t *backend;
|
48
48
|
VALUE thread = rb_thread_current();
|
49
49
|
int is_main_thread = (thread == rb_thread_main());
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
GetLibevBackend(self, backend);
|
52
|
+
backend->ev_loop = is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
53
53
|
|
54
|
-
ev_async_init(&
|
55
|
-
ev_async_start(
|
56
|
-
ev_unref(
|
54
|
+
ev_async_init(&backend->break_async, break_async_callback);
|
55
|
+
ev_async_start(backend->ev_loop, &backend->break_async);
|
56
|
+
ev_unref(backend->ev_loop); // don't count the break_async watcher
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
backend->running = 0;
|
59
|
+
backend->ref_count = 0;
|
60
|
+
backend->run_no_wait_count = 0;
|
61
61
|
|
62
62
|
return Qnil;
|
63
63
|
}
|
64
64
|
|
65
|
-
VALUE
|
66
|
-
|
67
|
-
|
65
|
+
VALUE LibevBackend_finalize(VALUE self) {
|
66
|
+
LibevBackend_t *backend;
|
67
|
+
GetLibevBackend(self, backend);
|
68
68
|
|
69
|
-
ev_async_stop(
|
69
|
+
ev_async_stop(backend->ev_loop, &backend->break_async);
|
70
70
|
|
71
|
-
if (!ev_is_default_loop(
|
71
|
+
if (!ev_is_default_loop(backend->ev_loop)) ev_loop_destroy(backend->ev_loop);
|
72
72
|
|
73
73
|
return self;
|
74
74
|
}
|
75
75
|
|
76
|
-
VALUE
|
77
|
-
|
78
|
-
|
76
|
+
VALUE LibevBackend_post_fork(VALUE self) {
|
77
|
+
LibevBackend_t *backend;
|
78
|
+
GetLibevBackend(self, backend);
|
79
79
|
|
80
80
|
// After fork there may be some watchers still active left over from the
|
81
81
|
// parent, so we destroy the loop, even if it's the default one, then use the
|
82
82
|
// default one, as post_fork is called only from the main thread of the forked
|
83
83
|
// process. That way we don't need to call ev_loop_fork, since the loop is
|
84
84
|
// always a fresh one.
|
85
|
-
ev_loop_destroy(
|
86
|
-
|
85
|
+
ev_loop_destroy(backend->ev_loop);
|
86
|
+
backend->ev_loop = EV_DEFAULT;
|
87
87
|
|
88
88
|
return self;
|
89
89
|
}
|
90
90
|
|
91
|
-
VALUE
|
92
|
-
|
93
|
-
|
91
|
+
VALUE LibevBackend_ref(VALUE self) {
|
92
|
+
LibevBackend_t *backend;
|
93
|
+
GetLibevBackend(self, backend);
|
94
94
|
|
95
|
-
|
95
|
+
backend->ref_count++;
|
96
96
|
return self;
|
97
97
|
}
|
98
98
|
|
99
|
-
VALUE
|
100
|
-
|
101
|
-
|
99
|
+
VALUE LibevBackend_unref(VALUE self) {
|
100
|
+
LibevBackend_t *backend;
|
101
|
+
GetLibevBackend(self, backend);
|
102
102
|
|
103
|
-
|
103
|
+
backend->ref_count--;
|
104
104
|
return self;
|
105
105
|
}
|
106
106
|
|
107
|
-
int
|
108
|
-
|
109
|
-
|
107
|
+
int LibevBackend_ref_count(VALUE self) {
|
108
|
+
LibevBackend_t *backend;
|
109
|
+
GetLibevBackend(self, backend);
|
110
110
|
|
111
|
-
return
|
111
|
+
return backend->ref_count;
|
112
112
|
}
|
113
113
|
|
114
|
-
void
|
115
|
-
|
116
|
-
|
114
|
+
void LibevBackend_reset_ref_count(VALUE self) {
|
115
|
+
LibevBackend_t *backend;
|
116
|
+
GetLibevBackend(self, backend);
|
117
117
|
|
118
|
-
|
118
|
+
backend->ref_count = 0;
|
119
119
|
}
|
120
120
|
|
121
|
-
VALUE
|
121
|
+
VALUE LibevBackend_pending_count(VALUE self) {
|
122
122
|
int count;
|
123
|
-
|
124
|
-
|
125
|
-
count = ev_pending_count(
|
123
|
+
LibevBackend_t *backend;
|
124
|
+
GetLibevBackend(self, backend);
|
125
|
+
count = ev_pending_count(backend->ev_loop);
|
126
126
|
return INT2NUM(count);
|
127
127
|
}
|
128
128
|
|
129
|
-
VALUE
|
129
|
+
VALUE LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue) {
|
130
130
|
int is_nowait = nowait == Qtrue;
|
131
|
-
|
132
|
-
|
131
|
+
LibevBackend_t *backend;
|
132
|
+
GetLibevBackend(self, backend);
|
133
133
|
|
134
134
|
if (is_nowait) {
|
135
135
|
long runnable_count = Queue_len(queue);
|
136
|
-
|
137
|
-
if (
|
136
|
+
backend->run_no_wait_count++;
|
137
|
+
if (backend->run_no_wait_count < runnable_count || backend->run_no_wait_count < 10)
|
138
138
|
return self;
|
139
139
|
}
|
140
140
|
|
141
|
-
|
141
|
+
backend->run_no_wait_count = 0;
|
142
142
|
|
143
143
|
COND_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
|
144
|
-
|
145
|
-
ev_run(
|
146
|
-
|
144
|
+
backend->running = 1;
|
145
|
+
ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
|
146
|
+
backend->running = 0;
|
147
147
|
COND_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
|
148
148
|
|
149
149
|
return self;
|
150
150
|
}
|
151
151
|
|
152
|
-
VALUE
|
153
|
-
|
154
|
-
|
152
|
+
VALUE LibevBackend_wakeup(VALUE self) {
|
153
|
+
LibevBackend_t *backend;
|
154
|
+
GetLibevBackend(self, backend);
|
155
155
|
|
156
|
-
if (
|
156
|
+
if (backend->running) {
|
157
157
|
// Since the loop will run until at least one event has occurred, we signal
|
158
158
|
// the selector's associated async watcher, which will cause the ev loop to
|
159
159
|
// return. In contrast to using `ev_break` to break out of the loop, which
|
160
160
|
// should be called from the same thread (from within the ev_loop), using an
|
161
161
|
// `ev_async` allows us to interrupt the event loop across threads.
|
162
|
-
ev_async_send(
|
162
|
+
ev_async_send(backend->ev_loop, &backend->break_async);
|
163
163
|
return Qtrue;
|
164
164
|
}
|
165
165
|
|
@@ -238,37 +238,37 @@ struct libev_io {
|
|
238
238
|
VALUE fiber;
|
239
239
|
};
|
240
240
|
|
241
|
-
void
|
241
|
+
void LibevBackend_io_callback(EV_P_ ev_io *w, int revents)
|
242
242
|
{
|
243
243
|
struct libev_io *watcher = (struct libev_io *)w;
|
244
244
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
245
245
|
}
|
246
246
|
|
247
|
-
inline VALUE libev_await(
|
247
|
+
inline VALUE libev_await(LibevBackend_t *backend) {
|
248
248
|
VALUE ret;
|
249
|
-
|
249
|
+
backend->ref_count++;
|
250
250
|
ret = Thread_switch_fiber(rb_thread_current());
|
251
|
-
|
251
|
+
backend->ref_count--;
|
252
252
|
RB_GC_GUARD(ret);
|
253
253
|
return ret;
|
254
254
|
}
|
255
255
|
|
256
|
-
VALUE
|
257
|
-
|
258
|
-
|
259
|
-
return libev_await(
|
256
|
+
VALUE libev_backend_await(VALUE self) {
|
257
|
+
LibevBackend_t *backend;
|
258
|
+
GetLibevBackend(self, backend);
|
259
|
+
return libev_await(backend);
|
260
260
|
}
|
261
261
|
|
262
|
-
VALUE libev_io_wait(
|
262
|
+
VALUE libev_io_wait(LibevBackend_t *backend, struct libev_io *watcher, rb_io_t *fptr, int flags) {
|
263
263
|
VALUE switchpoint_result;
|
264
264
|
|
265
265
|
if (watcher->fiber == Qnil) {
|
266
266
|
watcher->fiber = rb_fiber_current();
|
267
|
-
ev_io_init(&watcher->io,
|
267
|
+
ev_io_init(&watcher->io, LibevBackend_io_callback, fptr->fd, flags);
|
268
268
|
}
|
269
|
-
ev_io_start(
|
270
|
-
switchpoint_result = libev_await(
|
271
|
-
ev_io_stop(
|
269
|
+
ev_io_start(backend->ev_loop, &watcher->io);
|
270
|
+
switchpoint_result = libev_await(backend);
|
271
|
+
ev_io_stop(backend->ev_loop, &watcher->io);
|
272
272
|
|
273
273
|
RB_GC_GUARD(switchpoint_result);
|
274
274
|
return switchpoint_result;
|
@@ -304,8 +304,8 @@ inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
|
304
304
|
return;
|
305
305
|
}
|
306
306
|
|
307
|
-
VALUE
|
308
|
-
|
307
|
+
VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
308
|
+
LibevBackend_t *backend;
|
309
309
|
struct libev_io watcher;
|
310
310
|
rb_io_t *fptr;
|
311
311
|
long dynamic_len = length == Qnil;
|
@@ -317,7 +317,7 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
317
317
|
int read_to_eof = RTEST(to_eof);
|
318
318
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
319
319
|
|
320
|
-
|
320
|
+
GetLibevBackend(self, backend);
|
321
321
|
if (underlying_io != Qnil) io = underlying_io;
|
322
322
|
GetOpenFile(io, fptr);
|
323
323
|
rb_io_check_byte_readable(fptr);
|
@@ -341,7 +341,7 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
341
341
|
int e = errno;
|
342
342
|
if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
|
343
343
|
|
344
|
-
switchpoint_result = libev_io_wait(
|
344
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
|
345
345
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
346
346
|
}
|
347
347
|
else {
|
@@ -377,7 +377,7 @@ error:
|
|
377
377
|
return RAISE_EXCEPTION(switchpoint_result);
|
378
378
|
}
|
379
379
|
|
380
|
-
VALUE
|
380
|
+
VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
|
381
381
|
|
382
382
|
#define PREPARE_STR() { \
|
383
383
|
str = Qnil; \
|
@@ -394,7 +394,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
394
394
|
PREPARE_STR(); \
|
395
395
|
}
|
396
396
|
|
397
|
-
|
397
|
+
LibevBackend_t *backend;
|
398
398
|
struct libev_io watcher;
|
399
399
|
rb_io_t *fptr;
|
400
400
|
VALUE str;
|
@@ -407,7 +407,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
407
407
|
|
408
408
|
PREPARE_STR();
|
409
409
|
|
410
|
-
|
410
|
+
GetLibevBackend(self, backend);
|
411
411
|
if (underlying_io != Qnil) io = underlying_io;
|
412
412
|
GetOpenFile(io, fptr);
|
413
413
|
rb_io_check_byte_readable(fptr);
|
@@ -429,7 +429,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
429
429
|
int e = errno;
|
430
430
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
431
431
|
|
432
|
-
switchpoint_result = libev_io_wait(
|
432
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
|
433
433
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
434
434
|
}
|
435
435
|
else {
|
@@ -457,8 +457,8 @@ error:
|
|
457
457
|
return RAISE_EXCEPTION(switchpoint_result);
|
458
458
|
}
|
459
459
|
|
460
|
-
VALUE
|
461
|
-
|
460
|
+
VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
|
461
|
+
LibevBackend_t *backend;
|
462
462
|
struct libev_io watcher;
|
463
463
|
rb_io_t *fptr;
|
464
464
|
VALUE switchpoint_result = Qnil;
|
@@ -469,7 +469,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
469
469
|
|
470
470
|
underlying_io = rb_iv_get(io, "@io");
|
471
471
|
if (underlying_io != Qnil) io = underlying_io;
|
472
|
-
|
472
|
+
GetLibevBackend(self, backend);
|
473
473
|
io = rb_io_get_write_io(io);
|
474
474
|
GetOpenFile(io, fptr);
|
475
475
|
watcher.fiber = Qnil;
|
@@ -479,7 +479,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
479
479
|
if (n < 0) {
|
480
480
|
int e = errno;
|
481
481
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
482
|
-
switchpoint_result = libev_io_wait(
|
482
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
|
483
483
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
484
484
|
}
|
485
485
|
else {
|
@@ -501,8 +501,8 @@ error:
|
|
501
501
|
return RAISE_EXCEPTION(switchpoint_result);
|
502
502
|
}
|
503
503
|
|
504
|
-
VALUE
|
505
|
-
|
504
|
+
VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
505
|
+
LibevBackend_t *backend;
|
506
506
|
struct libev_io watcher;
|
507
507
|
rb_io_t *fptr;
|
508
508
|
VALUE switchpoint_result = Qnil;
|
@@ -515,7 +515,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
515
515
|
|
516
516
|
underlying_io = rb_iv_get(io, "@io");
|
517
517
|
if (underlying_io != Qnil) io = underlying_io;
|
518
|
-
|
518
|
+
GetLibevBackend(self, backend);
|
519
519
|
io = rb_io_get_write_io(io);
|
520
520
|
GetOpenFile(io, fptr);
|
521
521
|
watcher.fiber = Qnil;
|
@@ -535,7 +535,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
535
535
|
int e = errno;
|
536
536
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
537
537
|
|
538
|
-
switchpoint_result = libev_io_wait(
|
538
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
|
539
539
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
540
540
|
}
|
541
541
|
else {
|
@@ -571,20 +571,20 @@ error:
|
|
571
571
|
return RAISE_EXCEPTION(switchpoint_result);
|
572
572
|
}
|
573
573
|
|
574
|
-
VALUE
|
574
|
+
VALUE LibevBackend_write_m(int argc, VALUE *argv, VALUE self) {
|
575
575
|
if (argc < 2)
|
576
576
|
// TODO: raise ArgumentError
|
577
577
|
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
578
578
|
|
579
579
|
return (argc == 2) ?
|
580
|
-
|
581
|
-
|
580
|
+
LibevBackend_write(self, argv[0], argv[1]) :
|
581
|
+
LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
|
582
582
|
}
|
583
583
|
|
584
584
|
///////////////////////////////////////////////////////////////////////////
|
585
585
|
|
586
|
-
VALUE
|
587
|
-
|
586
|
+
VALUE LibevBackend_accept(VALUE self, VALUE sock) {
|
587
|
+
LibevBackend_t *backend;
|
588
588
|
struct libev_io watcher;
|
589
589
|
rb_io_t *fptr;
|
590
590
|
int fd;
|
@@ -594,7 +594,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
594
594
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
595
595
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
596
596
|
|
597
|
-
|
597
|
+
GetLibevBackend(self, backend);
|
598
598
|
GetOpenFile(sock, fptr);
|
599
599
|
io_set_nonblock(fptr, sock);
|
600
600
|
watcher.fiber = Qnil;
|
@@ -604,7 +604,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
604
604
|
int e = errno;
|
605
605
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
606
606
|
|
607
|
-
switchpoint_result = libev_io_wait(
|
607
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
|
608
608
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
609
609
|
}
|
610
610
|
else {
|
@@ -637,8 +637,8 @@ error:
|
|
637
637
|
return RAISE_EXCEPTION(switchpoint_result);
|
638
638
|
}
|
639
639
|
|
640
|
-
VALUE
|
641
|
-
|
640
|
+
VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
|
641
|
+
LibevBackend_t *backend;
|
642
642
|
struct libev_io watcher;
|
643
643
|
rb_io_t *fptr;
|
644
644
|
int fd;
|
@@ -649,7 +649,7 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
649
649
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
650
650
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
651
651
|
|
652
|
-
|
652
|
+
GetLibevBackend(self, backend);
|
653
653
|
GetOpenFile(sock, fptr);
|
654
654
|
io_set_nonblock(fptr, sock);
|
655
655
|
watcher.fiber = Qnil;
|
@@ -660,7 +660,7 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
660
660
|
int e = errno;
|
661
661
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
662
662
|
|
663
|
-
switchpoint_result = libev_io_wait(
|
663
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
|
664
664
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
665
665
|
}
|
666
666
|
else {
|
@@ -693,8 +693,8 @@ error:
|
|
693
693
|
return RAISE_EXCEPTION(switchpoint_result);
|
694
694
|
}
|
695
695
|
|
696
|
-
VALUE
|
697
|
-
|
696
|
+
VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
697
|
+
LibevBackend_t *backend;
|
698
698
|
struct libev_io watcher;
|
699
699
|
rb_io_t *fptr;
|
700
700
|
struct sockaddr_in addr;
|
@@ -703,7 +703,7 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
703
703
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
704
704
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
705
705
|
|
706
|
-
|
706
|
+
GetLibevBackend(self, backend);
|
707
707
|
GetOpenFile(sock, fptr);
|
708
708
|
io_set_nonblock(fptr, sock);
|
709
709
|
watcher.fiber = Qnil;
|
@@ -716,7 +716,7 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
716
716
|
if (result < 0) {
|
717
717
|
int e = errno;
|
718
718
|
if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
|
719
|
-
switchpoint_result = libev_io_wait(
|
719
|
+
switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
|
720
720
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
721
721
|
}
|
722
722
|
else {
|
@@ -729,31 +729,31 @@ error:
|
|
729
729
|
return RAISE_EXCEPTION(switchpoint_result);
|
730
730
|
}
|
731
731
|
|
732
|
-
VALUE libev_wait_fd(
|
732
|
+
VALUE libev_wait_fd(LibevBackend_t *backend, int fd, int events, int raise_exception) {
|
733
733
|
struct libev_io watcher;
|
734
734
|
VALUE switchpoint_result = Qnil;
|
735
735
|
|
736
736
|
watcher.fiber = rb_fiber_current();
|
737
|
-
ev_io_init(&watcher.io,
|
738
|
-
ev_io_start(
|
739
|
-
switchpoint_result = libev_await(
|
740
|
-
ev_io_stop(
|
737
|
+
ev_io_init(&watcher.io, LibevBackend_io_callback, fd, events);
|
738
|
+
ev_io_start(backend->ev_loop, &watcher.io);
|
739
|
+
switchpoint_result = libev_await(backend);
|
740
|
+
ev_io_stop(backend->ev_loop, &watcher.io);
|
741
741
|
|
742
742
|
if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
|
743
743
|
RB_GC_GUARD(switchpoint_result);
|
744
744
|
return switchpoint_result;
|
745
745
|
}
|
746
746
|
|
747
|
-
VALUE
|
748
|
-
|
747
|
+
VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
|
748
|
+
LibevBackend_t *backend;
|
749
749
|
rb_io_t *fptr;
|
750
750
|
int events = RTEST(write) ? EV_WRITE : EV_READ;
|
751
751
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
752
752
|
if (underlying_io != Qnil) io = underlying_io;
|
753
|
-
|
753
|
+
GetLibevBackend(self, backend);
|
754
754
|
GetOpenFile(io, fptr);
|
755
755
|
|
756
|
-
return libev_wait_fd(
|
756
|
+
return libev_wait_fd(backend, fptr->fd, events, 1);
|
757
757
|
}
|
758
758
|
|
759
759
|
struct libev_timer {
|
@@ -761,25 +761,25 @@ struct libev_timer {
|
|
761
761
|
VALUE fiber;
|
762
762
|
};
|
763
763
|
|
764
|
-
void
|
764
|
+
void LibevBackend_timer_callback(EV_P_ ev_timer *w, int revents)
|
765
765
|
{
|
766
766
|
struct libev_timer *watcher = (struct libev_timer *)w;
|
767
767
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
768
768
|
}
|
769
769
|
|
770
|
-
VALUE
|
771
|
-
|
770
|
+
VALUE LibevBackend_sleep(VALUE self, VALUE duration) {
|
771
|
+
LibevBackend_t *backend;
|
772
772
|
struct libev_timer watcher;
|
773
773
|
VALUE switchpoint_result = Qnil;
|
774
774
|
|
775
|
-
|
775
|
+
GetLibevBackend(self, backend);
|
776
776
|
watcher.fiber = rb_fiber_current();
|
777
|
-
ev_timer_init(&watcher.timer,
|
778
|
-
ev_timer_start(
|
777
|
+
ev_timer_init(&watcher.timer, LibevBackend_timer_callback, NUM2DBL(duration), 0.);
|
778
|
+
ev_timer_start(backend->ev_loop, &watcher.timer);
|
779
779
|
|
780
|
-
switchpoint_result = libev_await(
|
780
|
+
switchpoint_result = libev_await(backend);
|
781
781
|
|
782
|
-
ev_timer_stop(
|
782
|
+
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
783
783
|
|
784
784
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
785
785
|
RB_GC_GUARD(watcher.fiber);
|
@@ -792,7 +792,7 @@ struct libev_child {
|
|
792
792
|
VALUE fiber;
|
793
793
|
};
|
794
794
|
|
795
|
-
void
|
795
|
+
void LibevBackend_child_callback(EV_P_ ev_child *w, int revents)
|
796
796
|
{
|
797
797
|
struct libev_child *watcher = (struct libev_child *)w;
|
798
798
|
int exit_status = w->rstatus >> 8; // weird, why should we do this?
|
@@ -802,18 +802,18 @@ void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
|
|
802
802
|
Fiber_make_runnable(watcher->fiber, status);
|
803
803
|
}
|
804
804
|
|
805
|
-
VALUE
|
806
|
-
|
805
|
+
VALUE LibevBackend_waitpid(VALUE self, VALUE pid) {
|
806
|
+
LibevBackend_t *backend;
|
807
807
|
struct libev_child watcher;
|
808
808
|
VALUE switchpoint_result = Qnil;
|
809
|
-
|
809
|
+
GetLibevBackend(self, backend);
|
810
810
|
|
811
811
|
watcher.fiber = rb_fiber_current();
|
812
|
-
ev_child_init(&watcher.child,
|
813
|
-
ev_child_start(
|
812
|
+
ev_child_init(&watcher.child, LibevBackend_child_callback, NUM2INT(pid), 0);
|
813
|
+
ev_child_start(backend->ev_loop, &watcher.child);
|
814
814
|
|
815
|
-
switchpoint_result = libev_await(
|
816
|
-
ev_child_stop(
|
815
|
+
switchpoint_result = libev_await(backend);
|
816
|
+
ev_child_stop(backend->ev_loop, &watcher.child);
|
817
817
|
|
818
818
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
819
819
|
RB_GC_GUARD(watcher.fiber);
|
@@ -821,68 +821,68 @@ VALUE LibevAgent_waitpid(VALUE self, VALUE pid) {
|
|
821
821
|
return switchpoint_result;
|
822
822
|
}
|
823
823
|
|
824
|
-
struct ev_loop *
|
825
|
-
|
826
|
-
|
827
|
-
return
|
824
|
+
struct ev_loop *LibevBackend_ev_loop(VALUE self) {
|
825
|
+
LibevBackend_t *backend;
|
826
|
+
GetLibevBackend(self, backend);
|
827
|
+
return backend->ev_loop;
|
828
828
|
}
|
829
829
|
|
830
|
-
void
|
830
|
+
void LibevBackend_async_callback(EV_P_ ev_async *w, int revents) { }
|
831
831
|
|
832
|
-
VALUE
|
833
|
-
|
832
|
+
VALUE LibevBackend_wait_event(VALUE self, VALUE raise) {
|
833
|
+
LibevBackend_t *backend;
|
834
834
|
VALUE switchpoint_result = Qnil;
|
835
|
-
|
835
|
+
GetLibevBackend(self, backend);
|
836
836
|
|
837
837
|
struct ev_async async;
|
838
838
|
|
839
|
-
ev_async_init(&async,
|
840
|
-
ev_async_start(
|
841
|
-
switchpoint_result = libev_await(
|
842
|
-
ev_async_stop(
|
839
|
+
ev_async_init(&async, LibevBackend_async_callback);
|
840
|
+
ev_async_start(backend->ev_loop, &async);
|
841
|
+
switchpoint_result = libev_await(backend);
|
842
|
+
ev_async_stop(backend->ev_loop, &async);
|
843
843
|
|
844
844
|
if (RTEST(raise)) TEST_RESUME_EXCEPTION(switchpoint_result);
|
845
845
|
RB_GC_GUARD(switchpoint_result);
|
846
846
|
return switchpoint_result;
|
847
847
|
}
|
848
848
|
|
849
|
-
void
|
849
|
+
void Init_LibevBackend() {
|
850
850
|
rb_require("socket");
|
851
851
|
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
852
852
|
|
853
|
-
VALUE
|
854
|
-
rb_define_alloc_func(
|
853
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
854
|
+
rb_define_alloc_func(cBackend, LibevBackend_allocate);
|
855
855
|
|
856
|
-
rb_define_method(
|
857
|
-
rb_define_method(
|
858
|
-
rb_define_method(
|
859
|
-
rb_define_method(
|
856
|
+
rb_define_method(cBackend, "initialize", LibevBackend_initialize, 0);
|
857
|
+
rb_define_method(cBackend, "finalize", LibevBackend_finalize, 0);
|
858
|
+
rb_define_method(cBackend, "post_fork", LibevBackend_post_fork, 0);
|
859
|
+
rb_define_method(cBackend, "pending_count", LibevBackend_pending_count, 0);
|
860
860
|
|
861
|
-
rb_define_method(
|
862
|
-
rb_define_method(
|
861
|
+
rb_define_method(cBackend, "ref", LibevBackend_ref, 0);
|
862
|
+
rb_define_method(cBackend, "unref", LibevBackend_unref, 0);
|
863
863
|
|
864
|
-
rb_define_method(
|
865
|
-
rb_define_method(
|
864
|
+
rb_define_method(cBackend, "poll", LibevBackend_poll, 3);
|
865
|
+
rb_define_method(cBackend, "break", LibevBackend_wakeup, 0);
|
866
866
|
|
867
|
-
rb_define_method(
|
868
|
-
rb_define_method(
|
869
|
-
rb_define_method(
|
870
|
-
rb_define_method(
|
871
|
-
rb_define_method(
|
872
|
-
rb_define_method(
|
873
|
-
rb_define_method(
|
874
|
-
rb_define_method(
|
875
|
-
rb_define_method(
|
876
|
-
rb_define_method(
|
867
|
+
rb_define_method(cBackend, "read", LibevBackend_read, 4);
|
868
|
+
rb_define_method(cBackend, "read_loop", LibevBackend_read_loop, 1);
|
869
|
+
rb_define_method(cBackend, "write", LibevBackend_write_m, -1);
|
870
|
+
rb_define_method(cBackend, "accept", LibevBackend_accept, 1);
|
871
|
+
rb_define_method(cBackend, "accept_loop", LibevBackend_accept_loop, 1);
|
872
|
+
rb_define_method(cBackend, "connect", LibevBackend_connect, 3);
|
873
|
+
rb_define_method(cBackend, "wait_io", LibevBackend_wait_io, 2);
|
874
|
+
rb_define_method(cBackend, "sleep", LibevBackend_sleep, 1);
|
875
|
+
rb_define_method(cBackend, "waitpid", LibevBackend_waitpid, 1);
|
876
|
+
rb_define_method(cBackend, "wait_event", LibevBackend_wait_event, 1);
|
877
877
|
|
878
878
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
879
879
|
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
880
|
+
__BACKEND__.pending_count = LibevBackend_pending_count;
|
881
|
+
__BACKEND__.poll = LibevBackend_poll;
|
882
|
+
__BACKEND__.ref = LibevBackend_ref;
|
883
|
+
__BACKEND__.ref_count = LibevBackend_ref_count;
|
884
|
+
__BACKEND__.reset_ref_count = LibevBackend_reset_ref_count;
|
885
|
+
__BACKEND__.unref = LibevBackend_unref;
|
886
|
+
__BACKEND__.wait_event = LibevBackend_wait_event;
|
887
|
+
__BACKEND__.wakeup = LibevBackend_wakeup;
|
888
888
|
}
|