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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGELOG.md +4 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +3 -3
  7. data/Rakefile +1 -1
  8. data/TODO.md +4 -4
  9. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
  10. data/ext/liburing/liburing.h +585 -0
  11. data/ext/liburing/liburing/README.md +4 -0
  12. data/ext/liburing/liburing/barrier.h +73 -0
  13. data/ext/liburing/liburing/compat.h +15 -0
  14. data/ext/liburing/liburing/io_uring.h +343 -0
  15. data/ext/liburing/queue.c +333 -0
  16. data/ext/liburing/register.c +187 -0
  17. data/ext/liburing/setup.c +210 -0
  18. data/ext/liburing/syscall.c +54 -0
  19. data/ext/liburing/syscall.h +18 -0
  20. data/ext/polyphony/backend.h +0 -14
  21. data/ext/polyphony/backend_common.h +109 -0
  22. data/ext/polyphony/backend_io_uring.c +884 -0
  23. data/ext/polyphony/backend_io_uring_context.c +73 -0
  24. data/ext/polyphony/backend_io_uring_context.h +52 -0
  25. data/ext/polyphony/{libev_backend.c → backend_libev.c} +202 -294
  26. data/ext/polyphony/event.c +1 -1
  27. data/ext/polyphony/extconf.rb +31 -13
  28. data/ext/polyphony/fiber.c +29 -22
  29. data/ext/polyphony/libev.c +4 -0
  30. data/ext/polyphony/libev.h +8 -2
  31. data/ext/polyphony/liburing.c +8 -0
  32. data/ext/polyphony/playground.c +51 -0
  33. data/ext/polyphony/polyphony.c +5 -5
  34. data/ext/polyphony/polyphony.h +16 -12
  35. data/ext/polyphony/polyphony_ext.c +10 -4
  36. data/ext/polyphony/queue.c +1 -1
  37. data/ext/polyphony/thread.c +11 -9
  38. data/lib/polyphony/adapters/trace.rb +2 -2
  39. data/lib/polyphony/core/global_api.rb +1 -4
  40. data/lib/polyphony/extensions/debug.rb +13 -0
  41. data/lib/polyphony/extensions/fiber.rb +2 -2
  42. data/lib/polyphony/extensions/socket.rb +59 -10
  43. data/lib/polyphony/version.rb +1 -1
  44. data/test/helper.rb +36 -4
  45. data/test/io_uring_test.rb +55 -0
  46. data/test/stress.rb +5 -2
  47. data/test/test_backend.rb +4 -6
  48. data/test/test_ext.rb +1 -2
  49. data/test/test_fiber.rb +22 -16
  50. data/test/test_global_api.rb +33 -35
  51. data/test/test_throttler.rb +3 -6
  52. data/test/test_trace.rb +7 -5
  53. 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 LibevBackend_t {
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
- } LibevBackend_t;
48
+ } Backend_t;
21
49
 
