polyphony 0.45.5 → 0.46.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/.github/workflows/test.yml +2 -0
- data/.gitmodules +0 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/TODO.md +4 -4
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
- data/ext/liburing/liburing.h +585 -0
- data/ext/liburing/liburing/README.md +4 -0
- data/ext/liburing/liburing/barrier.h +73 -0
- data/ext/liburing/liburing/compat.h +15 -0
- data/ext/liburing/liburing/io_uring.h +343 -0
- data/ext/liburing/queue.c +333 -0
- data/ext/liburing/register.c +187 -0
- data/ext/liburing/setup.c +210 -0
- data/ext/liburing/syscall.c +54 -0
- data/ext/liburing/syscall.h +18 -0
- data/ext/polyphony/backend.h +0 -14
- data/ext/polyphony/backend_common.h +109 -0
- data/ext/polyphony/backend_io_uring.c +884 -0
- data/ext/polyphony/backend_io_uring_context.c +73 -0
- data/ext/polyphony/backend_io_uring_context.h +52 -0
- data/ext/polyphony/{libev_backend.c → backend_libev.c} +202 -294
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +31 -13
- data/ext/polyphony/fiber.c +29 -22
- data/ext/polyphony/libev.c +4 -0
- data/ext/polyphony/libev.h +8 -2
- data/ext/polyphony/liburing.c +8 -0
- data/ext/polyphony/playground.c +51 -0
- data/ext/polyphony/polyphony.c +5 -5
- data/ext/polyphony/polyphony.h +16 -12
- data/ext/polyphony/polyphony_ext.c +10 -4
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/thread.c +11 -9
- data/lib/polyphony/adapters/trace.rb +2 -2
- data/lib/polyphony/core/global_api.rb +1 -4
- data/lib/polyphony/extensions/debug.rb +13 -0
- data/lib/polyphony/extensions/fiber.rb +2 -2
- data/lib/polyphony/extensions/socket.rb +59 -10
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +36 -4
- data/test/io_uring_test.rb +55 -0
- data/test/stress.rb +5 -2
- data/test/test_backend.rb +4 -6
- data/test/test_ext.rb +1 -2
- data/test/test_fiber.rb +22 -16
- data/test/test_global_api.rb +33 -35
- data/test/test_throttler.rb +3 -6
- data/test/test_trace.rb +7 -5
- metadata +22 -3
@@ -0,0 +1,73 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "polyphony.h"
|
4
|
+
#include "backend_io_uring_context.h"
|
5
|
+
|
6
|
+
const char *op_type_to_str(enum op_type type) {
|
7
|
+
switch (type) {
|
8
|
+
case OP_READ: return "READ";
|
9
|
+
case OP_WRITEV: return "WRITEV";
|
10
|
+
case OP_WRITE: return "WRITE";
|
11
|
+
case OP_RECV: return "RECV";
|
12
|
+
case OP_SEND: return "SEND";
|
13
|
+
case OP_TIMEOUT: return "TIMEOUT";
|
14
|
+
case OP_POLL: return "POLL";
|
15
|
+
case OP_ACCEPT: return "ACCEPT";
|
16
|
+
case OP_CONNECT: return "CONNECT";
|
17
|
+
default: return "";
|
18
|
+
};
|
19
|
+
}
|
20
|
+
|
21
|
+
void context_store_initialize(op_context_store_t *store) {
|
22
|
+
store->last_id = 0;
|
23
|
+
store->available = NULL;
|
24
|
+
store->taken = NULL;
|
25
|
+
}
|
26
|
+
|
27
|
+
inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type) {
|
28
|
+
op_context_t *ctx = store->available;
|
29
|
+
if (ctx) {
|
30
|
+
if (ctx->next) ctx->next->prev = NULL;
|
31
|
+
store->available = ctx->next;
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
ctx = malloc(sizeof(op_context_t));
|
35
|
+
}
|
36
|
+
ctx->id = (++store->last_id);
|
37
|
+
|
38
|
+
ctx->prev = NULL;
|
39
|
+
ctx->next = store->taken;
|
40
|
+
if (store->taken) store->taken->prev = ctx;
|
41
|
+
store->taken = ctx;
|
42
|
+
|
43
|
+
ctx->type = type;
|
44
|
+
ctx->fiber = rb_fiber_current();
|
45
|
+
ctx->completed = 0;
|
46
|
+
ctx->result = 0;
|
47
|
+
|
48
|
+
return ctx;
|
49
|
+
}
|
50
|
+
|
51
|
+
inline void context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
52
|
+
if (ctx->next) ctx->next->prev = ctx->prev;
|
53
|
+
if (ctx->prev) ctx->prev->next = ctx->next;
|
54
|
+
if (store->taken == ctx) store->taken = ctx->next;
|
55
|
+
|
56
|
+
ctx->prev = NULL;
|
57
|
+
ctx->next = store->available;
|
58
|
+
if (ctx->next) ctx->next->prev = ctx;
|
59
|
+
store->available = ctx;
|
60
|
+
}
|
61
|
+
|
62
|
+
void context_store_free(op_context_store_t *store) {
|
63
|
+
while (store->available) {
|
64
|
+
op_context_t *next = store->available->next;
|
65
|
+
free(store->available);
|
66
|
+
store->available = next;
|
67
|
+
}
|
68
|
+
while (store->taken) {
|
69
|
+
op_context_t *next = store->taken->next;
|
70
|
+
free(store->taken);
|
71
|
+
store->taken = next;
|
72
|
+
}
|
73
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#ifndef BACKEND_IO_URING_CONTEXT_H
|
2
|
+
#define BACKEND_IO_URING_CONTEXT_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
enum op_type {
|
7
|
+
OP_NONE,
|
8
|
+
OP_READ,
|
9
|
+
OP_WRITEV,
|
10
|
+
OP_WRITE,
|
11
|
+
OP_RECV,
|
12
|
+
OP_SEND,
|
13
|
+
OP_TIMEOUT,
|
14
|
+
OP_POLL,
|
15
|
+
OP_ACCEPT,
|
16
|
+
OP_CONNECT
|
17
|
+
};
|
18
|
+
|
19
|
+
typedef struct op_context {
|
20
|
+
struct op_context *prev;
|
21
|
+
struct op_context *next;
|
22
|
+
enum op_type type: 16;
|
23
|
+
int completed : 16;
|
24
|
+
int id;
|
25
|
+
int result;
|
26
|
+
VALUE fiber;
|
27
|
+
} op_context_t;
|
28
|
+
|
29
|
+
typedef struct op_context_store {
|
30
|
+
int last_id;
|
31
|
+
op_context_t *available;
|
32
|
+
op_context_t *taken;
|
33
|
+
} op_context_store_t;
|
34
|
+
|
35
|
+
const char *op_type_to_str(enum op_type type);
|
36
|
+
|
37
|
+
void context_store_initialize(op_context_store_t *store);
|
38
|
+
op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type);
|
39
|
+
void context_store_release(op_context_store_t *store, op_context_t *ctx);
|
40
|
+
void context_store_free(op_context_store_t *store);
|
41
|
+
|
42
|
+
#define OP_CONTEXT_ACQUIRE(store, op_type) context_store_acquire(store, op_type)
|
43
|
+
#define OP_CONTEXT_RELEASE(store, ctx) { \
|
44
|
+
if (ctx->completed) {\
|
45
|
+
context_store_release(store, ctx); \
|
46
|
+
} \
|
47
|
+
else { \
|
48
|
+
ctx->completed = 1; \
|
49
|
+
} \
|
50
|
+
}
|
51
|
+
|
52
|
+
#endif /* BACKEND_IO_URING_CONTEXT_H */
|
@@ -1,3 +1,5 @@
|
|
1
|
+
#ifdef POLYPHONY_BACKEND_LIBEV
|
2
|
+
|
1
3
|
#include <netdb.h>
|
2
4
|
#include <sys/socket.h>
|
3
5
|
#include <sys/uio.h>
|
@@ -8,47 +10,73 @@
|
|
8
10
|
|
9
11
|
#include "polyphony.h"
|
10
12
|
#include "../libev/ev.h"
|
13
|
+
#include "ruby/io.h"
|
11
14
|
|
12
15
|
VALUE cTCPSocket;
|
16
|
+
VALUE SYM_libev;
|
17
|
+
|
18
|
+
ID ID_ivar_is_nonblocking;
|
19
|
+
|
20
|
+
// Since we need to ensure that fd's are non-blocking before every I/O
|
21
|
+
// operation, here we improve upon Ruby's rb_io_set_nonblock by caching the
|
22
|
+
// "nonblock" state in an instance variable. Calling rb_ivar_get on every read
|
23
|
+
// is still much cheaper than doing a fcntl syscall on every read! Preliminary
|
24
|
+
// benchmarks (with a "hello world" HTTP server) show throughput is improved
|
25
|
+
// by 10-13%.
|
26
|
+
inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
27
|
+
VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
|
28
|
+
if (is_nonblocking == Qtrue) return;
|
29
|
+
|
30
|
+
rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
|
31
|
+
|
32
|
+
#ifdef _WIN32
|
33
|
+
rb_w32_set_nonblock(fptr->fd);
|
34
|
+
#elif defined(F_GETFL)
|
35
|
+
int oflags = fcntl(fptr->fd, F_GETFL);
|
36
|
+
if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
|
37
|
+
oflags |= O_NONBLOCK;
|
38
|
+
fcntl(fptr->fd, F_SETFL, oflags);
|
39
|
+
#endif
|
40
|
+
}
|
13
41
|
|
14
|
-
typedef struct
|
42
|
+
typedef struct Backend_t {
|
15
43
|
struct ev_loop *ev_loop;
|
16
44
|
struct ev_async break_async;
|
17
45
|
int running;
|
18
46
|
int ref_count;
|
19
47
|
int run_no_wait_count;
|
20
|
-
}
|
48
|
+
} Backend_t;
|
21
49
|
|
22
|
-
static size_t
|
23
|
-
return sizeof(
|
50
|
+
static size_t Backend_size(const void *ptr) {
|
51
|
+
return sizeof(Backend_t);
|
24
52
|
}
|
25
53
|
|
26
|
-
static const rb_data_type_t
|
27
|
-
"
|
28
|
-
{0, 0,
|
54
|
+
static const rb_data_type_t Backend_type = {
|
55
|
+
"LibevBackend",
|
56
|
+
{0, 0, Backend_size,},
|
29
57
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
30
58
|
};
|
31
59
|
|
32
|
-
static VALUE
|
33
|
-
|
60
|
+
static VALUE Backend_allocate(VALUE klass) {
|
61
|
+
Backend_t *backend = ALLOC(Backend_t);
|
34
62
|
|
35
|
-
return TypedData_Wrap_Struct(klass, &
|
63
|
+
return TypedData_Wrap_Struct(klass, &Backend_type, backend);
|
36
64
|
}
|
37
65
|
|
38
|
-
#define
|
39
|
-
TypedData_Get_Struct((obj),
|
66
|
+
#define GetBackend(obj, backend) \
|
67
|
+
TypedData_Get_Struct((obj), Backend_t, &Backend_type, (backend))
|
40
68
|
|
41
69
|
void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
|
42
70
|
// This callback does nothing, the break async is used solely for breaking out
|
43
71
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
44
72
|
}
|
45
73
|
|
46
|
-
static VALUE
|
47
|
-
|
74
|
+
static VALUE Backend_initialize(VALUE self) {
|
75
|
+
Backend_t *backend;
|
48
76
|
VALUE thread = rb_thread_current();
|
49
77
|
int is_main_thread = (thread == rb_thread_main());
|
50
78
|
|
51
|
-
|
79
|
+
GetBackend(self, backend);
|
52
80
|
backend->ev_loop = is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
53
81
|
|
54
82
|
ev_async_init(&backend->break_async, break_async_callback);
|
@@ -62,9 +90,9 @@ static VALUE LibevBackend_initialize(VALUE self) {
|
|
62
90
|
return Qnil;
|
63
91
|
}
|
64
92
|
|
65
|
-
VALUE
|
66
|
-
|
67
|
-
|
93
|
+
VALUE Backend_finalize(VALUE self) {
|
94
|
+
Backend_t *backend;
|
95
|
+
GetBackend(self, backend);
|
68
96
|
|
69
97
|
ev_async_stop(backend->ev_loop, &backend->break_async);
|
70
98
|
|
@@ -73,9 +101,9 @@ VALUE LibevBackend_finalize(VALUE self) {
|
|
73
101
|
return self;
|
74
102
|
}
|
75
103
|
|
76
|
-
VALUE
|
77
|
-
|
78
|
-
|
104
|
+
VALUE Backend_post_fork(VALUE self) {
|
105
|
+
Backend_t *backend;
|
106
|
+
GetBackend(self, backend);
|
79
107
|
|
80
108
|
// After fork there may be some watchers still active left over from the
|
81
109
|
// parent, so we destroy the loop, even if it's the default one, then use the
|
@@ -88,48 +116,48 @@ VALUE LibevBackend_post_fork(VALUE self) {
|
|
88
116
|
return self;
|
89
117
|
}
|
90
118
|
|
91
|
-
VALUE
|
92
|
-
|
93
|
-
|
119
|
+
VALUE Backend_ref(VALUE self) {
|
120
|
+
Backend_t *backend;
|
121
|
+
GetBackend(self, backend);
|
94
122
|
|
95
123
|
backend->ref_count++;
|
96
124
|
return self;
|
97
125
|
}
|
98
126
|
|
99
|
-
VALUE
|
100
|
-
|
101
|
-
|
127
|
+
VALUE Backend_unref(VALUE self) {
|
128
|
+
Backend_t *backend;
|
129
|
+
GetBackend(self, backend);
|
102
130
|
|
103
131
|
backend->ref_count--;
|
104
132
|
return self;
|
105
133
|
}
|
106
134
|
|
107
|
-
int
|
108
|
-
|
109
|
-
|
135
|
+
int Backend_ref_count(VALUE self) {
|
136
|
+
Backend_t *backend;
|
137
|
+
GetBackend(self, backend);
|
110
138
|
|
111
139
|
return backend->ref_count;
|
112
140
|
}
|
113
141
|
|
114
|
-
void
|
115
|
-
|
116
|
-
|
142
|
+
void Backend_reset_ref_count(VALUE self) {
|
143
|
+
Backend_t *backend;
|
144
|
+
GetBackend(self, backend);
|
117
145
|
|
118
146
|
backend->ref_count = 0;
|
119
147
|
}
|
120
148
|
|
121
|
-
VALUE
|
149
|
+
VALUE Backend_pending_count(VALUE self) {
|
122
150
|
int count;
|
123
|
-
|
124
|
-
|
151
|
+
Backend_t *backend;
|
152
|
+
GetBackend(self, backend);
|
125
153
|
count = ev_pending_count(backend->ev_loop);
|
126
154
|
return INT2NUM(count);
|
127
155
|
}
|
128
156
|
|
129
|
-
VALUE
|
157
|
+
VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
|
130
158
|
int is_nowait = nowait == Qtrue;
|
131
|
-
|
132
|
-
|
159
|
+
Backend_t *backend;
|
160
|
+
GetBackend(self, backend);
|
133
161
|
|
134
162
|
if (is_nowait) {
|
135
163
|
backend->run_no_wait_count++;
|
@@ -141,18 +169,18 @@ VALUE LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE run
|
|
141
169
|
|
142
170
|
backend->run_no_wait_count = 0;
|
143
171
|
|
144
|
-
COND_TRACE(2,
|
172
|
+
COND_TRACE(2, SYM_fiber_event_poll_enter, current_fiber);
|
145
173
|
backend->running = 1;
|
146
174
|
ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
|
147
175
|
backend->running = 0;
|
148
|
-
COND_TRACE(2,
|
176
|
+
COND_TRACE(2, SYM_fiber_event_poll_leave, current_fiber);
|
149
177
|
|
150
178
|
return self;
|
151
179
|
}
|
152
180
|
|
153
|
-
VALUE
|
154
|
-
|
155
|
-
|
181
|
+
VALUE Backend_wakeup(VALUE self) {
|
182
|
+
Backend_t *backend;
|
183
|
+
GetBackend(self, backend);
|
156
184
|
|
157
185
|
if (backend->running) {
|
158
186
|
// Since the loop will run until at least one event has occurred, we signal
|
@@ -167,152 +195,51 @@ VALUE LibevBackend_wakeup(VALUE self) {
|
|
167
195
|
return Qnil;
|
168
196
|
}
|
169
197
|
|
170
|
-
#include "polyphony.h"
|
171
198
|
#include "../libev/ev.h"
|
172
199
|
|
173
|
-
|
174
|
-
//////////////////////////////////////////////////////////////////////
|
175
|
-
// the following is copied verbatim from the Ruby source code (io.c)
|
176
|
-
struct io_internal_read_struct {
|
177
|
-
int fd;
|
178
|
-
int nonblock;
|
179
|
-
void *buf;
|
180
|
-
size_t capa;
|
181
|
-
};
|
182
|
-
|
183
|
-
#define StringValue(v) rb_string_value(&(v))
|
184
|
-
|
185
|
-
int io_setstrbuf(VALUE *str, long len) {
|
186
|
-
#ifdef _WIN32
|
187
|
-
len = (len + 1) & ~1L; /* round up for wide char */
|
188
|
-
#endif
|
189
|
-
if (NIL_P(*str)) {
|
190
|
-
*str = rb_str_new(0, len);
|
191
|
-
return 1;
|
192
|
-
}
|
193
|
-
else {
|
194
|
-
VALUE s = StringValue(*str);
|
195
|
-
long clen = RSTRING_LEN(s);
|
196
|
-
if (clen >= len) {
|
197
|
-
rb_str_modify(s);
|
198
|
-
return 0;
|
199
|
-
}
|
200
|
-
len -= clen;
|
201
|
-
}
|
202
|
-
rb_str_modify_expand(*str, len);
|
203
|
-
return 0;
|
204
|
-
}
|
205
|
-
|
206
|
-
#define MAX_REALLOC_GAP 4096
|
207
|
-
static void io_shrink_read_string(VALUE str, long n) {
|
208
|
-
if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
|
209
|
-
rb_str_resize(str, n);
|
210
|
-
}
|
211
|
-
}
|
212
|
-
|
213
|
-
void io_set_read_length(VALUE str, long n, int shrinkable) {
|
214
|
-
if (RSTRING_LEN(str) != n) {
|
215
|
-
rb_str_modify(str);
|
216
|
-
rb_str_set_len(str, n);
|
217
|
-
if (shrinkable) io_shrink_read_string(str, n);
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
|
-
static rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
222
|
-
if (fptr->encs.enc) {
|
223
|
-
return fptr->encs.enc;
|
224
|
-
}
|
225
|
-
return rb_default_external_encoding();
|
226
|
-
}
|
227
|
-
|
228
|
-
VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
229
|
-
OBJ_TAINT(str);
|
230
|
-
rb_enc_associate(str, io_read_encoding(fptr));
|
231
|
-
return str;
|
232
|
-
}
|
233
|
-
|
234
|
-
//////////////////////////////////////////////////////////////////////
|
235
|
-
//////////////////////////////////////////////////////////////////////
|
200
|
+
#include "backend_common.h"
|
236
201
|
|
237
202
|
struct libev_io {
|
238
203
|
struct ev_io io;
|
239
204
|
VALUE fiber;
|
240
205
|
};
|
241
206
|
|
242
|
-
void
|
207
|
+
void Backend_io_callback(EV_P_ ev_io *w, int revents)
|
243
208
|
{
|
244
209
|
struct libev_io *watcher = (struct libev_io *)w;
|
245
210
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
246
211
|
}
|
247
212
|
|
248
|
-
|
249
|
-
VALUE ret;
|
250
|
-
backend->ref_count++;
|
251
|
-
ret = Thread_switch_fiber(rb_thread_current());
|
252
|
-
backend->ref_count--;
|
253
|
-
RB_GC_GUARD(ret);
|
254
|
-
return ret;
|
255
|
-
}
|
256
|
-
|
257
|
-
VALUE libev_wait_fd_with_watcher(LibevBackend_t *backend, int fd, struct libev_io *watcher, int events) {
|
213
|
+
VALUE libev_wait_fd_with_watcher(Backend_t *backend, int fd, struct libev_io *watcher, int events) {
|
258
214
|
VALUE switchpoint_result;
|
259
215
|
|
260
216
|
if (watcher->fiber == Qnil) {
|
261
217
|
watcher->fiber = rb_fiber_current();
|
262
|
-
ev_io_init(&watcher->io,
|
218
|
+
ev_io_init(&watcher->io, Backend_io_callback, fd, events);
|
263
219
|
}
|
264
220
|
ev_io_start(backend->ev_loop, &watcher->io);
|
265
221
|
|
266
|
-
switchpoint_result =
|
222
|
+
switchpoint_result = backend_await(backend);
|
267
223
|
|
268
224
|
ev_io_stop(backend->ev_loop, &watcher->io);
|
269
225
|
RB_GC_GUARD(switchpoint_result);
|
270
226
|
return switchpoint_result;
|
271
227
|
}
|
272
228
|
|
273
|
-
VALUE libev_wait_fd(
|
229
|
+
VALUE libev_wait_fd(Backend_t *backend, int fd, int events, int raise_exception) {
|
274
230
|
struct libev_io watcher;
|
275
231
|
VALUE switchpoint_result = Qnil;
|
276
232
|
watcher.fiber = Qnil;
|
277
233
|
|
278
234
|
switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, events);
|
279
235
|
|
280
|
-
if (raise_exception)
|
236
|
+
if (raise_exception) RAISE_IF_EXCEPTION(switchpoint_result);
|
281
237
|
RB_GC_GUARD(switchpoint_result);
|
282
238
|
return switchpoint_result;
|
283
239
|
}
|
284
240
|
|
285
|
-
VALUE
|
286
|
-
|
287
|
-
return Thread_switch_fiber(rb_thread_current());
|
288
|
-
}
|
289
|
-
|
290
|
-
ID ID_ivar_is_nonblocking;
|
291
|
-
|
292
|
-
// Since we need to ensure that fd's are non-blocking before every I/O
|
293
|
-
// operation, here we improve upon Ruby's rb_io_set_nonblock by caching the
|
294
|
-
// "nonblock" state in an instance variable. Calling rb_ivar_get on every read
|
295
|
-
// is still much cheaper than doing a fcntl syscall on every read! Preliminary
|
296
|
-
// benchmarks (with a "hello world" HTTP server) show throughput is improved
|
297
|
-
// by 10-13%.
|
298
|
-
inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
299
|
-
VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
|
300
|
-
if (is_nonblocking == Qtrue) return;
|
301
|
-
|
302
|
-
rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
|
303
|
-
|
304
|
-
#ifdef _WIN32
|
305
|
-
rb_w32_set_nonblock(fptr->fd);
|
306
|
-
#elif defined(F_GETFL)
|
307
|
-
int oflags = fcntl(fptr->fd, F_GETFL);
|
308
|
-
if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
|
309
|
-
oflags |= O_NONBLOCK;
|
310
|
-
fcntl(fptr->fd, F_SETFL, oflags);
|
311
|
-
#endif
|
312
|
-
}
|
313
|
-
|
314
|
-
VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
315
|
-
LibevBackend_t *backend;
|
241
|
+
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
242
|
+
Backend_t *backend;
|
316
243
|
struct libev_io watcher;
|
317
244
|
rb_io_t *fptr;
|
318
245
|
long dynamic_len = length == Qnil;
|
@@ -322,26 +249,17 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
|
|
322
249
|
long total = 0;
|
323
250
|
VALUE switchpoint_result = Qnil;
|
324
251
|
int read_to_eof = RTEST(to_eof);
|
325
|
-
VALUE underlying_io =
|
252
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
326
253
|
|
327
|
-
|
254
|
+
GetBackend(self, backend);
|
328
255
|
if (underlying_io != Qnil) io = underlying_io;
|
329
256
|
GetOpenFile(io, fptr);
|
330
257
|
rb_io_check_byte_readable(fptr);
|
331
258
|
io_set_nonblock(fptr, io);
|
259
|
+
rectify_io_file_pos(fptr);
|
332
260
|
watcher.fiber = Qnil;
|
333
|
-
|
334
261
|
OBJ_TAINT(str);
|
335
262
|
|
336
|
-
// Apparently after reopening a closed file, the file position is not reset,
|
337
|
-
// which causes the read to fail. Fortunately we can use fptr->rbuf.len to
|
338
|
-
// find out if that's the case.
|
339
|
-
// See: https://github.com/digital-fabric/polyphony/issues/30
|
340
|
-
if (fptr->rbuf.len > 0) {
|
341
|
-
lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
|
342
|
-
fptr->rbuf.len = 0;
|
343
|
-
}
|
344
|
-
|
345
263
|
while (1) {
|
346
264
|
ssize_t n = read(fptr->fd, buf, len - total);
|
347
265
|
if (n < 0) {
|
@@ -353,7 +271,7 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
|
|
353
271
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
354
272
|
}
|
355
273
|
else {
|
356
|
-
switchpoint_result =
|
274
|
+
switchpoint_result = backend_snooze();
|
357
275
|
|
358
276
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
359
277
|
|
@@ -387,24 +305,12 @@ error:
|
|
387
305
|
return RAISE_EXCEPTION(switchpoint_result);
|
388
306
|
}
|
389
307
|
|
390
|
-
VALUE
|
391
|
-
|
392
|
-
|
393
|
-
str = Qnil; \
|
394
|
-
shrinkable = io_setstrbuf(&str, len); \
|
395
|
-
buf = RSTRING_PTR(str); \
|
396
|
-
total = 0; \
|
397
|
-
OBJ_TAINT(str); \
|
398
|
-
}
|
399
|
-
|
400
|
-
#define YIELD_STR() { \
|
401
|
-
io_set_read_length(str, total, shrinkable); \
|
402
|
-
io_enc_str(str, fptr); \
|
403
|
-
rb_yield(str); \
|
404
|
-
PREPARE_STR(); \
|
405
|
-
}
|
308
|
+
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
309
|
+
return Backend_read(self, io, str, length, Qnil);
|
310
|
+
}
|
406
311
|
|
407
|
-
|
312
|
+
VALUE Backend_read_loop(VALUE self, VALUE io) {
|
313
|
+
Backend_t *backend;
|
408
314
|
struct libev_io watcher;
|
409
315
|
rb_io_t *fptr;
|
410
316
|
VALUE str;
|
@@ -413,26 +319,18 @@ VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
|
|
413
319
|
int shrinkable;
|
414
320
|
char *buf;
|
415
321
|
VALUE switchpoint_result = Qnil;
|
416
|
-
VALUE underlying_io =
|
322
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
417
323
|
|
418
|
-
|
324
|
+
READ_LOOP_PREPARE_STR();
|
419
325
|
|
420
|
-
|
326
|
+
GetBackend(self, backend);
|
421
327
|
if (underlying_io != Qnil) io = underlying_io;
|
422
328
|
GetOpenFile(io, fptr);
|
423
329
|
rb_io_check_byte_readable(fptr);
|
424
330
|
io_set_nonblock(fptr, io);
|
331
|
+
rectify_io_file_pos(fptr);
|
425
332
|
watcher.fiber = Qnil;
|
426
333
|
|
427
|
-
// Apparently after reopening a closed file, the file position is not reset,
|
428
|
-
// which causes the read to fail. Fortunately we can use fptr->rbuf.len to
|
429
|
-
// find out if that's the case.
|
430
|
-
// See: https://github.com/digital-fabric/polyphony/issues/30
|
431
|
-
if (fptr->rbuf.len > 0) {
|
432
|
-
lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
|
433
|
-
fptr->rbuf.len = 0;
|
434
|
-
}
|
435
|
-
|
436
334
|
while (1) {
|
437
335
|
ssize_t n = read(fptr->fd, buf, len);
|
438
336
|
if (n < 0) {
|
@@ -443,13 +341,13 @@ VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
|
|
443
341
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
444
342
|
}
|
445
343
|
else {
|
446
|
-
switchpoint_result =
|
344
|
+
switchpoint_result = backend_snooze();
|
447
345
|
|
448
346
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
449
347
|
|
450
348
|
if (n == 0) break; // EOF
|
451
349
|
total = n;
|
452
|
-
|
350
|
+
READ_LOOP_YIELD_STR();
|
453
351
|
}
|
454
352
|
}
|
455
353
|
|
@@ -462,8 +360,8 @@ error:
|
|
462
360
|
return RAISE_EXCEPTION(switchpoint_result);
|
463
361
|
}
|
464
362
|
|
465
|
-
VALUE
|
466
|
-
|
363
|
+
VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
364
|
+
Backend_t *backend;
|
467
365
|
struct libev_io watcher;
|
468
366
|
rb_io_t *fptr;
|
469
367
|
VALUE switchpoint_result = Qnil;
|
@@ -472,11 +370,12 @@ VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
|
|
472
370
|
long len = RSTRING_LEN(str);
|
473
371
|
long left = len;
|
474
372
|
|
475
|
-
underlying_io =
|
373
|
+
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
476
374
|
if (underlying_io != Qnil) io = underlying_io;
|
477
|
-
|
375
|
+
GetBackend(self, backend);
|
478
376
|
io = rb_io_get_write_io(io);
|
479
377
|
GetOpenFile(io, fptr);
|
378
|
+
io_set_nonblock(fptr, io);
|
480
379
|
watcher.fiber = Qnil;
|
481
380
|
|
482
381
|
while (left > 0) {
|
@@ -496,7 +395,7 @@ VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
|
|
496
395
|
}
|
497
396
|
|
498
397
|
if (watcher.fiber == Qnil) {
|
499
|
-
switchpoint_result =
|
398
|
+
switchpoint_result = backend_snooze();
|
500
399
|
|
501
400
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
502
401
|
}
|
@@ -509,8 +408,8 @@ error:
|
|
509
408
|
return RAISE_EXCEPTION(switchpoint_result);
|
510
409
|
}
|
511
410
|
|
512
|
-
VALUE
|
513
|
-
|
411
|
+
VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
412
|
+
Backend_t *backend;
|
514
413
|
struct libev_io watcher;
|
515
414
|
rb_io_t *fptr;
|
516
415
|
VALUE switchpoint_result = Qnil;
|
@@ -521,11 +420,12 @@ VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
521
420
|
struct iovec *iov_ptr = 0;
|
522
421
|
int iov_count = argc;
|
523
422
|
|
524
|
-
underlying_io =
|
423
|
+
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
525
424
|
if (underlying_io != Qnil) io = underlying_io;
|
526
|
-
|
425
|
+
GetBackend(self, backend);
|
527
426
|
io = rb_io_get_write_io(io);
|
528
427
|
GetOpenFile(io, fptr);
|
428
|
+
io_set_nonblock(fptr, io);
|
529
429
|
watcher.fiber = Qnil;
|
530
430
|
|
531
431
|
iov = malloc(iov_count * sizeof(struct iovec));
|
@@ -541,7 +441,10 @@ VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
541
441
|
ssize_t n = writev(fptr->fd, iov_ptr, iov_count);
|
542
442
|
if (n < 0) {
|
543
443
|
int e = errno;
|
544
|
-
if ((e != EWOULDBLOCK && e != EAGAIN))
|
444
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) {
|
445
|
+
free(iov);
|
446
|
+
rb_syserr_fail(e, strerror(e));
|
447
|
+
}
|
545
448
|
|
546
449
|
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
547
450
|
|
@@ -566,8 +469,7 @@ VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
566
469
|
}
|
567
470
|
}
|
568
471
|
if (watcher.fiber == Qnil) {
|
569
|
-
switchpoint_result =
|
570
|
-
|
472
|
+
switchpoint_result = backend_snooze();
|
571
473
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
572
474
|
}
|
573
475
|
|
@@ -581,30 +483,28 @@ error:
|
|
581
483
|
return RAISE_EXCEPTION(switchpoint_result);
|
582
484
|
}
|
583
485
|
|
584
|
-
VALUE
|
486
|
+
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
585
487
|
if (argc < 2)
|
586
488
|
// TODO: raise ArgumentError
|
587
489
|
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
588
490
|
|
589
491
|
return (argc == 2) ?
|
590
|
-
|
591
|
-
|
492
|
+
Backend_write(self, argv[0], argv[1]) :
|
493
|
+
Backend_writev(self, argv[0], argc - 1, argv + 1);
|
592
494
|
}
|
593
495
|
|
594
|
-
|
595
|
-
|
596
|
-
VALUE LibevBackend_accept(VALUE self, VALUE sock) {
|
597
|
-
LibevBackend_t *backend;
|
496
|
+
VALUE Backend_accept(VALUE self, VALUE sock) {
|
497
|
+
Backend_t *backend;
|
598
498
|
struct libev_io watcher;
|
599
499
|
rb_io_t *fptr;
|
600
500
|
int fd;
|
601
501
|
struct sockaddr addr;
|
602
502
|
socklen_t len = (socklen_t)sizeof addr;
|
603
503
|
VALUE switchpoint_result = Qnil;
|
604
|
-
VALUE underlying_sock =
|
504
|
+
VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
|
605
505
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
606
506
|
|
607
|
-
|
507
|
+
GetBackend(self, backend);
|
608
508
|
GetOpenFile(sock, fptr);
|
609
509
|
io_set_nonblock(fptr, sock);
|
610
510
|
watcher.fiber = Qnil;
|
@@ -621,7 +521,7 @@ VALUE LibevBackend_accept(VALUE self, VALUE sock) {
|
|
621
521
|
else {
|
622
522
|
VALUE socket;
|
623
523
|
rb_io_t *fp;
|
624
|
-
switchpoint_result =
|
524
|
+
switchpoint_result = backend_snooze();
|
625
525
|
|
626
526
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
627
527
|
close(fd); // close fd since we're raising an exception
|
@@ -649,8 +549,8 @@ error:
|
|
649
549
|
return RAISE_EXCEPTION(switchpoint_result);
|
650
550
|
}
|
651
551
|
|
652
|
-
VALUE
|
653
|
-
|
552
|
+
VALUE Backend_accept_loop(VALUE self, VALUE sock) {
|
553
|
+
Backend_t *backend;
|
654
554
|
struct libev_io watcher;
|
655
555
|
rb_io_t *fptr;
|
656
556
|
int fd;
|
@@ -658,10 +558,10 @@ VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
|
|
658
558
|
socklen_t len = (socklen_t)sizeof addr;
|
659
559
|
VALUE switchpoint_result = Qnil;
|
660
560
|
VALUE socket = Qnil;
|
661
|
-
VALUE underlying_sock =
|
561
|
+
VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
|
662
562
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
663
563
|
|
664
|
-
|
564
|
+
GetBackend(self, backend);
|
665
565
|
GetOpenFile(sock, fptr);
|
666
566
|
io_set_nonblock(fptr, sock);
|
667
567
|
watcher.fiber = Qnil;
|
@@ -678,7 +578,7 @@ VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
|
|
678
578
|
}
|
679
579
|
else {
|
680
580
|
rb_io_t *fp;
|
681
|
-
switchpoint_result =
|
581
|
+
switchpoint_result = backend_snooze();
|
682
582
|
|
683
583
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
684
584
|
close(fd); // close fd since we're raising an exception
|
@@ -707,17 +607,17 @@ error:
|
|
707
607
|
return RAISE_EXCEPTION(switchpoint_result);
|
708
608
|
}
|
709
609
|
|
710
|
-
VALUE
|
711
|
-
|
610
|
+
VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
611
|
+
Backend_t *backend;
|
712
612
|
struct libev_io watcher;
|
713
613
|
rb_io_t *fptr;
|
714
614
|
struct sockaddr_in addr;
|
715
615
|
char *host_buf = StringValueCStr(host);
|
716
616
|
VALUE switchpoint_result = Qnil;
|
717
|
-
VALUE underlying_sock =
|
617
|
+
VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
|
718
618
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
719
619
|
|
720
|
-
|
620
|
+
GetBackend(self, backend);
|
721
621
|
GetOpenFile(sock, fptr);
|
722
622
|
io_set_nonblock(fptr, sock);
|
723
623
|
watcher.fiber = Qnil;
|
@@ -736,7 +636,7 @@ VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
736
636
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
737
637
|
}
|
738
638
|
else {
|
739
|
-
switchpoint_result =
|
639
|
+
switchpoint_result = backend_snooze();
|
740
640
|
|
741
641
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
742
642
|
}
|
@@ -746,13 +646,13 @@ error:
|
|
746
646
|
return RAISE_EXCEPTION(switchpoint_result);
|
747
647
|
}
|
748
648
|
|
749
|
-
VALUE
|
750
|
-
|
649
|
+
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
650
|
+
Backend_t *backend;
|
751
651
|
rb_io_t *fptr;
|
752
652
|
int events = RTEST(write) ? EV_WRITE : EV_READ;
|
753
|
-
VALUE underlying_io =
|
653
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
754
654
|
if (underlying_io != Qnil) io = underlying_io;
|
755
|
-
|
655
|
+
GetBackend(self, backend);
|
756
656
|
GetOpenFile(io, fptr);
|
757
657
|
|
758
658
|
return libev_wait_fd(backend, fptr->fd, events, 1);
|
@@ -763,26 +663,26 @@ struct libev_timer {
|
|
763
663
|
VALUE fiber;
|
764
664
|
};
|
765
665
|
|
766
|
-
void
|
666
|
+
void Backend_timer_callback(EV_P_ ev_timer *w, int revents)
|
767
667
|
{
|
768
668
|
struct libev_timer *watcher = (struct libev_timer *)w;
|
769
669
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
770
670
|
}
|
771
671
|
|
772
|
-
VALUE
|
773
|
-
|
672
|
+
VALUE Backend_sleep(VALUE self, VALUE duration) {
|
673
|
+
Backend_t *backend;
|
774
674
|
struct libev_timer watcher;
|
775
675
|
VALUE switchpoint_result = Qnil;
|
776
676
|
|
777
|
-
|
677
|
+
GetBackend(self, backend);
|
778
678
|
watcher.fiber = rb_fiber_current();
|
779
|
-
ev_timer_init(&watcher.timer,
|
679
|
+
ev_timer_init(&watcher.timer, Backend_timer_callback, NUM2DBL(duration), 0.);
|
780
680
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
781
681
|
|
782
|
-
switchpoint_result =
|
682
|
+
switchpoint_result = backend_await(backend);
|
783
683
|
|
784
684
|
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
785
|
-
|
685
|
+
RAISE_IF_EXCEPTION(switchpoint_result);
|
786
686
|
RB_GC_GUARD(watcher.fiber);
|
787
687
|
RB_GC_GUARD(switchpoint_result);
|
788
688
|
return switchpoint_result;
|
@@ -793,98 +693,106 @@ struct libev_child {
|
|
793
693
|
VALUE fiber;
|
794
694
|
};
|
795
695
|
|
796
|
-
void
|
696
|
+
void Backend_child_callback(EV_P_ ev_child *w, int revents)
|
797
697
|
{
|
798
698
|
struct libev_child *watcher = (struct libev_child *)w;
|
799
|
-
int exit_status = w->rstatus
|
699
|
+
int exit_status = WEXITSTATUS(w->rstatus);
|
800
700
|
VALUE status;
|
801
701
|
|
802
702
|
status = rb_ary_new_from_args(2, INT2NUM(w->rpid), INT2NUM(exit_status));
|
803
703
|
Fiber_make_runnable(watcher->fiber, status);
|
804
704
|
}
|
805
705
|
|
806
|
-
VALUE
|
807
|
-
|
706
|
+
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
707
|
+
Backend_t *backend;
|
808
708
|
struct libev_child watcher;
|
809
709
|
VALUE switchpoint_result = Qnil;
|
810
|
-
|
710
|
+
GetBackend(self, backend);
|
811
711
|
|
812
712
|
watcher.fiber = rb_fiber_current();
|
813
|
-
ev_child_init(&watcher.child,
|
713
|
+
ev_child_init(&watcher.child, Backend_child_callback, NUM2INT(pid), 0);
|
814
714
|
ev_child_start(backend->ev_loop, &watcher.child);
|
815
715
|
|
816
|
-
switchpoint_result =
|
716
|
+
switchpoint_result = backend_await(backend);
|
817
717
|
|
818
718
|
ev_child_stop(backend->ev_loop, &watcher.child);
|
819
|
-
|
719
|
+
RAISE_IF_EXCEPTION(switchpoint_result);
|
820
720
|
RB_GC_GUARD(watcher.fiber);
|
821
721
|
RB_GC_GUARD(switchpoint_result);
|
822
722
|
return switchpoint_result;
|
823
723
|
}
|
824
724
|
|
825
|
-
|
826
|
-
LibevBackend_t *backend;
|
827
|
-
GetLibevBackend(self, backend);
|
828
|
-
return backend->ev_loop;
|
829
|
-
}
|
830
|
-
|
831
|
-
void LibevBackend_async_callback(EV_P_ ev_async *w, int revents) { }
|
725
|
+
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
832
726
|
|
833
|
-
VALUE
|
834
|
-
|
727
|
+
VALUE Backend_wait_event(VALUE self, VALUE raise) {
|
728
|
+
Backend_t *backend;
|
835
729
|
VALUE switchpoint_result = Qnil;
|
836
|
-
|
730
|
+
GetBackend(self, backend);
|
837
731
|
|
838
732
|
struct ev_async async;
|
839
733
|
|
840
|
-
ev_async_init(&async,
|
734
|
+
ev_async_init(&async, Backend_async_callback);
|
841
735
|
ev_async_start(backend->ev_loop, &async);
|
842
736
|
|
843
|
-
switchpoint_result =
|
737
|
+
switchpoint_result = backend_await(backend);
|
844
738
|
|
845
739
|
ev_async_stop(backend->ev_loop, &async);
|
846
|
-
if (RTEST(raise))
|
740
|
+
if (RTEST(raise)) RAISE_IF_EXCEPTION(switchpoint_result);
|
847
741
|
RB_GC_GUARD(switchpoint_result);
|
848
742
|
return switchpoint_result;
|
849
743
|
}
|
850
744
|
|
851
|
-
|
745
|
+
VALUE Backend_kind(VALUE self) {
|
746
|
+
return SYM_libev;
|
747
|
+
}
|
748
|
+
|
749
|
+
void Init_Backend() {
|
750
|
+
ev_set_allocator(xrealloc);
|
751
|
+
|
852
752
|
rb_require("socket");
|
853
753
|
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
854
754
|
|
855
755
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
856
|
-
rb_define_alloc_func(cBackend,
|
857
|
-
|
858
|
-
rb_define_method(cBackend, "initialize",
|
859
|
-
rb_define_method(cBackend, "finalize",
|
860
|
-
rb_define_method(cBackend, "post_fork",
|
861
|
-
rb_define_method(cBackend, "pending_count",
|
862
|
-
|
863
|
-
rb_define_method(cBackend, "ref",
|
864
|
-
rb_define_method(cBackend, "unref",
|
865
|
-
|
866
|
-
rb_define_method(cBackend, "poll",
|
867
|
-
rb_define_method(cBackend, "break",
|
868
|
-
|
869
|
-
rb_define_method(cBackend, "read",
|
870
|
-
rb_define_method(cBackend, "read_loop",
|
871
|
-
rb_define_method(cBackend, "write",
|
872
|
-
rb_define_method(cBackend, "accept",
|
873
|
-
rb_define_method(cBackend, "accept_loop",
|
874
|
-
rb_define_method(cBackend, "connect",
|
875
|
-
rb_define_method(cBackend, "
|
876
|
-
rb_define_method(cBackend, "
|
877
|
-
rb_define_method(cBackend, "
|
878
|
-
rb_define_method(cBackend, "
|
756
|
+
rb_define_alloc_func(cBackend, Backend_allocate);
|
757
|
+
|
758
|
+
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
759
|
+
rb_define_method(cBackend, "finalize", Backend_finalize, 0);
|
760
|
+
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
761
|
+
rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
|
762
|
+
|
763
|
+
rb_define_method(cBackend, "ref", Backend_ref, 0);
|
764
|
+
rb_define_method(cBackend, "unref", Backend_unref, 0);
|
765
|
+
|
766
|
+
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
767
|
+
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
768
|
+
|
769
|
+
rb_define_method(cBackend, "read", Backend_read, 4);
|
770
|
+
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
771
|
+
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
772
|
+
rb_define_method(cBackend, "accept", Backend_accept, 1);
|
773
|
+
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 1);
|
774
|
+
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
775
|
+
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
776
|
+
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
777
|
+
rb_define_method(cBackend, "send", Backend_write, 2);
|
778
|
+
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
779
|
+
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
780
|
+
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
781
|
+
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
782
|
+
|
783
|
+
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
879
784
|
|
880
785
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
786
|
+
SYM_libev = ID2SYM(rb_intern("libev"));
|
881
787
|
|
882
|
-
__BACKEND__.pending_count =
|
883
|
-
__BACKEND__.poll =
|
884
|
-
__BACKEND__.ref =
|
885
|
-
__BACKEND__.ref_count =
|
886
|
-
__BACKEND__.reset_ref_count =
|
887
|
-
__BACKEND__.unref =
|
888
|
-
__BACKEND__.wait_event =
|
889
|
-
__BACKEND__.wakeup =
|
788
|
+
__BACKEND__.pending_count = Backend_pending_count;
|
789
|
+
__BACKEND__.poll = Backend_poll;
|
790
|
+
__BACKEND__.ref = Backend_ref;
|
791
|
+
__BACKEND__.ref_count = Backend_ref_count;
|
792
|
+
__BACKEND__.reset_ref_count = Backend_reset_ref_count;
|
793
|
+
__BACKEND__.unref = Backend_unref;
|
794
|
+
__BACKEND__.wait_event = Backend_wait_event;
|
795
|
+
__BACKEND__.wakeup = Backend_wakeup;
|
890
796
|
}
|
797
|
+
|
798
|
+
#endif // POLYPHONY_BACKEND_LIBEV
|