polyphony 0.17 → 0.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +11 -3
- data/README.md +18 -18
- data/TODO.md +5 -21
- data/examples/core/channel_echo.rb +3 -3
- data/examples/core/enumerator.rb +1 -1
- data/examples/core/fork.rb +1 -1
- data/examples/core/genserver.rb +1 -1
- data/examples/core/lock.rb +3 -3
- data/examples/core/multiple_spawn.rb +2 -2
- data/examples/core/nested_async.rb +1 -1
- data/examples/core/nested_multiple_spawn.rb +3 -3
- data/examples/core/resource_cancel.rb +1 -1
- data/examples/core/sleep_spawn.rb +2 -2
- data/examples/core/spawn.rb +1 -1
- data/examples/core/spawn_cancel.rb +1 -1
- data/examples/core/spawn_error.rb +4 -4
- data/examples/core/supervisor.rb +1 -1
- data/examples/core/supervisor_with_error.rb +1 -1
- data/examples/core/supervisor_with_manual_move_on.rb +1 -1
- data/examples/core/thread.rb +2 -2
- data/examples/core/thread_cancel.rb +2 -2
- data/examples/core/thread_pool.rb +1 -1
- data/examples/core/throttle.rb +3 -3
- data/examples/core/timeout.rb +10 -0
- data/examples/fs/read.rb +1 -1
- data/examples/http/http_client.rb +1 -1
- data/examples/http/http_get.rb +7 -0
- data/examples/http/http_parse_experiment.rb +118 -0
- data/examples/http/http_proxy.rb +81 -0
- data/examples/http/http_server.rb +15 -4
- data/examples/http/http_server_forked.rb +2 -2
- data/examples/http/http_server_throttled.rb +1 -1
- data/examples/http/http_ws_server.rb +2 -2
- data/examples/http/https_server.rb +5 -1
- data/examples/http/https_wss_server.rb +1 -1
- data/examples/http/rack_server_https_forked.rb +1 -1
- data/examples/interfaces/pg_client.rb +1 -1
- data/examples/interfaces/pg_pool.rb +1 -1
- data/examples/interfaces/redis_channels.rb +5 -5
- data/examples/interfaces/redis_pubsub.rb +2 -2
- data/examples/interfaces/redis_pubsub_perf.rb +3 -3
- data/examples/io/echo_client.rb +2 -2
- data/examples/io/echo_pipe.rb +17 -0
- data/examples/io/echo_server.rb +1 -1
- data/examples/io/echo_server_with_timeout.rb +1 -1
- data/examples/io/httparty.rb +10 -0
- data/examples/io/httparty_multi.rb +29 -0
- data/examples/io/httparty_threaded.rb +25 -0
- data/examples/io/irb.rb +15 -0
- data/examples/io/net-http.rb +15 -0
- data/examples/io/system.rb +1 -1
- data/examples/io/tcpsocket.rb +18 -0
- data/examples/performance/perf_multi_snooze.rb +2 -2
- data/examples/performance/perf_snooze.rb +17 -20
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/ext/ev/ev.h +9 -1
- data/ext/ev/ev_ext.c +4 -1
- data/ext/ev/ev_module.c +36 -22
- data/ext/ev/extconf.rb +1 -1
- data/ext/ev/io.c +23 -23
- data/ext/ev/signal.c +1 -1
- data/ext/ev/socket.c +161 -0
- data/lib/polyphony/core/coprocess.rb +1 -1
- data/lib/polyphony/core/fiber_pool.rb +2 -2
- data/lib/polyphony/core/supervisor.rb +2 -18
- data/lib/polyphony/extensions/io.rb +19 -6
- data/lib/polyphony/extensions/kernel.rb +17 -5
- data/lib/polyphony/extensions/socket.rb +40 -1
- data/lib/polyphony/http/agent.rb +56 -25
- data/lib/polyphony/http/http1_adapter.rb +254 -0
- data/lib/polyphony/http/http2_adapter.rb +157 -0
- data/lib/polyphony/http/{http2_request.rb → request.rb} +25 -22
- data/lib/polyphony/http/server.rb +19 -11
- data/lib/polyphony/net.rb +10 -6
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -5
- data/test/test_coprocess.rb +9 -9
- data/test/test_core.rb +14 -14
- data/test/test_io.rb +4 -4
- data/test/test_kernel.rb +1 -1
- metadata +48 -23
- data/lib/polyphony/http/http1.rb +0 -124
- data/lib/polyphony/http/http1_request.rb +0 -83
- data/lib/polyphony/http/http2.rb +0 -65
data/ext/ev/extconf.rb
CHANGED
data/ext/ev/io.c
CHANGED
@@ -26,7 +26,6 @@ static VALUE EV_IO_initialize(VALUE self, VALUE io, VALUE event_mask);
|
|
26
26
|
|
27
27
|
static VALUE EV_IO_start(VALUE self);
|
28
28
|
static VALUE EV_IO_stop(VALUE self);
|
29
|
-
static VALUE EV_IO_await(VALUE self);
|
30
29
|
|
31
30
|
void EV_IO_callback(ev_loop *ev_loop, struct ev_io *io, int revents);
|
32
31
|
|
@@ -38,9 +37,6 @@ static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io);
|
|
38
37
|
static VALUE IO_write(int argc, VALUE *argv, VALUE io);
|
39
38
|
static VALUE IO_write_chevron(VALUE io, VALUE str);
|
40
39
|
|
41
|
-
static VALUE IO_read_watcher(VALUE self);
|
42
|
-
static VALUE IO_write_watcher(VALUE self);
|
43
|
-
|
44
40
|
void Init_EV_IO() {
|
45
41
|
mEV = rb_define_module("EV");
|
46
42
|
cEV_IO = rb_define_class_under(mEV, "IO", rb_cData);
|
@@ -164,7 +160,7 @@ static VALUE EV_IO_stop(VALUE self) {
|
|
164
160
|
return self;
|
165
161
|
}
|
166
162
|
|
167
|
-
|
163
|
+
VALUE EV_IO_await(VALUE self) {
|
168
164
|
struct EV_IO *io;
|
169
165
|
VALUE ret;
|
170
166
|
|
@@ -221,7 +217,7 @@ struct io_internal_read_struct {
|
|
221
217
|
size_t capa;
|
222
218
|
};
|
223
219
|
|
224
|
-
|
220
|
+
int io_setstrbuf(VALUE *str, long len) {
|
225
221
|
#ifdef _WIN32
|
226
222
|
len = (len + 1) & ~1L; /* round up for wide char */
|
227
223
|
#endif
|
@@ -249,7 +245,7 @@ static void io_shrink_read_string(VALUE str, long n) {
|
|
249
245
|
}
|
250
246
|
}
|
251
247
|
|
252
|
-
|
248
|
+
void io_set_read_length(VALUE str, long n, int shrinkable) {
|
253
249
|
if (RSTRING_LEN(str) != n) {
|
254
250
|
rb_str_modify(str);
|
255
251
|
rb_str_set_len(str, n);
|
@@ -257,17 +253,14 @@ static void io_set_read_length(VALUE str, long n, int shrinkable) {
|
|
257
253
|
}
|
258
254
|
}
|
259
255
|
|
260
|
-
static rb_encoding*
|
261
|
-
io_read_encoding(rb_io_t *fptr)
|
262
|
-
{
|
256
|
+
static rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
263
257
|
if (fptr->encs.enc) {
|
264
258
|
return fptr->encs.enc;
|
265
259
|
}
|
266
260
|
return rb_default_external_encoding();
|
267
261
|
}
|
268
262
|
|
269
|
-
|
270
|
-
{
|
263
|
+
VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
271
264
|
OBJ_TAINT(str);
|
272
265
|
rb_enc_associate(str, io_read_encoding(fptr));
|
273
266
|
return str;
|
@@ -277,6 +270,9 @@ static VALUE io_enc_str(VALUE str, rb_io_t *fptr)
|
|
277
270
|
//////////////////////////////////////////////////////////////////////
|
278
271
|
|
279
272
|
static VALUE IO_read(int argc, VALUE *argv, VALUE io) {
|
273
|
+
VALUE underlying_io = rb_iv_get(io, "@io");
|
274
|
+
if (!NIL_P(underlying_io)) io = underlying_io;
|
275
|
+
|
280
276
|
long len = argc == 1 ? NUM2LONG(argv[0]) : 8192;
|
281
277
|
|
282
278
|
rb_io_t *fptr;
|
@@ -291,7 +287,7 @@ static VALUE IO_read(int argc, VALUE *argv, VALUE io) {
|
|
291
287
|
VALUE str = argc >= 2 ? argv[1] : Qnil;
|
292
288
|
|
293
289
|
shrinkable = io_setstrbuf(&str, len);
|
294
|
-
|
290
|
+
OBJ_TAINT(str);
|
295
291
|
GetOpenFile(io, fptr);
|
296
292
|
rb_io_check_byte_readable(fptr);
|
297
293
|
rb_io_set_nonblock(fptr);
|
@@ -308,8 +304,7 @@ static VALUE IO_read(int argc, VALUE *argv, VALUE io) {
|
|
308
304
|
int e = errno;
|
309
305
|
if ((e == EWOULDBLOCK || e == EAGAIN)) {
|
310
306
|
if (read_watcher == Qnil)
|
311
|
-
|
312
|
-
read_watcher = rb_funcall(io, ID_read_watcher, 0);
|
307
|
+
read_watcher = IO_read_watcher(io);
|
313
308
|
EV_IO_await(read_watcher);
|
314
309
|
}
|
315
310
|
else
|
@@ -337,6 +332,9 @@ static VALUE IO_read(int argc, VALUE *argv, VALUE io) {
|
|
337
332
|
}
|
338
333
|
|
339
334
|
static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io) {
|
335
|
+
VALUE underlying_io = rb_iv_get(io, "@io");
|
336
|
+
if (!NIL_P(underlying_io)) io = underlying_io;
|
337
|
+
|
340
338
|
long len = argc == 1 ? NUM2LONG(argv[0]) : 8192;
|
341
339
|
|
342
340
|
rb_io_t *fptr;
|
@@ -363,10 +361,9 @@ static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io) {
|
|
363
361
|
n = read(fptr->fd, RSTRING_PTR(str), len);
|
364
362
|
if (n < 0) {
|
365
363
|
int e = errno;
|
366
|
-
if (
|
364
|
+
if (e == EWOULDBLOCK || e == EAGAIN) {
|
367
365
|
if (read_watcher == Qnil)
|
368
|
-
|
369
|
-
read_watcher = rb_funcall(io, ID_read_watcher, 0);
|
366
|
+
read_watcher = IO_read_watcher(io);
|
370
367
|
EV_IO_await(read_watcher);
|
371
368
|
}
|
372
369
|
else
|
@@ -387,6 +384,9 @@ static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io) {
|
|
387
384
|
}
|
388
385
|
|
389
386
|
static VALUE IO_write(int argc, VALUE *argv, VALUE io) {
|
387
|
+
VALUE underlying_io = rb_iv_get(io, "@io");
|
388
|
+
if (!NIL_P(underlying_io)) io = underlying_io;
|
389
|
+
|
390
390
|
long i;
|
391
391
|
long n;
|
392
392
|
long total = 0;
|
@@ -413,8 +413,8 @@ static VALUE IO_write(int argc, VALUE *argv, VALUE io) {
|
|
413
413
|
int e = errno;
|
414
414
|
if (e == EWOULDBLOCK || e == EAGAIN) {
|
415
415
|
if (write_watcher == Qnil)
|
416
|
-
|
417
|
-
write_watcher = rb_funcall(io, ID_write_watcher, 0);
|
416
|
+
write_watcher = IO_write_watcher(io);
|
417
|
+
// write_watcher = rb_funcall(io, ID_write_watcher, 0);
|
418
418
|
EV_IO_await(write_watcher);
|
419
419
|
}
|
420
420
|
else {
|
@@ -441,7 +441,7 @@ static VALUE IO_write_chevron(VALUE io, VALUE str) {
|
|
441
441
|
return io;
|
442
442
|
}
|
443
443
|
|
444
|
-
|
444
|
+
VALUE IO_read_watcher(VALUE self) {
|
445
445
|
VALUE watcher = rb_iv_get(self, "@read_watcher");
|
446
446
|
if (watcher == Qnil) {
|
447
447
|
watcher = rb_funcall(cEV_IO, rb_intern("new"), 2, self, ID2SYM(rb_intern("r")));
|
@@ -450,11 +450,11 @@ static VALUE IO_read_watcher(VALUE self) {
|
|
450
450
|
return watcher;
|
451
451
|
}
|
452
452
|
|
453
|
-
|
453
|
+
VALUE IO_write_watcher(VALUE self) {
|
454
454
|
VALUE watcher = rb_iv_get(self, "@write_watcher");
|
455
455
|
if (watcher == Qnil) {
|
456
456
|
watcher = rb_funcall(cEV_IO, rb_intern("new"), 2, self, ID2SYM(rb_intern("w")));
|
457
457
|
rb_iv_set(self, "@write_watcher", watcher);
|
458
458
|
}
|
459
459
|
return watcher;
|
460
|
-
}
|
460
|
+
}
|
data/ext/ev/signal.c
CHANGED
data/ext/ev/socket.c
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
#include "ev.h"
|
2
|
+
#include <sys/socket.h>
|
3
|
+
|
4
|
+
static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE io);
|
5
|
+
static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE io);
|
6
|
+
|
7
|
+
void Init_Socket() {
|
8
|
+
rb_require("socket");
|
9
|
+
VALUE cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
10
|
+
|
11
|
+
rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
|
12
|
+
rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
|
13
|
+
}
|
14
|
+
|
15
|
+
///////////////////////////////////////////////////////////////////////////
|
16
|
+
|
17
|
+
struct rsock_send_arg {
|
18
|
+
int fd, flags;
|
19
|
+
VALUE mesg;
|
20
|
+
struct sockaddr *to;
|
21
|
+
socklen_t tolen;
|
22
|
+
};
|
23
|
+
|
24
|
+
#define StringValue(v) rb_string_value(&(v))
|
25
|
+
#define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
|
26
|
+
|
27
|
+
VALUE
|
28
|
+
rsock_sockaddr_string_value(volatile VALUE *v)
|
29
|
+
{
|
30
|
+
// VALUE val = *v;
|
31
|
+
// if (IS_ADDRINFO(val)) {
|
32
|
+
// *v = addrinfo_to_sockaddr(val);
|
33
|
+
// }
|
34
|
+
StringValue(*v);
|
35
|
+
return *v;
|
36
|
+
}
|
37
|
+
|
38
|
+
#define SockAddrStringValue(v) rsock_sockaddr_string_value(&(v))
|
39
|
+
#define RSTRING_LENINT(str) rb_long2int(RSTRING_LEN(str))
|
40
|
+
#ifndef RSTRING_SOCKLEN
|
41
|
+
# define RSTRING_SOCKLEN (socklen_t)RSTRING_LENINT
|
42
|
+
#endif
|
43
|
+
|
44
|
+
#if defined __APPLE__
|
45
|
+
# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
|
46
|
+
#else
|
47
|
+
# define do_write_retry(code) ret = code
|
48
|
+
#endif
|
49
|
+
|
50
|
+
VALUE
|
51
|
+
rsock_sendto_blocking(void *data)
|
52
|
+
{
|
53
|
+
struct rsock_send_arg *arg = data;
|
54
|
+
VALUE mesg = arg->mesg;
|
55
|
+
ssize_t ret;
|
56
|
+
do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
57
|
+
arg->flags, arg->to, arg->tolen));
|
58
|
+
return (VALUE)ret;
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUE
|
62
|
+
rsock_send_blocking(void *data)
|
63
|
+
{
|
64
|
+
struct rsock_send_arg *arg = data;
|
65
|
+
VALUE mesg = arg->mesg;
|
66
|
+
ssize_t ret;
|
67
|
+
do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
68
|
+
arg->flags));
|
69
|
+
return (VALUE)ret;
|
70
|
+
}
|
71
|
+
|
72
|
+
///////////////////////////////////////////////////////////////////////////
|
73
|
+
|
74
|
+
static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE sock) {
|
75
|
+
VALUE underlying_socket = rb_iv_get(sock, "@socket");
|
76
|
+
if (!NIL_P(underlying_socket)) sock = underlying_socket;
|
77
|
+
struct rsock_send_arg arg;
|
78
|
+
VALUE flags, to;
|
79
|
+
rb_io_t *fptr;
|
80
|
+
ssize_t n;
|
81
|
+
rb_blocking_function_t *func;
|
82
|
+
const char *funcname;
|
83
|
+
VALUE write_watcher = Qnil;
|
84
|
+
|
85
|
+
rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
|
86
|
+
|
87
|
+
StringValue(arg.mesg);
|
88
|
+
if (!NIL_P(to)) {
|
89
|
+
SockAddrStringValue(to);
|
90
|
+
to = rb_str_new4(to);
|
91
|
+
arg.to = (struct sockaddr *)RSTRING_PTR(to);
|
92
|
+
arg.tolen = RSTRING_SOCKLEN(to);
|
93
|
+
func = rsock_sendto_blocking;
|
94
|
+
funcname = "sendto(2)";
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
func = rsock_send_blocking;
|
98
|
+
funcname = "send(2)";
|
99
|
+
}
|
100
|
+
GetOpenFile(sock, fptr);
|
101
|
+
rb_io_set_nonblock(fptr);
|
102
|
+
arg.fd = fptr->fd;
|
103
|
+
arg.flags = NUM2INT(flags);
|
104
|
+
while ((n = (ssize_t)func(&arg)) < 0) {
|
105
|
+
if (write_watcher == Qnil)
|
106
|
+
write_watcher = IO_write_watcher(sock);
|
107
|
+
EV_IO_await(write_watcher);
|
108
|
+
}
|
109
|
+
return SSIZET2NUM(n);
|
110
|
+
}
|
111
|
+
|
112
|
+
static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE sock) {
|
113
|
+
VALUE underlying_socket = rb_iv_get(sock, "@socket");
|
114
|
+
if (!NIL_P(underlying_socket)) sock = underlying_socket;
|
115
|
+
long len = argc >= 1 ? NUM2LONG(argv[0]) : 8192;
|
116
|
+
if (len < 0) {
|
117
|
+
rb_raise(rb_eArgError, "negative length %ld given", len);
|
118
|
+
}
|
119
|
+
|
120
|
+
rb_io_t *fptr;
|
121
|
+
long n;
|
122
|
+
int shrinkable;
|
123
|
+
VALUE read_watcher = Qnil;
|
124
|
+
|
125
|
+
|
126
|
+
VALUE str = argc >= 3 ? argv[2] : Qnil;
|
127
|
+
|
128
|
+
shrinkable = io_setstrbuf(&str, len);
|
129
|
+
OBJ_TAINT(str);
|
130
|
+
GetOpenFile(sock, fptr);
|
131
|
+
// rb_io_set_nonblock(fptr);
|
132
|
+
rb_io_check_byte_readable(fptr);
|
133
|
+
|
134
|
+
if (len == 0)
|
135
|
+
return str;
|
136
|
+
|
137
|
+
while (1) {
|
138
|
+
n = recv(fptr->fd, RSTRING_PTR(str), len, MSG_DONTWAIT);
|
139
|
+
if (n < 0) {
|
140
|
+
int e = errno;
|
141
|
+
if (e == EWOULDBLOCK || e == EAGAIN) {
|
142
|
+
if (read_watcher == Qnil)
|
143
|
+
read_watcher = IO_read_watcher(sock);
|
144
|
+
EV_IO_await(read_watcher);
|
145
|
+
}
|
146
|
+
else
|
147
|
+
rb_syserr_fail(e, strerror(e));
|
148
|
+
// rb_syserr_fail_path(e, fptr->pathv);
|
149
|
+
}
|
150
|
+
else
|
151
|
+
break;
|
152
|
+
}
|
153
|
+
|
154
|
+
io_set_read_length(str, n, shrinkable);
|
155
|
+
io_enc_str(str, fptr);
|
156
|
+
|
157
|
+
if (n == 0)
|
158
|
+
return Qnil;
|
159
|
+
|
160
|
+
return str;
|
161
|
+
}
|
@@ -20,7 +20,7 @@ class Coprocess
|
|
20
20
|
def run(&block2)
|
21
21
|
@caller = caller if Exceptions.debug
|
22
22
|
|
23
|
-
@fiber = FiberPool.
|
23
|
+
@fiber = FiberPool.run do
|
24
24
|
@fiber.coprocess = self
|
25
25
|
@result = (@block || block2).call(self)
|
26
26
|
rescue Exceptions::MoveOn, Exceptions::Stop => e
|
@@ -4,7 +4,7 @@ export :available,
|
|
4
4
|
:checked_out,
|
5
5
|
:reset!,
|
6
6
|
:size,
|
7
|
-
:
|
7
|
+
:run
|
8
8
|
|
9
9
|
require 'fiber'
|
10
10
|
|
@@ -48,7 +48,7 @@ EV.unref
|
|
48
48
|
# Invokes the given block using a fiber taken from the fiber pool. If the pool
|
49
49
|
# is exhausted, a new fiber will be created.
|
50
50
|
# @return [Fiber]
|
51
|
-
def
|
51
|
+
def run(&block)
|
52
52
|
fiber = @pool.empty? ? new_fiber : @pool.shift
|
53
53
|
fiber.next_job = block
|
54
54
|
fiber
|
@@ -25,30 +25,14 @@ class Supervisor
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
|
30
|
-
spawn_coprocess(proc)
|
31
|
-
else
|
32
|
-
spawn_proc(block || proc)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def spawn_coprocess(proc)
|
28
|
+
def spin(proc = nil, &block)
|
29
|
+
proc = Coprocess.new(&(proc || block)) unless proc.is_a?(Coprocess)
|
37
30
|
@coprocesses << proc
|
38
31
|
proc.when_done { task_completed(proc) }
|
39
32
|
proc.run unless proc.running?
|
40
33
|
proc
|
41
34
|
end
|
42
35
|
|
43
|
-
def spawn_proc(proc)
|
44
|
-
@coprocesses << coproc do |coprocess|
|
45
|
-
proc.call(coprocess)
|
46
|
-
task_completed(coprocess)
|
47
|
-
rescue Exception => e
|
48
|
-
task_completed(coprocess)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
36
|
def still_running?
|
53
37
|
!@coprocesses.empty?
|
54
38
|
end
|
@@ -30,18 +30,20 @@ class ::IO
|
|
30
30
|
|
31
31
|
alias_method :orig_read, :read
|
32
32
|
def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
|
33
|
+
opt, length = length, nil if length.is_a?(Hash)
|
33
34
|
File.open(name, opt[:mode] || 'r') do |f|
|
34
35
|
f.seek(offset) if offset
|
35
36
|
length ? f.read(length) : f.read
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
alias_method :orig_readlines, :readlines
|
40
|
-
def readlines(name, sep = $/, limit = nil, getline_args = EMPTY_HASH)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
40
|
+
# alias_method :orig_readlines, :readlines
|
41
|
+
# def readlines(name, sep = $/, limit = nil, getline_args = EMPTY_HASH)
|
42
|
+
# File.open(name, 'r') do |f|
|
43
|
+
# puts "readlines(#{sep.inspect}, #{limit.inspect}, #{getline_args.inspect}"
|
44
|
+
# f.readlines(sep, limit, getline_args)
|
45
|
+
# end
|
46
|
+
# end
|
45
47
|
|
46
48
|
alias_method :orig_write, :write
|
47
49
|
def write(name, string, offset = nil, opt = EMPTY_HASH)
|
@@ -141,4 +143,15 @@ class ::IO
|
|
141
143
|
|
142
144
|
# def readlines(sep = $/, limit = nil, chomp: nil)
|
143
145
|
# end
|
146
|
+
|
147
|
+
def write_nonblock(string, options = {})
|
148
|
+
# STDOUT << '>'
|
149
|
+
write(string, 0)
|
150
|
+
end
|
151
|
+
|
152
|
+
def read_nonblock(maxlen, buf = nil, options = nil)
|
153
|
+
# STDOUT << '<'
|
154
|
+
buf ? readpartial(maxlen, buf) : readpartial(maxlen)
|
155
|
+
end
|
156
|
+
|
144
157
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fiber'
|
4
|
+
require 'timeout'
|
4
5
|
|
5
6
|
CancelScope = import('../core/cancel_scope')
|
6
7
|
Coprocess = import('../core/coprocess')
|
@@ -56,7 +57,7 @@ end
|
|
56
57
|
|
57
58
|
module ::Process
|
58
59
|
def self.detach(pid)
|
59
|
-
|
60
|
+
spin {
|
60
61
|
EV::Child.new(pid).await
|
61
62
|
}
|
62
63
|
end
|
@@ -93,7 +94,7 @@ module ::Kernel
|
|
93
94
|
CancelScope.new(timeout: duration, mode: :cancel).(&block)
|
94
95
|
end
|
95
96
|
|
96
|
-
def
|
97
|
+
def spin(proc = nil, &block)
|
97
98
|
if proc.is_a?(Coprocess)
|
98
99
|
proc.run
|
99
100
|
else
|
@@ -139,10 +140,12 @@ module ::Kernel
|
|
139
140
|
nil
|
140
141
|
end
|
141
142
|
|
142
|
-
def throttled_loop(rate, &block)
|
143
|
+
def throttled_loop(rate, count: nil, &block)
|
143
144
|
throttler = Throttler.new(rate)
|
144
|
-
|
145
|
-
throttler.(&block)
|
145
|
+
if count
|
146
|
+
count.times { throttler.(&block) }
|
147
|
+
else
|
148
|
+
loop { throttler.(&block) }
|
146
149
|
end
|
147
150
|
end
|
148
151
|
|
@@ -155,3 +158,12 @@ module ::Kernel
|
|
155
158
|
end
|
156
159
|
end
|
157
160
|
|
161
|
+
module ::Timeout
|
162
|
+
def self.timeout(sec, klass = nil, message = nil, &block)
|
163
|
+
cancel_after(sec, &block)
|
164
|
+
rescue Exceptions::Cancel => e
|
165
|
+
error = klass ? klass.new(message) : ::Timeout::Error.new
|
166
|
+
error.set_backtrace(e.backtrace)
|
167
|
+
raise error
|
168
|
+
end
|
169
|
+
end
|