polyphony 0.17 → 0.19
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/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
|