polyphony 0.45.1 → 0.46.1

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