22
- static size_t LibevBackend_size(const void *ptr) {
23
- return sizeof(LibevBackend_t);
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 LibevBackend_type = {
27
- "Libev",
28
- {0, 0, LibevBackend_size,},
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 LibevBackend_allocate(VALUE klass) {
33
- LibevBackend_t *backend = ALLOC(LibevBackend_t);
60
+ static VALUE Backend_allocate(VALUE klass) {
61
+ Backend_t *backend = ALLOC(Backend_t);
34
62
 
35
- return TypedData_Wrap_Struct(klass, &LibevBackend_type, backend);
63
+ return TypedData_Wrap_Struct(klass, &Backend_type, backend);
36
64
  }
37
65
 
38
- #define GetLibevBackend(obj, backend) \
39
- TypedData_Get_Struct((obj), LibevBackend_t, &LibevBackend_type, (backend))
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 LibevBackend_initialize(VALUE self) {
47
- LibevBackend_t *backend;
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
- GetLibevBackend(self, backend);
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 LibevBackend_finalize(VALUE self) {
66
- LibevBackend_t *backend;
67
- GetLibevBackend(self, backend);
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 LibevBackend_post_fork(VALUE self) {
77
- LibevBackend_t *backend;
78
- GetLibevBackend(self, backend);
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 LibevBackend_ref(VALUE self) {
92
- LibevBackend_t *backend;
93
- GetLibevBackend(self, backend);
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 LibevBackend_unref(VALUE self) {
100
- LibevBackend_t *backend;
101
- GetLibevBackend(self, backend);
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 LibevBackend_ref_count(VALUE self) {
108
- LibevBackend_t *backend;
109
- GetLibevBackend(self, backend);
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 LibevBackend_reset_ref_count(VALUE self) {
115
- LibevBackend_t *backend;
116
- GetLibevBackend(self, backend);
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 LibevBackend_pending_count(VALUE self) {
149
+ VALUE Backend_pending_count(VALUE self) {
122
150
  int count;
123
- LibevBackend_t *backend;
124
- GetLibevBackend(self, backend);
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 LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
157
+ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
130
158
  int is_nowait = nowait == Qtrue;
131
- LibevBackend_t *backend;
132
- GetLibevBackend(self, backend);
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, SYM_fiber_ev_loop_enter, current_fiber);
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, SYM_fiber_ev_loop_leave, current_fiber);
176
+ COND_TRACE(2, SYM_fiber_event_poll_leave, current_fiber);
149
177
 
150
178
  return self;
151
179
  }
152
180
 
153
- VALUE LibevBackend_wakeup(VALUE self) {
154
- LibevBackend_t *backend;
155
- GetLibevBackend(self, backend);
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 LibevBackend_io_callback(EV_P_ ev_io *w, int revents)
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
- inline VALUE libev_await(LibevBackend_t *backend) {
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, LibevBackend_io_callback, fd, events);
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 = libev_await(backend);
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(LibevBackend_t *backend, int fd, int events, int raise_exception) {
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) TEST_RESUME_EXCEPTION(switchpoint_result);
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 libev_snooze() {
286
- Fiber_make_runnable(rb_fiber_current(), Qnil);
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 = rb_iv_get(io, "@io");
252
+ VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
326
253
 
327
- GetLibevBackend(self, backend);
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 = libev_snooze();
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 LibevBackend_read_loop(VALUE self, VALUE io) {
391
-
392
- #define PREPARE_STR() { \
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
- LibevBackend_t *backend;
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 = rb_iv_get(io, "@io");
322
+ VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
417
323
 
418
- PREPARE_STR();
324
+ READ_LOOP_PREPARE_STR();
419
325
 
420
- GetLibevBackend(self, backend);
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 = libev_snooze();
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
- YIELD_STR();
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 LibevBackend_write(VALUE self, VALUE io, VALUE str) {
466
- LibevBackend_t *backend;
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 = rb_iv_get(io, "@io");
373
+ underlying_io = rb_ivar_get(io, ID_ivar_io);
476
374
  if (underlying_io != Qnil) io = underlying_io;
477
- GetLibevBackend(self, backend);
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 = libev_snooze();
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 LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
513
- LibevBackend_t *backend;
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 = rb_iv_get(io, "@io");
423
+ underlying_io = rb_ivar_get(io, ID_ivar_io);
525
424
  if (underlying_io != Qnil) io = underlying_io;
526
- GetLibevBackend(self, backend);
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)) rb_syserr_fail(e, strerror(e));
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 = libev_snooze();
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 LibevBackend_write_m(int argc, VALUE *argv, VALUE self) {
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
- LibevBackend_write(self, argv[0], argv[1]) :
591
- LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
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 = rb_iv_get(sock, "@io");
504
+ VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
605
505
  if (underlying_sock != Qnil) sock = underlying_sock;
606
506
 
607
- GetLibevBackend(self, backend);
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 = libev_snooze();
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 LibevBackend_accept_loop(VALUE self, VALUE sock) {
653
- LibevBackend_t *backend;
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 = rb_iv_get(sock, "@io");
561
+ VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
662
562
  if (underlying_sock != Qnil) sock = underlying_sock;
663
563
 
664
- GetLibevBackend(self, backend);
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 = libev_snooze();
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 LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
711
- LibevBackend_t *backend;
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 = rb_iv_get(sock, "@io");
617
+ VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
718
618
  if (underlying_sock != Qnil) sock = underlying_sock;
719
619
 
720
- GetLibevBackend(self, backend);
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 = libev_snooze();
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 LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
750
- LibevBackend_t *backend;
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 = rb_iv_get(io, "@io");
653
+ VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
754
654
  if (underlying_io != Qnil) io = underlying_io;
755
- GetLibevBackend(self, backend);
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 LibevBackend_timer_callback(EV_P_ ev_timer *w, int revents)
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 LibevBackend_sleep(VALUE self, VALUE duration) {
773
- LibevBackend_t *backend;
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
- GetLibevBackend(self, backend);
677
+ GetBackend(self, backend);
778
678
  watcher.fiber = rb_fiber_current();
779
- ev_timer_init(&watcher.timer, LibevBackend_timer_callback, NUM2DBL(duration), 0.);
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 = libev_await(backend);
682
+ switchpoint_result = backend_await(backend);
783
683
 
784
684
  ev_timer_stop(backend->ev_loop, &watcher.timer);
785
- TEST_RESUME_EXCEPTION(switchpoint_result);
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 LibevBackend_child_callback(EV_P_ ev_child *w, int revents)
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 >> 8; // weird, why should we do this?
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 LibevBackend_waitpid(VALUE self, VALUE pid) {
807
- LibevBackend_t *backend;
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
- GetLibevBackend(self, backend);
710
+ GetBackend(self, backend);
811
711
 
812
712
  watcher.fiber = rb_fiber_current();
813
- ev_child_init(&watcher.child, LibevBackend_child_callback, NUM2INT(pid), 0);
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 = libev_await(backend);
716
+ switchpoint_result = backend_await(backend);
817
717
 
818
718
  ev_child_stop(backend->ev_loop, &watcher.child);
819
- TEST_RESUME_EXCEPTION(switchpoint_result);
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
- struct ev_loop *LibevBackend_ev_loop(VALUE self) {
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 LibevBackend_wait_event(VALUE self, VALUE raise) {
834
- LibevBackend_t *backend;
727
+ VALUE Backend_wait_event(VALUE self, VALUE raise) {
728
+ Backend_t *backend;
835
729
  VALUE switchpoint_result = Qnil;
836
- GetLibevBackend(self, backend);
730
+ GetBackend(self, backend);
837
731
 
838
732
  struct ev_async async;
839
733
 
840
- ev_async_init(&async, LibevBackend_async_callback);
734
+ ev_async_init(&async, Backend_async_callback);
841
735
  ev_async_start(backend->ev_loop, &async);
842
736
 
843
- switchpoint_result = libev_await(backend);
737
+ switchpoint_result = backend_await(backend);
844
738
 
845
739
  ev_async_stop(backend->ev_loop, &async);
846
- if (RTEST(raise)) TEST_RESUME_EXCEPTION(switchpoint_result);
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
- void Init_LibevBackend() {
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, LibevBackend_allocate);
857
-
858
- rb_define_method(cBackend, "initialize", LibevBackend_initialize, 0);
859
- rb_define_method(cBackend, "finalize", LibevBackend_finalize, 0);
860
- rb_define_method(cBackend, "post_fork", LibevBackend_post_fork, 0);
861
- rb_define_method(cBackend, "pending_count", LibevBackend_pending_count, 0);
862
-
863
- rb_define_method(cBackend, "ref", LibevBackend_ref, 0);
864
- rb_define_method(cBackend, "unref", LibevBackend_unref, 0);
865
-
866
- rb_define_method(cBackend, "poll", LibevBackend_poll, 3);
867
- rb_define_method(cBackend, "break", LibevBackend_wakeup, 0);
868
-
869
- rb_define_method(cBackend, "read", LibevBackend_read, 4);
870
- rb_define_method(cBackend, "read_loop", LibevBackend_read_loop, 1);
871
- rb_define_method(cBackend, "write", LibevBackend_write_m, -1);
872
- rb_define_method(cBackend, "accept", LibevBackend_accept, 1);
873
- rb_define_method(cBackend, "accept_loop", LibevBackend_accept_loop, 1);
874
- rb_define_method(cBackend, "connect", LibevBackend_connect, 3);
875
- rb_define_method(cBackend, "wait_io", LibevBackend_wait_io, 2);
876
- rb_define_method(cBackend, "sleep", LibevBackend_sleep, 1);
877
- rb_define_method(cBackend, "waitpid", LibevBackend_waitpid, 1);
878
- rb_define_method(cBackend, "wait_event", LibevBackend_wait_event, 1);
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 = LibevBackend_pending_count;
883
- __BACKEND__.poll = LibevBackend_poll;
884
- __BACKEND__.ref = LibevBackend_ref;
885
- __BACKEND__.ref_count = LibevBackend_ref_count;
886
- __BACKEND__.reset_ref_count = LibevBackend_reset_ref_count;
887
- __BACKEND__.unref = LibevBackend_unref;
888
- __BACKEND__.wait_event = LibevBackend_wait_event;
889
- __BACKEND__.wakeup = LibevBackend_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