polyphony 0.53.2 → 0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.gitignore +3 -1
- data/CHANGELOG.md +55 -24
- data/Gemfile.lock +3 -1
- data/TODO.md +0 -3
- data/examples/core/idle_gc.rb +21 -0
- data/examples/core/queue.rb +19 -0
- data/examples/io/https_server.rb +30 -0
- data/examples/io/pipe.rb +11 -0
- data/examples/io/splice_chunks.rb +29 -0
- data/examples/io/stdio.rb +8 -0
- data/ext/polyphony/backend_common.c +197 -0
- data/ext/polyphony/backend_common.h +28 -130
- data/ext/polyphony/backend_io_uring.c +380 -109
- data/ext/polyphony/backend_io_uring_context.c +14 -3
- data/ext/polyphony/backend_io_uring_context.h +11 -11
- data/ext/polyphony/backend_libev.c +417 -94
- data/ext/polyphony/polyphony.c +17 -15
- data/ext/polyphony/polyphony.h +3 -0
- data/ext/polyphony/runqueue.c +29 -1
- data/ext/polyphony/thread.c +19 -4
- data/lib/polyphony/core/sync.rb +8 -0
- data/lib/polyphony/extensions/openssl.rb +24 -17
- data/lib/polyphony/extensions/socket.rb +6 -20
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -0
- data/test/helper.rb +3 -3
- data/test/test_backend.rb +137 -2
- data/test/test_fiber.rb +0 -1
- data/test/test_io.rb +6 -3
- data/test/test_signal.rb +1 -1
- data/test/test_sync.rb +43 -0
- data/test/test_thread.rb +52 -0
- data/test/test_thread_pool.rb +1 -1
- data/test/test_timer.rb +16 -10
- metadata +23 -2
@@ -1,4 +1,5 @@
|
|
1
1
|
#include <stdlib.h>
|
2
|
+
#include <assert.h>
|
2
3
|
#include "ruby.h"
|
3
4
|
#include "polyphony.h"
|
4
5
|
#include "backend_io_uring_context.h"
|
@@ -15,6 +16,7 @@ const char *op_type_to_str(enum op_type type) {
|
|
15
16
|
case OP_POLL: return "POLL";
|
16
17
|
case OP_ACCEPT: return "ACCEPT";
|
17
18
|
case OP_CONNECT: return "CONNECT";
|
19
|
+
case OP_CHAIN: return "CHAIN";
|
18
20
|
default: return "";
|
19
21
|
};
|
20
22
|
}
|
@@ -35,7 +37,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
35
37
|
ctx = malloc(sizeof(op_context_t));
|
36
38
|
}
|
37
39
|
ctx->id = (++store->last_id);
|
38
|
-
|
40
|
+
// printf("acquire %p %d (%s)\n", ctx, ctx->id, op_type_to_str(type));
|
39
41
|
ctx->prev = NULL;
|
40
42
|
ctx->next = store->taken;
|
41
43
|
if (store->taken) store->taken->prev = ctx;
|
@@ -44,13 +46,21 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
44
46
|
ctx->type = type;
|
45
47
|
ctx->fiber = rb_fiber_current();
|
46
48
|
ctx->resume_value = Qnil;
|
47
|
-
ctx->
|
49
|
+
ctx->ref_count = 2;
|
48
50
|
ctx->result = 0;
|
49
51
|
|
50
52
|
return ctx;
|
51
53
|
}
|
52
54
|
|
53
|
-
|
55
|
+
// returns true if ctx was released
|
56
|
+
inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
57
|
+
// printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
58
|
+
|
59
|
+
assert(ctx->ref_count);
|
60
|
+
|
61
|
+
ctx->ref_count--;
|
62
|
+
if (ctx->ref_count) return 0;
|
63
|
+
|
54
64
|
if (ctx->next) ctx->next->prev = ctx->prev;
|
55
65
|
if (ctx->prev) ctx->prev->next = ctx->next;
|
56
66
|
if (store->taken == ctx) store->taken = ctx->next;
|
@@ -59,6 +69,7 @@ inline void context_store_release(op_context_store_t *store, op_context_t *ctx)
|
|
59
69
|
ctx->next = store->available;
|
60
70
|
if (ctx->next) ctx->next->prev = ctx;
|
61
71
|
store->available = ctx;
|
72
|
+
return 1;
|
62
73
|
}
|
63
74
|
|
64
75
|
void context_store_free(op_context_store_t *store) {
|
@@ -14,14 +14,15 @@ enum op_type {
|
|
14
14
|
OP_TIMEOUT,
|
15
15
|
OP_POLL,
|
16
16
|
OP_ACCEPT,
|
17
|
-
OP_CONNECT
|
17
|
+
OP_CONNECT,
|
18
|
+
OP_CHAIN
|
18
19
|
};
|
19
20
|
|
20
21
|
typedef struct op_context {
|
21
22
|
struct op_context *prev;
|
22
23
|
struct op_context *next;
|
23
24
|
enum op_type type: 16;
|
24
|
-
int
|
25
|
+
unsigned int ref_count : 16;
|
25
26
|
int id;
|
26
27
|
int result;
|
27
28
|
VALUE fiber;
|
@@ -38,17 +39,16 @@ const char *op_type_to_str(enum op_type type);
|
|
38
39
|
|
39
40
|
void context_store_initialize(op_context_store_t *store);
|
40
41
|
op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type);
|
41
|
-
|
42
|
+
int context_store_release(op_context_store_t *store, op_context_t *ctx);
|
42
43
|
void context_store_free(op_context_store_t *store);
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
if (ctx->
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
} \
|
45
|
+
inline unsigned int OP_CONTEXT_RELEASE(op_context_store_t *store, op_context_t *ctx) {
|
46
|
+
int completed = !ctx->ref_count;
|
47
|
+
if (ctx->ref_count)
|
48
|
+
ctx->ref_count -= 1;
|
49
|
+
else
|
50
|
+
context_store_release(store, ctx);
|
51
|
+
return completed;
|
52
52
|
}
|
53
53
|
|
54
54
|
#endif /* BACKEND_IO_URING_CONTEXT_H */
|
@@ -42,7 +42,6 @@ thread.
|
|
42
42
|
#define _GNU_SOURCE 1
|
43
43
|
#endif
|
44
44
|
|
45
|
-
#include <fcntl.h>
|
46
45
|
#include <netdb.h>
|
47
46
|
#include <sys/socket.h>
|
48
47
|
#include <sys/uio.h>
|
@@ -52,58 +51,41 @@ thread.
|
|
52
51
|
#include <stdnoreturn.h>
|
53
52
|
#include <sys/types.h>
|
54
53
|
#include <sys/wait.h>
|
54
|
+
#include <fcntl.h>
|
55
55
|
|
56
56
|
#include "polyphony.h"
|
57
57
|
#include "../libev/ev.h"
|
58
58
|
#include "ruby/io.h"
|
59
59
|
|
60
|
+
#include "../libev/ev.h"
|
61
|
+
#include "backend_common.h"
|
62
|
+
|
60
63
|
VALUE SYM_libev;
|
61
64
|
VALUE SYM_send;
|
62
65
|
VALUE SYM_splice;
|
63
66
|
VALUE SYM_write;
|
64
67
|
|
65
|
-
ID ID_ivar_is_nonblocking;
|
66
|
-
|
67
|
-
// Since we need to ensure that fd's are non-blocking before every I/O
|
68
|
-
// operation, here we improve upon Ruby's rb_io_set_nonblock by caching the
|
69
|
-
// "nonblock" state in an instance variable. Calling rb_ivar_get on every read
|
70
|
-
// is still much cheaper than doing a fcntl syscall on every read! Preliminary
|
71
|
-
// benchmarks (with a "hello world" HTTP server) show throughput is improved
|
72
|
-
// by 10-13%.
|
73
|
-
inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
74
|
-
VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
|
75
|
-
if (is_nonblocking == Qtrue) return;
|
76
|
-
|
77
|
-
rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
|
78
|
-
|
79
|
-
#ifdef _WIN32
|
80
|
-
rb_w32_set_nonblock(fptr->fd);
|
81
|
-
#elif defined(F_GETFL)
|
82
|
-
int oflags = fcntl(fptr->fd, F_GETFL);
|
83
|
-
if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
|
84
|
-
oflags |= O_NONBLOCK;
|
85
|
-
fcntl(fptr->fd, F_SETFL, oflags);
|
86
|
-
#endif
|
87
|
-
}
|
88
|
-
|
89
68
|
typedef struct Backend_t {
|
90
|
-
|
91
|
-
unsigned int currently_polling;
|
92
|
-
unsigned int pending_count;
|
93
|
-
unsigned int poll_no_wait_count;
|
69
|
+
struct Backend_base base;
|
94
70
|
|
95
71
|
// implementation-specific fields
|
96
72
|
struct ev_loop *ev_loop;
|
97
73
|
struct ev_async break_async;
|
98
74
|
} Backend_t;
|
99
75
|
|
76
|
+
static void Backend_mark(void *ptr) {
|
77
|
+
Backend_t *backend = ptr;
|
78
|
+
if (backend->base.idle_block != Qnil)
|
79
|
+
rb_gc_mark(backend->base.idle_block);
|
80
|
+
}
|
81
|
+
|
100
82
|
static size_t Backend_size(const void *ptr) {
|
101
83
|
return sizeof(Backend_t);
|
102
84
|
}
|
103
85
|
|
104
86
|
static const rb_data_type_t Backend_type = {
|
105
87
|
"LibevBackend",
|
106
|
-
{
|
88
|
+
{Backend_mark, 0, Backend_size,},
|
107
89
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
108
90
|
};
|
109
91
|
|
@@ -134,6 +116,8 @@ static VALUE Backend_initialize(VALUE self) {
|
|
134
116
|
Backend_t *backend;
|
135
117
|
|
136
118
|
GetBackend(self, backend);
|
119
|
+
|
120
|
+
initialize_backend_base(&backend->base);
|
137
121
|
backend->ev_loop = libev_new_loop();
|
138
122
|
|
139
123
|
// start async watcher used for breaking a poll op (from another thread)
|
@@ -143,10 +127,6 @@ static VALUE Backend_initialize(VALUE self) {
|
|
143
127
|
// block when no other watcher is active
|
144
128
|
ev_unref(backend->ev_loop);
|
145
129
|
|
146
|
-
backend->currently_polling = 0;
|
147
|
-
backend->pending_count = 0;
|
148
|
-
backend->poll_no_wait_count = 0;
|
149
|
-
|
150
130
|
return Qnil;
|
151
131
|
}
|
152
132
|
|
@@ -176,32 +156,21 @@ VALUE Backend_post_fork(VALUE self) {
|
|
176
156
|
return self;
|
177
157
|
}
|
178
158
|
|
179
|
-
unsigned int Backend_pending_count(VALUE self) {
|
159
|
+
inline unsigned int Backend_pending_count(VALUE self) {
|
180
160
|
Backend_t *backend;
|
181
161
|
GetBackend(self, backend);
|
182
162
|
|
183
|
-
return backend->pending_count;
|
163
|
+
return backend->base.pending_count;
|
184
164
|
}
|
185
165
|
|
186
166
|
VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
|
187
|
-
int is_nowait = nowait == Qtrue;
|
188
167
|
Backend_t *backend;
|
189
168
|
GetBackend(self, backend);
|
190
169
|
|
191
|
-
if (is_nowait) {
|
192
|
-
backend->poll_no_wait_count++;
|
193
|
-
if (backend->poll_no_wait_count < 10) return self;
|
194
|
-
|
195
|
-
long runnable_count = Runqueue_len(runqueue);
|
196
|
-
if (backend->poll_no_wait_count < runnable_count) return self;
|
197
|
-
}
|
198
|
-
|
199
|
-
backend->poll_no_wait_count = 0;
|
200
|
-
|
201
170
|
COND_TRACE(2, SYM_fiber_event_poll_enter, current_fiber);
|
202
|
-
backend->currently_polling = 1;
|
203
|
-
ev_run(backend->ev_loop,
|
204
|
-
backend->currently_polling = 0;
|
171
|
+
backend->base.currently_polling = 1;
|
172
|
+
ev_run(backend->ev_loop, nowait == Qtrue ? EVRUN_NOWAIT : EVRUN_ONCE);
|
173
|
+
backend->base.currently_polling = 0;
|
205
174
|
COND_TRACE(2, SYM_fiber_event_poll_leave, current_fiber);
|
206
175
|
|
207
176
|
return self;
|
@@ -211,7 +180,7 @@ VALUE Backend_wakeup(VALUE self) {
|
|
211
180
|
Backend_t *backend;
|
212
181
|
GetBackend(self, backend);
|
213
182
|
|
214
|
-
if (backend->currently_polling) {
|
183
|
+
if (backend->base.currently_polling) {
|
215
184
|
// Since the loop will run until at least one event has occurred, we signal
|
216
185
|
// the selector's associated async watcher, which will cause the ev loop to
|
217
186
|
// return. In contrast to using `ev_break` to break out of the loop, which
|
@@ -224,10 +193,6 @@ VALUE Backend_wakeup(VALUE self) {
|
|
224
193
|
return Qnil;
|
225
194
|
}
|
226
195
|
|
227
|
-
#include "../libev/ev.h"
|
228
|
-
|
229
|
-
#include "backend_common.h"
|
230
|
-
|
231
196
|
struct libev_io {
|
232
197
|
struct ev_io io;
|
233
198
|
VALUE fiber;
|
@@ -248,7 +213,7 @@ VALUE libev_wait_fd_with_watcher(Backend_t *backend, int fd, struct libev_io *wa
|
|
248
213
|
}
|
249
214
|
ev_io_start(backend->ev_loop, &watcher->io);
|
250
215
|
|
251
|
-
switchpoint_result = backend_await(backend);
|
216
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
252
217
|
|
253
218
|
ev_io_stop(backend->ev_loop, &watcher->io);
|
254
219
|
RB_GC_GUARD(switchpoint_result);
|
@@ -284,7 +249,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
284
249
|
if (underlying_io != Qnil) io = underlying_io;
|
285
250
|
GetOpenFile(io, fptr);
|
286
251
|
rb_io_check_byte_readable(fptr);
|
287
|
-
|
252
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
288
253
|
rectify_io_file_pos(fptr);
|
289
254
|
watcher.fiber = Qnil;
|
290
255
|
OBJ_TAINT(str);
|
@@ -301,7 +266,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
301
266
|
}
|
302
267
|
else {
|
303
268
|
switchpoint_result = backend_snooze();
|
304
|
-
|
305
269
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
306
270
|
|
307
271
|
if (n == 0) break; // EOF
|
@@ -356,7 +320,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
|
|
356
320
|
if (underlying_io != Qnil) io = underlying_io;
|
357
321
|
GetOpenFile(io, fptr);
|
358
322
|
rb_io_check_byte_readable(fptr);
|
359
|
-
|
323
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
360
324
|
rectify_io_file_pos(fptr);
|
361
325
|
watcher.fiber = Qnil;
|
362
326
|
|
@@ -408,7 +372,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
408
372
|
if (underlying_io != Qnil) io = underlying_io;
|
409
373
|
GetOpenFile(io, fptr);
|
410
374
|
rb_io_check_byte_readable(fptr);
|
411
|
-
|
375
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
412
376
|
rectify_io_file_pos(fptr);
|
413
377
|
watcher.fiber = Qnil;
|
414
378
|
|
@@ -456,7 +420,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
456
420
|
GetBackend(self, backend);
|
457
421
|
io = rb_io_get_write_io(io);
|
458
422
|
GetOpenFile(io, fptr);
|
459
|
-
|
423
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
460
424
|
watcher.fiber = Qnil;
|
461
425
|
|
462
426
|
while (left > 0) {
|
@@ -506,7 +470,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
506
470
|
GetBackend(self, backend);
|
507
471
|
io = rb_io_get_write_io(io);
|
508
472
|
GetOpenFile(io, fptr);
|
509
|
-
|
473
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
510
474
|
watcher.fiber = Qnil;
|
511
475
|
|
512
476
|
iov = malloc(iov_count * sizeof(struct iovec));
|
@@ -587,7 +551,7 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
587
551
|
|
588
552
|
GetBackend(self, backend);
|
589
553
|
GetOpenFile(server_socket, fptr);
|
590
|
-
|
554
|
+
io_verify_blocking_mode(fptr, server_socket, Qfalse);
|
591
555
|
watcher.fiber = Qnil;
|
592
556
|
while (1) {
|
593
557
|
fd = accept(fptr->fd, &addr, &len);
|
@@ -615,7 +579,7 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
615
579
|
fp->fd = fd;
|
616
580
|
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
617
581
|
rb_io_ascii8bit_binmode(socket);
|
618
|
-
|
582
|
+
io_verify_blocking_mode(fp, socket, Qfalse);
|
619
583
|
rb_io_synchronized(fp);
|
620
584
|
|
621
585
|
// if (rsock_do_not_reverse_lookup) {
|
@@ -644,7 +608,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
644
608
|
|
645
609
|
GetBackend(self, backend);
|
646
610
|
GetOpenFile(server_socket, fptr);
|
647
|
-
|
611
|
+
io_verify_blocking_mode(fptr, server_socket, Qfalse);
|
648
612
|
watcher.fiber = Qnil;
|
649
613
|
|
650
614
|
while (1) {
|
@@ -672,7 +636,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
672
636
|
fp->fd = fd;
|
673
637
|
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
674
638
|
rb_io_ascii8bit_binmode(socket);
|
675
|
-
|
639
|
+
io_verify_blocking_mode(fp, socket, Qfalse);
|
676
640
|
rb_io_synchronized(fp);
|
677
641
|
|
678
642
|
rb_yield(socket);
|
@@ -700,7 +664,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
700
664
|
|
701
665
|
GetBackend(self, backend);
|
702
666
|
GetOpenFile(sock, fptr);
|
703
|
-
|
667
|
+
io_verify_blocking_mode(fptr, sock, Qfalse);
|
704
668
|
watcher.fiber = Qnil;
|
705
669
|
|
706
670
|
addr.sin_family = AF_INET;
|
@@ -743,7 +707,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
743
707
|
GetBackend(self, backend);
|
744
708
|
io = rb_io_get_write_io(io);
|
745
709
|
GetOpenFile(io, fptr);
|
746
|
-
|
710
|
+
io_verify_blocking_mode(fptr, io, Qfalse);
|
747
711
|
watcher.fiber = Qnil;
|
748
712
|
|
749
713
|
while (left > 0) {
|
@@ -776,10 +740,63 @@ error:
|
|
776
740
|
return RAISE_EXCEPTION(switchpoint_result);
|
777
741
|
}
|
778
742
|
|
743
|
+
struct libev_rw_ctx {
|
744
|
+
int ref_count;
|
745
|
+
VALUE fiber;
|
746
|
+
};
|
747
|
+
|
748
|
+
struct libev_ref_count_io {
|
749
|
+
struct ev_io io;
|
750
|
+
struct libev_rw_ctx *ctx;
|
751
|
+
};
|
752
|
+
|
753
|
+
struct libev_rw_io {
|
754
|
+
struct libev_ref_count_io r;
|
755
|
+
struct libev_ref_count_io w;
|
756
|
+
struct libev_rw_ctx ctx;
|
757
|
+
};
|
758
|
+
|
759
|
+
void Backend_rw_io_callback(EV_P_ ev_io *w, int revents)
|
760
|
+
{
|
761
|
+
struct libev_ref_count_io *watcher = (struct libev_ref_count_io *)w;
|
762
|
+
int ref_count = watcher->ctx->ref_count--;
|
763
|
+
if (!ref_count)
|
764
|
+
Fiber_make_runnable(watcher->ctx->fiber, Qnil);
|
765
|
+
}
|
766
|
+
|
767
|
+
VALUE libev_wait_rw_fd_with_watcher(Backend_t *backend, int r_fd, int w_fd, struct libev_rw_io *watcher) {
|
768
|
+
VALUE switchpoint_result = Qnil;
|
769
|
+
|
770
|
+
if (watcher->ctx.fiber == Qnil) watcher->ctx.fiber = rb_fiber_current();
|
771
|
+
watcher->ctx.ref_count = 0;
|
772
|
+
if (r_fd != -1) {
|
773
|
+
ev_io_init(&watcher->r.io, Backend_rw_io_callback, r_fd, EV_READ);
|
774
|
+
ev_io_start(backend->ev_loop, &watcher->r.io);
|
775
|
+
watcher->r.ctx = &watcher->ctx;
|
776
|
+
watcher->ctx.ref_count++;
|
777
|
+
}
|
778
|
+
if (w_fd != -1) {
|
779
|
+
ev_io_init(&watcher->w.io, Backend_rw_io_callback, w_fd, EV_WRITE);
|
780
|
+
ev_io_start(backend->ev_loop, &watcher->w.io);
|
781
|
+
watcher->w.ctx = &watcher->ctx;
|
782
|
+
watcher->ctx.ref_count++;
|
783
|
+
}
|
784
|
+
|
785
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
786
|
+
|
787
|
+
if (r_fd != -1) ev_io_stop(backend->ev_loop, &watcher->r.io);
|
788
|
+
if (w_fd != -1) ev_io_stop(backend->ev_loop, &watcher->w.io);
|
789
|
+
RB_GC_GUARD(switchpoint_result);
|
790
|
+
return switchpoint_result;
|
791
|
+
}
|
792
|
+
|
793
|
+
|
794
|
+
|
795
|
+
|
779
796
|
#ifdef POLYPHONY_LINUX
|
780
797
|
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
781
798
|
Backend_t *backend;
|
782
|
-
struct
|
799
|
+
struct libev_rw_io watcher;
|
783
800
|
VALUE switchpoint_result = Qnil;
|
784
801
|
VALUE underlying_io;
|
785
802
|
rb_io_t *src_fptr;
|
@@ -791,25 +808,22 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
791
808
|
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
792
809
|
if (underlying_io != Qnil) src = underlying_io;
|
793
810
|
GetOpenFile(src, src_fptr);
|
794
|
-
|
811
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
795
812
|
|
796
813
|
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
797
814
|
if (underlying_io != Qnil) dest = underlying_io;
|
798
815
|
dest = rb_io_get_write_io(dest);
|
799
816
|
GetOpenFile(dest, dest_fptr);
|
800
|
-
|
817
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
801
818
|
|
802
|
-
watcher.fiber = Qnil;
|
819
|
+
watcher.ctx.fiber = Qnil;
|
803
820
|
while (1) {
|
804
821
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
805
822
|
if (len < 0) {
|
806
823
|
int e = errno;
|
807
824
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
808
825
|
|
809
|
-
switchpoint_result =
|
810
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
811
|
-
|
812
|
-
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
826
|
+
switchpoint_result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, dest_fptr->fd, &watcher);
|
813
827
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
814
828
|
}
|
815
829
|
else {
|
@@ -817,12 +831,12 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
817
831
|
}
|
818
832
|
}
|
819
833
|
|
820
|
-
if (watcher.fiber == Qnil) {
|
834
|
+
if (watcher.ctx.fiber == Qnil) {
|
821
835
|
switchpoint_result = backend_snooze();
|
822
836
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
823
837
|
}
|
824
838
|
|
825
|
-
RB_GC_GUARD(watcher.fiber);
|
839
|
+
RB_GC_GUARD(watcher.ctx.fiber);
|
826
840
|
RB_GC_GUARD(switchpoint_result);
|
827
841
|
|
828
842
|
return INT2NUM(len);
|
@@ -832,7 +846,7 @@ error:
|
|
832
846
|
|
833
847
|
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
834
848
|
Backend_t *backend;
|
835
|
-
struct
|
849
|
+
struct libev_rw_io watcher;
|
836
850
|
VALUE switchpoint_result = Qnil;
|
837
851
|
VALUE underlying_io;
|
838
852
|
rb_io_t *src_fptr;
|
@@ -845,25 +859,22 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
845
859
|
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
846
860
|
if (underlying_io != Qnil) src = underlying_io;
|
847
861
|
GetOpenFile(src, src_fptr);
|
848
|
-
|
862
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
849
863
|
|
850
864
|
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
851
865
|
if (underlying_io != Qnil) dest = underlying_io;
|
852
866
|
dest = rb_io_get_write_io(dest);
|
853
867
|
GetOpenFile(dest, dest_fptr);
|
854
|
-
|
868
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
855
869
|
|
856
|
-
watcher.fiber = Qnil;
|
870
|
+
watcher.ctx.fiber = Qnil;
|
857
871
|
while (1) {
|
858
872
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
859
873
|
if (len < 0) {
|
860
874
|
int e = errno;
|
861
875
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
862
876
|
|
863
|
-
switchpoint_result =
|
864
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
865
|
-
|
866
|
-
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
877
|
+
switchpoint_result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, dest_fptr->fd, &watcher);
|
867
878
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
868
879
|
}
|
869
880
|
else if (len == 0) {
|
@@ -874,6 +885,79 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
874
885
|
}
|
875
886
|
}
|
876
887
|
|
888
|
+
if (watcher.ctx.fiber == Qnil) {
|
889
|
+
switchpoint_result = backend_snooze();
|
890
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
891
|
+
}
|
892
|
+
|
893
|
+
RB_GC_GUARD(watcher.ctx.fiber);
|
894
|
+
RB_GC_GUARD(switchpoint_result);
|
895
|
+
|
896
|
+
return INT2NUM(total);
|
897
|
+
error:
|
898
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
899
|
+
}
|
900
|
+
#endif
|
901
|
+
|
902
|
+
VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
903
|
+
Backend_t *backend;
|
904
|
+
struct libev_io watcher;
|
905
|
+
VALUE switchpoint_result = Qnil;
|
906
|
+
VALUE underlying_io;
|
907
|
+
rb_io_t *src_fptr;
|
908
|
+
rb_io_t *dest_fptr;
|
909
|
+
int len = NUM2INT(maxlen);
|
910
|
+
VALUE str = rb_str_new(0, len);
|
911
|
+
char *buf = RSTRING_PTR(str);
|
912
|
+
int left = 0;
|
913
|
+
int total = 0;
|
914
|
+
|
915
|
+
GetBackend(self, backend);
|
916
|
+
|
917
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
918
|
+
if (underlying_io != Qnil) src = underlying_io;
|
919
|
+
GetOpenFile(src, src_fptr);
|
920
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
921
|
+
|
922
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
923
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
924
|
+
dest = rb_io_get_write_io(dest);
|
925
|
+
GetOpenFile(dest, dest_fptr);
|
926
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
927
|
+
|
928
|
+
watcher.fiber = Qnil;
|
929
|
+
|
930
|
+
while (1) {
|
931
|
+
ssize_t n = read(src_fptr->fd, buf, len);
|
932
|
+
if (n < 0) {
|
933
|
+
int e = errno;
|
934
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
935
|
+
|
936
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, src_fptr->fd, &watcher, EV_READ);
|
937
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
938
|
+
}
|
939
|
+
else {
|
940
|
+
total = left = n;
|
941
|
+
break;
|
942
|
+
}
|
943
|
+
}
|
944
|
+
|
945
|
+
while (left > 0) {
|
946
|
+
ssize_t n = write(dest_fptr->fd, buf, left);
|
947
|
+
if (n < 0) {
|
948
|
+
int e = errno;
|
949
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
950
|
+
|
951
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
952
|
+
|
953
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
954
|
+
}
|
955
|
+
else {
|
956
|
+
buf += n;
|
957
|
+
left -= n;
|
958
|
+
}
|
959
|
+
}
|
960
|
+
|
877
961
|
if (watcher.fiber == Qnil) {
|
878
962
|
switchpoint_result = backend_snooze();
|
879
963
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
@@ -881,12 +965,90 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
881
965
|
|
882
966
|
RB_GC_GUARD(watcher.fiber);
|
883
967
|
RB_GC_GUARD(switchpoint_result);
|
968
|
+
RB_GC_GUARD(str);
|
969
|
+
|
970
|
+
return INT2NUM(total);
|
971
|
+
error:
|
972
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
973
|
+
}
|
974
|
+
|
975
|
+
VALUE Backend_fake_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
976
|
+
Backend_t *backend;
|
977
|
+
struct libev_io watcher;
|
978
|
+
VALUE switchpoint_result = Qnil;
|
979
|
+
VALUE underlying_io;
|
980
|
+
rb_io_t *src_fptr;
|
981
|
+
rb_io_t *dest_fptr;
|
982
|
+
int len = NUM2INT(maxlen);
|
983
|
+
VALUE str = rb_str_new(0, len);
|
984
|
+
char *buf = RSTRING_PTR(str);
|
985
|
+
int left = 0;
|
986
|
+
int total = 0;
|
987
|
+
|
988
|
+
GetBackend(self, backend);
|
989
|
+
|
990
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
991
|
+
if (underlying_io != Qnil) src = underlying_io;
|
992
|
+
GetOpenFile(src, src_fptr);
|
993
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
994
|
+
|
995
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
996
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
997
|
+
dest = rb_io_get_write_io(dest);
|
998
|
+
GetOpenFile(dest, dest_fptr);
|
999
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
1000
|
+
|
1001
|
+
watcher.fiber = Qnil;
|
1002
|
+
|
1003
|
+
while (1) {
|
1004
|
+
char *ptr = buf;
|
1005
|
+
while (1) {
|
1006
|
+
ssize_t n = read(src_fptr->fd, ptr, len);
|
1007
|
+
if (n < 0) {
|
1008
|
+
int e = errno;
|
1009
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
1010
|
+
|
1011
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, src_fptr->fd, &watcher, EV_READ);
|
1012
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
1013
|
+
}
|
1014
|
+
else if (n == 0) goto done;
|
1015
|
+
else {
|
1016
|
+
total += n;
|
1017
|
+
left = n;
|
1018
|
+
break;
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
while (left > 0) {
|
1023
|
+
ssize_t n = write(dest_fptr->fd, ptr, left);
|
1024
|
+
if (n < 0) {
|
1025
|
+
int e = errno;
|
1026
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
1027
|
+
|
1028
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
1029
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
1030
|
+
}
|
1031
|
+
else {
|
1032
|
+
ptr += n;
|
1033
|
+
left -= n;
|
1034
|
+
}
|
1035
|
+
}
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
done:
|
1039
|
+
if (watcher.fiber == Qnil) {
|
1040
|
+
switchpoint_result = backend_snooze();
|
1041
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
1042
|
+
}
|
1043
|
+
|
1044
|
+
RB_GC_GUARD(watcher.fiber);
|
1045
|
+
RB_GC_GUARD(switchpoint_result);
|
1046
|
+
RB_GC_GUARD(str);
|
884
1047
|
|
885
1048
|
return INT2NUM(total);
|
886
1049
|
error:
|
887
1050
|
return RAISE_EXCEPTION(switchpoint_result);
|
888
1051
|
}
|
889
|
-
#endif
|
890
1052
|
|
891
1053
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
892
1054
|
Backend_t *backend;
|
@@ -921,7 +1083,7 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
921
1083
|
ev_timer_init(&watcher.timer, Backend_timer_callback, NUM2DBL(duration), 0.);
|
922
1084
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
923
1085
|
|
924
|
-
switchpoint_result = backend_await(backend);
|
1086
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
925
1087
|
|
926
1088
|
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
927
1089
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
@@ -949,7 +1111,7 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
949
1111
|
VALUE switchpoint_result = Qnil;
|
950
1112
|
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
951
1113
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
952
|
-
switchpoint_result = backend_await(backend);
|
1114
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
953
1115
|
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
954
1116
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
955
1117
|
RB_GC_GUARD(switchpoint_result);
|
@@ -1066,7 +1228,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1066
1228
|
ev_child_init(&watcher.child, Backend_child_callback, NUM2INT(pid), 0);
|
1067
1229
|
ev_child_start(backend->ev_loop, &watcher.child);
|
1068
1230
|
|
1069
|
-
switchpoint_result = backend_await(backend);
|
1231
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1070
1232
|
|
1071
1233
|
ev_child_stop(backend->ev_loop, &watcher.child);
|
1072
1234
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
@@ -1088,7 +1250,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
|
|
1088
1250
|
ev_async_init(&async, Backend_async_callback);
|
1089
1251
|
ev_async_start(backend->ev_loop, &async);
|
1090
1252
|
|
1091
|
-
switchpoint_result = backend_await(backend);
|
1253
|
+
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1092
1254
|
|
1093
1255
|
ev_async_stop(backend->ev_loop, &async);
|
1094
1256
|
if (RTEST(raise)) RAISE_IF_EXCEPTION(switchpoint_result);
|
@@ -1113,10 +1275,8 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1113
1275
|
result = Backend_write(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
|
1114
1276
|
else if (op_type == SYM_send && op_len == 4)
|
1115
1277
|
result = Backend_send(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1116
|
-
#ifdef POLYPHONY_LINUX
|
1117
1278
|
else if (op_type == SYM_splice && op_len == 4)
|
1118
1279
|
result = Backend_splice(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1119
|
-
#endif
|
1120
1280
|
else
|
1121
1281
|
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1122
1282
|
}
|
@@ -1125,6 +1285,164 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1125
1285
|
return result;
|
1126
1286
|
}
|
1127
1287
|
|
1288
|
+
VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
1289
|
+
Backend_t *backend;
|
1290
|
+
GetBackend(self, backend);
|
1291
|
+
backend->base.idle_gc_period = NUM2DBL(period);
|
1292
|
+
backend->base.idle_gc_last_time = current_time();
|
1293
|
+
return self;
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
VALUE Backend_idle_block_set(VALUE self, VALUE block) {
|
1297
|
+
Backend_t *backend;
|
1298
|
+
GetBackend(self, backend);
|
1299
|
+
backend->base.idle_block = block;
|
1300
|
+
return self;
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
inline VALUE Backend_run_idle_tasks(VALUE self) {
|
1304
|
+
Backend_t *backend;
|
1305
|
+
GetBackend(self, backend);
|
1306
|
+
backend_run_idle_tasks(&backend->base);
|
1307
|
+
return self;
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
|
1311
|
+
char *buf = RSTRING_PTR(str);
|
1312
|
+
int len = RSTRING_LEN(str);
|
1313
|
+
int left = len;
|
1314
|
+
while (left > 0) {
|
1315
|
+
ssize_t n = write(fd, buf, left);
|
1316
|
+
if (n < 0) {
|
1317
|
+
int err = errno;
|
1318
|
+
if ((err != EWOULDBLOCK && err != EAGAIN)) return err;
|
1319
|
+
|
1320
|
+
*result = libev_wait_rw_fd_with_watcher(backend, -1, fd, watcher);
|
1321
|
+
if (TEST_EXCEPTION(*result)) return -1;
|
1322
|
+
}
|
1323
|
+
else {
|
1324
|
+
buf += n;
|
1325
|
+
left -= n;
|
1326
|
+
}
|
1327
|
+
}
|
1328
|
+
return 0;
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
|
1332
|
+
Backend_t *backend;
|
1333
|
+
GetBackend(self, backend);
|
1334
|
+
int total = 0;
|
1335
|
+
int err = 0;
|
1336
|
+
VALUE result = Qnil;
|
1337
|
+
|
1338
|
+
rb_io_t *src_fptr;
|
1339
|
+
rb_io_t *dest_fptr;
|
1340
|
+
|
1341
|
+
VALUE underlying_io = rb_ivar_get(src, ID_ivar_io);
|
1342
|
+
if (underlying_io != Qnil) src = underlying_io;
|
1343
|
+
GetOpenFile(src, src_fptr);
|
1344
|
+
io_verify_blocking_mode(src_fptr, src, Qfalse);
|
1345
|
+
|
1346
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
1347
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
1348
|
+
dest = rb_io_get_write_io(dest);
|
1349
|
+
GetOpenFile(dest, dest_fptr);
|
1350
|
+
io_verify_blocking_mode(dest_fptr, dest, Qfalse);
|
1351
|
+
|
1352
|
+
struct libev_rw_io watcher;
|
1353
|
+
watcher.ctx.fiber = Qnil;
|
1354
|
+
int maxlen = NUM2INT(chunk_size);
|
1355
|
+
VALUE str = Qnil;
|
1356
|
+
VALUE chunk_len_value = Qnil;
|
1357
|
+
|
1358
|
+
int pipefd[2] = { -1, -1 };
|
1359
|
+
if (pipe(pipefd) == -1) {
|
1360
|
+
err = errno;
|
1361
|
+
goto syscallerror;
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
|
1365
|
+
fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
|
1366
|
+
|
1367
|
+
if (prefix != Qnil) {
|
1368
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
|
1369
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1370
|
+
}
|
1371
|
+
while (1) {
|
1372
|
+
int chunk_len;
|
1373
|
+
// splice to pipe
|
1374
|
+
while (1) {
|
1375
|
+
chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
|
1376
|
+
if (chunk_len < 0) {
|
1377
|
+
err = errno;
|
1378
|
+
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1379
|
+
|
1380
|
+
result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, pipefd[1], &watcher);
|
1381
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1382
|
+
}
|
1383
|
+
else {
|
1384
|
+
break;
|
1385
|
+
}
|
1386
|
+
}
|
1387
|
+
if (chunk_len == 0) break;
|
1388
|
+
|
1389
|
+
total += chunk_len;
|
1390
|
+
chunk_len_value = INT2NUM(chunk_len);
|
1391
|
+
|
1392
|
+
if (chunk_prefix != Qnil) {
|
1393
|
+
VALUE str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1394
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, str, &watcher, &result);
|
1395
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1396
|
+
}
|
1397
|
+
|
1398
|
+
int left = chunk_len;
|
1399
|
+
while (1) {
|
1400
|
+
int n = splice(pipefd[0], 0, dest_fptr->fd, 0, left, 0);
|
1401
|
+
if (n < 0) {
|
1402
|
+
err = errno;
|
1403
|
+
if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
|
1404
|
+
|
1405
|
+
result = libev_wait_rw_fd_with_watcher(backend, pipefd[0], dest_fptr->fd, &watcher);
|
1406
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1407
|
+
}
|
1408
|
+
else {
|
1409
|
+
left -= n;
|
1410
|
+
if (left == 0) break;
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
if (chunk_postfix != Qnil) {
|
1415
|
+
VALUE str = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1416
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, str, &watcher, &result);
|
1417
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1418
|
+
}
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
if (postfix != Qnil) {
|
1422
|
+
int err = splice_chunks_write(backend, dest_fptr->fd, postfix, &watcher, &result);
|
1423
|
+
if (err == -1) goto error; else if (err) goto syscallerror;
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
if (watcher.ctx.fiber == Qnil) {
|
1427
|
+
result = backend_snooze();
|
1428
|
+
if (TEST_EXCEPTION(result)) goto error;
|
1429
|
+
}
|
1430
|
+
RB_GC_GUARD(str);
|
1431
|
+
RB_GC_GUARD(chunk_len_value);
|
1432
|
+
RB_GC_GUARD(result);
|
1433
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1434
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1435
|
+
return INT2NUM(total);
|
1436
|
+
syscallerror:
|
1437
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1438
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1439
|
+
rb_syserr_fail(err, strerror(err));
|
1440
|
+
error:
|
1441
|
+
if (pipefd[0] != -1) close(pipefd[0]);
|
1442
|
+
if (pipefd[1] != -1) close(pipefd[1]);
|
1443
|
+
return RAISE_EXCEPTION(result);
|
1444
|
+
}
|
1445
|
+
|
1128
1446
|
void Init_Backend() {
|
1129
1447
|
ev_set_allocator(xrealloc);
|
1130
1448
|
|
@@ -1139,6 +1457,9 @@ void Init_Backend() {
|
|
1139
1457
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1140
1458
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1141
1459
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1460
|
+
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1461
|
+
rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
|
1462
|
+
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1142
1463
|
|
1143
1464
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1144
1465
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
@@ -1156,6 +1477,9 @@ void Init_Backend() {
|
|
1156
1477
|
#ifdef POLYPHONY_LINUX
|
1157
1478
|
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1158
1479
|
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1480
|
+
#else
|
1481
|
+
rb_define_method(cBackend, "splice", Backend_fake_splice, 3);
|
1482
|
+
rb_define_method(cBackend, "splice_to_eof", Backend_fake_splice_to_eof, 3);
|
1159
1483
|
#endif
|
1160
1484
|
|
1161
1485
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
@@ -1165,7 +1489,6 @@ void Init_Backend() {
|
|
1165
1489
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1166
1490
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1167
1491
|
|
1168
|
-
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1169
1492
|
SYM_libev = ID2SYM(rb_intern("libev"));
|
1170
1493
|
|
1171
1494
|
SYM_send = ID2SYM(rb_intern("send"));
|