polyphony 0.45.5 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
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