polyphony 0.39 → 0.43.1
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 +11 -2
- data/.gitignore +2 -2
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +23 -4
- data/Gemfile.lock +15 -12
- data/README.md +2 -1
- data/Rakefile +3 -3
- data/TODO.md +27 -97
- data/docs/_config.yml +56 -7
- data/docs/_sass/custom/custom.scss +6 -26
- data/docs/_sass/overrides.scss +0 -46
- data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
- data/docs/_user-guide/index.md +9 -0
- data/docs/{user-guide → _user-guide}/web-server.md +0 -0
- data/docs/api-reference/fiber.md +2 -2
- data/docs/api-reference/index.md +9 -0
- data/docs/api-reference/polyphony-process.md +1 -1
- data/docs/api-reference/thread.md +1 -1
- data/docs/faq.md +21 -11
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +10 -0
- data/docs/getting-started/installing.md +2 -6
- data/docs/getting-started/overview.md +486 -0
- data/docs/getting-started/tutorial.md +27 -19
- data/docs/index.md +6 -2
- data/docs/main-concepts/concurrency.md +0 -5
- data/docs/main-concepts/design-principles.md +69 -21
- data/docs/main-concepts/extending.md +1 -1
- data/docs/main-concepts/index.md +9 -0
- data/docs/polyphony-logo.png +0 -0
- data/examples/core/01-spinning-up-fibers.rb +1 -0
- data/examples/core/03-interrupting.rb +4 -1
- data/examples/core/04-handling-signals.rb +19 -0
- data/examples/core/xx-agent.rb +102 -0
- data/examples/core/xx-sleeping.rb +14 -6
- data/examples/io/tunnel.rb +48 -0
- data/examples/io/xx-irb.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
- data/examples/performance/xx-array.rb +11 -0
- data/examples/performance/xx-fiber-switch.rb +9 -0
- data/examples/performance/xx-snooze.rb +15 -0
- data/ext/{gyro → polyphony}/extconf.rb +2 -2
- data/ext/{gyro → polyphony}/fiber.c +17 -23
- data/ext/{gyro → polyphony}/libev.c +0 -0
- data/ext/{gyro → polyphony}/libev.h +0 -0
- data/ext/polyphony/libev_agent.c +718 -0
- data/ext/polyphony/libev_queue.c +216 -0
- data/ext/polyphony/polyphony.c +73 -0
- data/ext/{gyro/gyro.h → polyphony/polyphony.h} +19 -39
- data/ext/polyphony/polyphony_ext.c +21 -0
- data/ext/polyphony/thread.c +200 -0
- data/ext/{gyro → polyphony}/tracing.c +1 -1
- data/lib/polyphony.rb +19 -14
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +6 -5
- data/lib/polyphony/adapters/process.rb +5 -5
- data/lib/polyphony/adapters/trace.rb +28 -28
- data/lib/polyphony/core/channel.rb +3 -3
- data/lib/polyphony/core/exceptions.rb +1 -1
- data/lib/polyphony/core/global_api.rb +13 -11
- data/lib/polyphony/core/resource_pool.rb +3 -3
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +6 -6
- data/lib/polyphony/core/throttler.rb +13 -6
- data/lib/polyphony/event.rb +27 -0
- data/lib/polyphony/extensions/core.rb +22 -14
- data/lib/polyphony/extensions/fiber.rb +4 -4
- data/lib/polyphony/extensions/io.rb +59 -25
- data/lib/polyphony/extensions/openssl.rb +36 -16
- data/lib/polyphony/extensions/socket.rb +28 -10
- data/lib/polyphony/extensions/thread.rb +16 -9
- data/lib/polyphony/net.rb +9 -9
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +4 -4
- data/test/helper.rb +12 -8
- data/test/test_agent.rb +124 -0
- data/test/{test_async.rb → test_event.rb} +15 -7
- data/test/test_ext.rb +25 -4
- data/test/test_fiber.rb +19 -10
- data/test/test_global_api.rb +11 -11
- data/test/test_io.rb +44 -29
- data/test/test_queue.rb +74 -0
- data/test/test_signal.rb +3 -40
- data/test/test_socket.rb +34 -0
- data/test/test_thread.rb +38 -17
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +5 -3
- data/test/test_trace.rb +6 -5
- metadata +41 -43
- data/docs/_includes/nav.html +0 -51
- data/docs/_includes/prevnext.html +0 -17
- data/docs/_layouts/default.html +0 -106
- data/docs/api-reference.md +0 -11
- data/docs/api-reference/gyro-async.md +0 -57
- data/docs/api-reference/gyro-child.md +0 -29
- data/docs/api-reference/gyro-queue.md +0 -44
- data/docs/api-reference/gyro-timer.md +0 -51
- data/docs/api-reference/gyro.md +0 -25
- data/docs/getting-started.md +0 -10
- data/docs/main-concepts.md +0 -10
- data/docs/user-guide.md +0 -10
- data/examples/core/forever_sleep.rb +0 -19
- data/ext/gyro/async.c +0 -162
- data/ext/gyro/child.c +0 -141
- data/ext/gyro/gyro.c +0 -103
- data/ext/gyro/gyro_ext.c +0 -33
- data/ext/gyro/io.c +0 -489
- data/ext/gyro/queue.c +0 -142
- data/ext/gyro/selector.c +0 -228
- data/ext/gyro/signal.c +0 -133
- data/ext/gyro/socket.c +0 -210
- data/ext/gyro/thread.c +0 -308
- data/ext/gyro/timer.c +0 -151
- data/test/test_timer.rb +0 -32
data/ext/gyro/gyro.c
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
|
3
|
-
VALUE mGyro;
|
4
|
-
|
5
|
-
ID ID_call;
|
6
|
-
ID ID_caller;
|
7
|
-
ID ID_clear;
|
8
|
-
ID ID_each;
|
9
|
-
ID ID_empty;
|
10
|
-
ID ID_inspect;
|
11
|
-
ID ID_new;
|
12
|
-
ID ID_pop;
|
13
|
-
ID ID_push;
|
14
|
-
ID ID_raise;
|
15
|
-
ID ID_ivar_running;
|
16
|
-
ID ID_ivar_thread;
|
17
|
-
ID ID_runnable;
|
18
|
-
ID ID_runnable_value;
|
19
|
-
ID ID_size;
|
20
|
-
ID ID_signal;
|
21
|
-
ID ID_switch_fiber;
|
22
|
-
ID ID_transfer;
|
23
|
-
ID ID_R;
|
24
|
-
ID ID_W;
|
25
|
-
ID ID_RW;
|
26
|
-
|
27
|
-
static VALUE Gyro_break_set(VALUE self) {
|
28
|
-
// break_flag = 1;
|
29
|
-
ev_break(Gyro_Selector_current_thread_ev_loop(), EVBREAK_ALL);
|
30
|
-
return Qnil;
|
31
|
-
}
|
32
|
-
|
33
|
-
// static VALUE Gyro_break_get(VALUE self) {
|
34
|
-
// return (break_flag == 0) ? Qfalse : Qtrue;
|
35
|
-
// }
|
36
|
-
|
37
|
-
VALUE Gyro_snooze(VALUE self) {
|
38
|
-
VALUE fiber = rb_fiber_current();
|
39
|
-
Fiber_make_runnable(fiber, Qnil);
|
40
|
-
|
41
|
-
VALUE ret = Thread_switch_fiber(rb_thread_current());
|
42
|
-
TEST_RESUME_EXCEPTION(ret);
|
43
|
-
RB_GC_GUARD(ret);
|
44
|
-
return ret;
|
45
|
-
}
|
46
|
-
|
47
|
-
static VALUE Gyro_ref(VALUE self) {
|
48
|
-
return Thread_ref(rb_thread_current());
|
49
|
-
}
|
50
|
-
|
51
|
-
static VALUE Gyro_unref(VALUE self) {
|
52
|
-
return Thread_unref(rb_thread_current());
|
53
|
-
}
|
54
|
-
|
55
|
-
static VALUE Gyro_suspend(VALUE self) {
|
56
|
-
VALUE ret = Thread_switch_fiber(rb_thread_current());
|
57
|
-
|
58
|
-
TEST_RESUME_EXCEPTION(ret);
|
59
|
-
RB_GC_GUARD(ret);
|
60
|
-
return ret;
|
61
|
-
}
|
62
|
-
|
63
|
-
VALUE Gyro_trace(VALUE self, VALUE enabled) {
|
64
|
-
__tracing_enabled__ = RTEST(enabled) ? 1 : 0;
|
65
|
-
return Qnil;
|
66
|
-
}
|
67
|
-
|
68
|
-
void Init_Gyro() {
|
69
|
-
mGyro = rb_define_module("Gyro");
|
70
|
-
|
71
|
-
rb_define_singleton_method(mGyro, "ref", Gyro_ref, 0);
|
72
|
-
rb_define_singleton_method(mGyro, "unref", Gyro_unref, 0);
|
73
|
-
rb_define_singleton_method(mGyro, "trace", Gyro_trace, 1);
|
74
|
-
|
75
|
-
rb_define_singleton_method(mGyro, "break!", Gyro_break_set, 0);
|
76
|
-
// rb_define_singleton_method(mGyro, "break?", Gyro_break_get, 0);
|
77
|
-
|
78
|
-
rb_define_global_function("snooze", Gyro_snooze, 0);
|
79
|
-
rb_define_global_function("suspend", Gyro_suspend, 0);
|
80
|
-
|
81
|
-
ID_call = rb_intern("call");
|
82
|
-
ID_caller = rb_intern("caller");
|
83
|
-
ID_clear = rb_intern("clear");
|
84
|
-
ID_each = rb_intern("each");
|
85
|
-
ID_empty = rb_intern("empty?");
|
86
|
-
ID_inspect = rb_intern("inspect");
|
87
|
-
ID_ivar_running = rb_intern("@running");
|
88
|
-
ID_ivar_thread = rb_intern("@thread");
|
89
|
-
ID_new = rb_intern("new");
|
90
|
-
ID_pop = rb_intern("pop");
|
91
|
-
ID_push = rb_intern("push");
|
92
|
-
ID_raise = rb_intern("raise");
|
93
|
-
ID_runnable = rb_intern("runnable");
|
94
|
-
ID_runnable_value = rb_intern("runnable_value");
|
95
|
-
ID_signal = rb_intern("signal");
|
96
|
-
ID_size = rb_intern("size");
|
97
|
-
ID_switch_fiber = rb_intern("switch_fiber");
|
98
|
-
ID_transfer = rb_intern("transfer");
|
99
|
-
|
100
|
-
ID_R = rb_intern("r");
|
101
|
-
ID_RW = rb_intern("rw");
|
102
|
-
ID_W = rb_intern("w");
|
103
|
-
}
|
data/ext/gyro/gyro_ext.c
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
|
3
|
-
void Init_Fiber();
|
4
|
-
void Init_Gyro();
|
5
|
-
void Init_Gyro_Async();
|
6
|
-
void Init_Gyro_Child();
|
7
|
-
void Init_Gyro_IO();
|
8
|
-
void Init_Gyro_Queue();
|
9
|
-
void Init_Gyro_Selector();
|
10
|
-
void Init_Gyro_Signal();
|
11
|
-
void Init_Gyro_Timer();
|
12
|
-
void Init_Socket();
|
13
|
-
void Init_Thread();
|
14
|
-
void Init_Tracing();
|
15
|
-
|
16
|
-
void Init_gyro_ext() {
|
17
|
-
ev_set_allocator(xrealloc);
|
18
|
-
|
19
|
-
Init_Gyro();
|
20
|
-
Init_Gyro_Async();
|
21
|
-
Init_Gyro_Child();
|
22
|
-
Init_Gyro_IO();
|
23
|
-
Init_Gyro_Queue();
|
24
|
-
Init_Gyro_Selector();
|
25
|
-
Init_Gyro_Signal();
|
26
|
-
Init_Gyro_Timer();
|
27
|
-
|
28
|
-
Init_Fiber();
|
29
|
-
Init_Socket();
|
30
|
-
Init_Thread();
|
31
|
-
|
32
|
-
Init_Tracing();
|
33
|
-
}
|
data/ext/gyro/io.c
DELETED
@@ -1,489 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
|
3
|
-
#ifdef GetReadFile
|
4
|
-
# define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
5
|
-
#else
|
6
|
-
# define FPTR_TO_FD(fptr) fptr->fd
|
7
|
-
#endif /* GetReadFile */
|
8
|
-
|
9
|
-
struct Gyro_IO {
|
10
|
-
struct ev_io ev_io;
|
11
|
-
struct ev_loop *ev_loop;
|
12
|
-
int active;
|
13
|
-
VALUE self;
|
14
|
-
VALUE fiber;
|
15
|
-
VALUE selector;
|
16
|
-
};
|
17
|
-
|
18
|
-
VALUE cGyro_IO = Qnil;
|
19
|
-
|
20
|
-
ID ID_ivar_read_watcher;
|
21
|
-
ID ID_ivar_write_watcher;
|
22
|
-
VALUE SYM_r;
|
23
|
-
VALUE SYM_w;
|
24
|
-
|
25
|
-
static void Gyro_IO_mark(void *ptr) {
|
26
|
-
struct Gyro_IO *io = ptr;
|
27
|
-
if (io->fiber != Qnil) {
|
28
|
-
rb_gc_mark(io->fiber);
|
29
|
-
}
|
30
|
-
if (io->selector != Qnil) {
|
31
|
-
rb_gc_mark(io->selector);
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
static void Gyro_IO_free(void *ptr) {
|
36
|
-
struct Gyro_IO *io = ptr;
|
37
|
-
switch (io->active) {
|
38
|
-
case GYRO_WATCHER_POST_FORK:
|
39
|
-
return;
|
40
|
-
case 1:
|
41
|
-
ev_clear_pending(io->ev_loop, &io->ev_io);
|
42
|
-
ev_io_stop(io->ev_loop, &io->ev_io);
|
43
|
-
default:
|
44
|
-
xfree(io);
|
45
|
-
}
|
46
|
-
}
|
47
|
-
|
48
|
-
static size_t Gyro_IO_size(const void *ptr) {
|
49
|
-
return sizeof(struct Gyro_IO);
|
50
|
-
}
|
51
|
-
|
52
|
-
static const rb_data_type_t Gyro_IO_type = {
|
53
|
-
"Gyro_IO",
|
54
|
-
{Gyro_IO_mark, Gyro_IO_free, Gyro_IO_size,},
|
55
|
-
0, 0, 0
|
56
|
-
};
|
57
|
-
|
58
|
-
static VALUE Gyro_IO_allocate(VALUE klass) {
|
59
|
-
struct Gyro_IO *io = ALLOC(struct Gyro_IO);
|
60
|
-
|
61
|
-
return TypedData_Wrap_Struct(klass, &Gyro_IO_type, io);
|
62
|
-
}
|
63
|
-
|
64
|
-
inline void io_activate(struct Gyro_IO *io) {
|
65
|
-
if (io->active) return;
|
66
|
-
|
67
|
-
io->active = 1;
|
68
|
-
io->fiber = rb_fiber_current();
|
69
|
-
io->selector = Thread_current_event_selector();
|
70
|
-
io->ev_loop = Gyro_Selector_ev_loop(io->selector);
|
71
|
-
Gyro_Selector_add_active_watcher(io->selector, io->self);
|
72
|
-
ev_io_start(io->ev_loop, &io->ev_io);
|
73
|
-
}
|
74
|
-
|
75
|
-
inline void io_deactivate(struct Gyro_IO *io) {
|
76
|
-
if (!io->active) return;
|
77
|
-
|
78
|
-
ev_io_stop(io->ev_loop, &io->ev_io);
|
79
|
-
Gyro_Selector_remove_active_watcher(io->selector, io->self);
|
80
|
-
io->active = 0;
|
81
|
-
io->ev_loop = 0;
|
82
|
-
io->selector = Qnil;
|
83
|
-
io->fiber = Qnil;
|
84
|
-
}
|
85
|
-
|
86
|
-
void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *ev_io, int revents) {
|
87
|
-
struct Gyro_IO *io = (struct Gyro_IO*)ev_io;
|
88
|
-
|
89
|
-
Fiber_make_runnable(io->fiber, Qnil);
|
90
|
-
io_deactivate(io);
|
91
|
-
}
|
92
|
-
|
93
|
-
static int Gyro_IO_symbol2event_mask(VALUE sym) {
|
94
|
-
ID sym_id;
|
95
|
-
|
96
|
-
if (NIL_P(sym)) {
|
97
|
-
return 0;
|
98
|
-
}
|
99
|
-
|
100
|
-
sym_id = SYM2ID(sym);
|
101
|
-
|
102
|
-
if(sym_id == ID_R) {
|
103
|
-
return EV_READ;
|
104
|
-
} else if(sym_id == ID_W) {
|
105
|
-
return EV_WRITE;
|
106
|
-
} else if(sym_id == ID_RW) {
|
107
|
-
return EV_READ | EV_WRITE;
|
108
|
-
} else {
|
109
|
-
rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
|
110
|
-
RSTRING_PTR(rb_funcall(sym, ID_inspect, 0)));
|
111
|
-
}
|
112
|
-
}
|
113
|
-
|
114
|
-
#define GetGyro_IO(obj, io) TypedData_Get_Struct((obj), struct Gyro_IO, &Gyro_IO_type, (io))
|
115
|
-
|
116
|
-
static const char * S_IO = "IO";
|
117
|
-
static const char * S_to_io = "to_io";
|
118
|
-
|
119
|
-
static VALUE Gyro_IO_initialize(VALUE self, VALUE io_obj, VALUE event_mask) {
|
120
|
-
struct Gyro_IO *io;
|
121
|
-
rb_io_t *fptr;
|
122
|
-
|
123
|
-
GetGyro_IO(self, io);
|
124
|
-
|
125
|
-
io->self = self;
|
126
|
-
io->fiber = Qnil;
|
127
|
-
io->selector = Qnil;
|
128
|
-
io->active = 0;
|
129
|
-
io->ev_loop = 0;
|
130
|
-
|
131
|
-
int fd;
|
132
|
-
if (NIL_P(io_obj)) {
|
133
|
-
fd = 0;
|
134
|
-
}
|
135
|
-
else {
|
136
|
-
GetOpenFile(rb_convert_type(io_obj, T_FILE, S_IO, S_to_io), fptr);
|
137
|
-
fd = FPTR_TO_FD(fptr);
|
138
|
-
}
|
139
|
-
int events = Gyro_IO_symbol2event_mask(event_mask);
|
140
|
-
|
141
|
-
ev_io_init(&io->ev_io, Gyro_IO_callback, fd, events);
|
142
|
-
|
143
|
-
return Qnil;
|
144
|
-
}
|
145
|
-
|
146
|
-
VALUE Gyro_IO_await(VALUE self) {
|
147
|
-
struct Gyro_IO *io;
|
148
|
-
GetGyro_IO(self, io);
|
149
|
-
|
150
|
-
io_activate(io);
|
151
|
-
VALUE ret = Gyro_switchpoint();
|
152
|
-
io_deactivate(io);
|
153
|
-
|
154
|
-
TEST_RESUME_EXCEPTION(ret);
|
155
|
-
RB_GC_GUARD(ret);
|
156
|
-
return ret;
|
157
|
-
}
|
158
|
-
|
159
|
-
VALUE Gyro_IO_deactivate_post_fork(VALUE self) {
|
160
|
-
struct Gyro_IO *io;
|
161
|
-
GetGyro_IO(self, io);
|
162
|
-
|
163
|
-
if (io->active)
|
164
|
-
io->active = GYRO_WATCHER_POST_FORK;
|
165
|
-
|
166
|
-
return self;
|
167
|
-
}
|
168
|
-
|
169
|
-
VALUE Gyro_IO_auto_io(int fd, int events) {
|
170
|
-
VALUE watcher = Fiber_auto_io(rb_fiber_current());
|
171
|
-
struct Gyro_IO *io;
|
172
|
-
GetGyro_IO(watcher, io);
|
173
|
-
|
174
|
-
ev_io_set(&io->ev_io, fd, events);
|
175
|
-
|
176
|
-
RB_GC_GUARD(watcher);
|
177
|
-
return watcher;
|
178
|
-
}
|
179
|
-
|
180
|
-
|
181
|
-
//////////////////////////////////////////////////////////////////////
|
182
|
-
//////////////////////////////////////////////////////////////////////
|
183
|
-
// the following is copied verbatim from the Ruby source code (io.c)
|
184
|
-
struct io_internal_read_struct {
|
185
|
-
int fd;
|
186
|
-
int nonblock;
|
187
|
-
void *buf;
|
188
|
-
size_t capa;
|
189
|
-
};
|
190
|
-
|
191
|
-
int io_setstrbuf(VALUE *str, long len) {
|
192
|
-
#ifdef _WIN32
|
193
|
-
len = (len + 1) & ~1L; /* round up for wide char */
|
194
|
-
#endif
|
195
|
-
if (NIL_P(*str)) {
|
196
|
-
*str = rb_str_new(0, len);
|
197
|
-
return 1;
|
198
|
-
}
|
199
|
-
else {
|
200
|
-
VALUE s = StringValue(*str);
|
201
|
-
long clen = RSTRING_LEN(s);
|
202
|
-
if (clen >= len) {
|
203
|
-
rb_str_modify(s);
|
204
|
-
return 0;
|
205
|
-
}
|
206
|
-
len -= clen;
|
207
|
-
}
|
208
|
-
rb_str_modify_expand(*str, len);
|
209
|
-
return 0;
|
210
|
-
}
|
211
|
-
|
212
|
-
#define MAX_REALLOC_GAP 4096
|
213
|
-
static void io_shrink_read_string(VALUE str, long n) {
|
214
|
-
if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
|
215
|
-
rb_str_resize(str, n);
|
216
|
-
}
|
217
|
-
}
|
218
|
-
|
219
|
-
void io_set_read_length(VALUE str, long n, int shrinkable) {
|
220
|
-
if (RSTRING_LEN(str) != n) {
|
221
|
-
rb_str_modify(str);
|
222
|
-
rb_str_set_len(str, n);
|
223
|
-
if (shrinkable) io_shrink_read_string(str, n);
|
224
|
-
}
|
225
|
-
}
|
226
|
-
|
227
|
-
static rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
228
|
-
if (fptr->encs.enc) {
|
229
|
-
return fptr->encs.enc;
|
230
|
-
}
|
231
|
-
return rb_default_external_encoding();
|
232
|
-
}
|
233
|
-
|
234
|
-
VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
235
|
-
OBJ_TAINT(str);
|
236
|
-
rb_enc_associate(str, io_read_encoding(fptr));
|
237
|
-
return str;
|
238
|
-
}
|
239
|
-
|
240
|
-
//////////////////////////////////////////////////////////////////////
|
241
|
-
//////////////////////////////////////////////////////////////////////
|
242
|
-
|
243
|
-
static VALUE IO_read(int argc, VALUE *argv, VALUE io) {
|
244
|
-
VALUE underlying_io = rb_iv_get(io, "@io");
|
245
|
-
if (!NIL_P(underlying_io)) io = underlying_io;
|
246
|
-
|
247
|
-
long len = argc == 1 ? NUM2LONG(argv[0]) : (1 << 30);
|
248
|
-
|
249
|
-
rb_io_t *fptr;
|
250
|
-
long n;
|
251
|
-
int shrinkable;
|
252
|
-
VALUE read_watcher = Qnil;
|
253
|
-
|
254
|
-
if (len < 0) {
|
255
|
-
rb_raise(rb_eArgError, "negative length %ld given", len);
|
256
|
-
}
|
257
|
-
|
258
|
-
VALUE str = argc >= 2 ? argv[1] : Qnil;
|
259
|
-
|
260
|
-
shrinkable = io_setstrbuf(&str, len);
|
261
|
-
OBJ_TAINT(str);
|
262
|
-
GetOpenFile(io, fptr);
|
263
|
-
rb_io_check_byte_readable(fptr);
|
264
|
-
rb_io_set_nonblock(fptr);
|
265
|
-
|
266
|
-
if (len == 0)
|
267
|
-
return str;
|
268
|
-
|
269
|
-
char *buf = RSTRING_PTR(str);
|
270
|
-
long total = 0;
|
271
|
-
|
272
|
-
while (1) {
|
273
|
-
n = read(fptr->fd, buf, len);
|
274
|
-
if (n < 0) {
|
275
|
-
int e = errno;
|
276
|
-
if ((e == EWOULDBLOCK || e == EAGAIN)) {
|
277
|
-
if (NIL_P(read_watcher))
|
278
|
-
read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
|
279
|
-
Gyro_IO_await(read_watcher);
|
280
|
-
}
|
281
|
-
else
|
282
|
-
rb_syserr_fail(e, strerror(e));
|
283
|
-
// rb_syserr_fail_path(e, fptr->pathv);
|
284
|
-
}
|
285
|
-
else if (n == 0)
|
286
|
-
break;
|
287
|
-
else {
|
288
|
-
total = total + n;
|
289
|
-
buf += n;
|
290
|
-
len -= n;
|
291
|
-
if (len == 0)
|
292
|
-
break;
|
293
|
-
}
|
294
|
-
}
|
295
|
-
|
296
|
-
if (total == 0)
|
297
|
-
return Qnil;
|
298
|
-
|
299
|
-
io_set_read_length(str, total, shrinkable);
|
300
|
-
io_enc_str(str, fptr);
|
301
|
-
|
302
|
-
return str;
|
303
|
-
}
|
304
|
-
|
305
|
-
#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
|
306
|
-
#define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(size_t)(n))
|
307
|
-
|
308
|
-
static long
|
309
|
-
read_buffered_data(char *ptr, long len, rb_io_t *fptr)
|
310
|
-
{
|
311
|
-
int n;
|
312
|
-
|
313
|
-
n = READ_DATA_PENDING_COUNT(fptr);
|
314
|
-
if (n <= 0) return 0;
|
315
|
-
if (n > len) n = (int)len;
|
316
|
-
MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
|
317
|
-
fptr->rbuf.off += n;
|
318
|
-
fptr->rbuf.len -= n;
|
319
|
-
return n;
|
320
|
-
}
|
321
|
-
|
322
|
-
static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io) {
|
323
|
-
VALUE underlying_io = rb_iv_get(io, "@io");
|
324
|
-
if (!NIL_P(underlying_io)) io = underlying_io;
|
325
|
-
|
326
|
-
long len = argc >= 1 ? NUM2LONG(argv[0]) : 8192;
|
327
|
-
|
328
|
-
rb_io_t *fptr;
|
329
|
-
long n;
|
330
|
-
int shrinkable;
|
331
|
-
VALUE read_watcher = Qnil;
|
332
|
-
|
333
|
-
if (len < 0) {
|
334
|
-
rb_raise(rb_eArgError, "negative length %ld given", len);
|
335
|
-
}
|
336
|
-
|
337
|
-
VALUE str = argc >= 2 ? argv[1] : Qnil;
|
338
|
-
|
339
|
-
shrinkable = io_setstrbuf(&str, len);
|
340
|
-
OBJ_TAINT(str);
|
341
|
-
GetOpenFile(io, fptr);
|
342
|
-
rb_io_set_nonblock(fptr);
|
343
|
-
rb_io_check_byte_readable(fptr);
|
344
|
-
|
345
|
-
if (len == 0)
|
346
|
-
return str;
|
347
|
-
|
348
|
-
n = read_buffered_data(RSTRING_PTR(str), len, fptr);
|
349
|
-
if (n <= 0) {
|
350
|
-
while (1) {
|
351
|
-
n = read(fptr->fd, RSTRING_PTR(str), len);
|
352
|
-
if (n < 0) {
|
353
|
-
int e = errno;
|
354
|
-
if (e == EWOULDBLOCK || e == EAGAIN) {
|
355
|
-
if (NIL_P(read_watcher))
|
356
|
-
read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
|
357
|
-
Gyro_IO_await(read_watcher);
|
358
|
-
}
|
359
|
-
else
|
360
|
-
rb_syserr_fail(e, strerror(e));
|
361
|
-
// rb_syserr_fail_path(e, fptr->pathv);
|
362
|
-
}
|
363
|
-
else
|
364
|
-
break;
|
365
|
-
}
|
366
|
-
}
|
367
|
-
|
368
|
-
io_set_read_length(str, n, shrinkable);
|
369
|
-
io_enc_str(str, fptr);
|
370
|
-
|
371
|
-
// ensure yielding to reactor if haven't yielded while reading
|
372
|
-
// if (read_watcher == Qnil) {
|
373
|
-
// Gyro_snooze(Qnil);
|
374
|
-
// }
|
375
|
-
|
376
|
-
if (n == 0)
|
377
|
-
return Qnil;
|
378
|
-
|
379
|
-
return str;
|
380
|
-
}
|
381
|
-
|
382
|
-
static VALUE IO_write(int argc, VALUE *argv, VALUE io) {
|
383
|
-
VALUE underlying_io = rb_iv_get(io, "@io");
|
384
|
-
if (!NIL_P(underlying_io)) io = underlying_io;
|
385
|
-
|
386
|
-
long i;
|
387
|
-
long n;
|
388
|
-
long total = 0;
|
389
|
-
rb_io_t *fptr;
|
390
|
-
|
391
|
-
io = rb_io_get_write_io(io);
|
392
|
-
VALUE write_watcher = Qnil;
|
393
|
-
|
394
|
-
GetOpenFile(io, fptr);
|
395
|
-
rb_io_check_writable(fptr);
|
396
|
-
rb_io_set_nonblock(fptr);
|
397
|
-
|
398
|
-
for (i = 0; i < argc; i++) {
|
399
|
-
VALUE str = argv[i];
|
400
|
-
if (!RB_TYPE_P(str, T_STRING))
|
401
|
-
str = rb_obj_as_string(str);
|
402
|
-
char *buf = RSTRING_PTR(str);
|
403
|
-
long len = RSTRING_LEN(str);
|
404
|
-
RB_GC_GUARD(str);
|
405
|
-
while (1) {
|
406
|
-
n = write(fptr->fd, buf, len);
|
407
|
-
|
408
|
-
if (n < 0) {
|
409
|
-
int e = errno;
|
410
|
-
if (e == EWOULDBLOCK || e == EAGAIN) {
|
411
|
-
if (NIL_P(write_watcher))
|
412
|
-
write_watcher = Gyro_IO_auto_io(fptr->fd, EV_WRITE);
|
413
|
-
Gyro_IO_await(write_watcher);
|
414
|
-
}
|
415
|
-
else {
|
416
|
-
rb_syserr_fail(e, strerror(e));
|
417
|
-
// rb_syserr_fail_path(e, fptr->pathv);
|
418
|
-
}
|
419
|
-
}
|
420
|
-
else {
|
421
|
-
total += n;
|
422
|
-
if (n < len) {
|
423
|
-
buf += n;
|
424
|
-
len -= n;
|
425
|
-
}
|
426
|
-
else break;
|
427
|
-
}
|
428
|
-
}
|
429
|
-
}
|
430
|
-
|
431
|
-
// ensure yielding to reactor if haven't yielded while writing
|
432
|
-
// if (write_watcher == Qnil) {
|
433
|
-
// Gyro_snooze(Qnil);
|
434
|
-
// }
|
435
|
-
|
436
|
-
return LONG2FIX(total);
|
437
|
-
}
|
438
|
-
|
439
|
-
static VALUE IO_write_chevron(VALUE io, VALUE str) {
|
440
|
-
IO_write(1, &str, io);
|
441
|
-
return io;
|
442
|
-
}
|
443
|
-
|
444
|
-
VALUE IO_read_watcher(VALUE self) {
|
445
|
-
VALUE watcher = rb_ivar_get(self, ID_ivar_read_watcher);
|
446
|
-
if (watcher == Qnil) {
|
447
|
-
VALUE args[] = {self, SYM_r};
|
448
|
-
watcher = rb_class_new_instance(2, args, cGyro_IO);
|
449
|
-
rb_ivar_set(self, ID_ivar_read_watcher, watcher);
|
450
|
-
}
|
451
|
-
return watcher;
|
452
|
-
}
|
453
|
-
|
454
|
-
VALUE IO_write_watcher(VALUE self) {
|
455
|
-
VALUE watcher = rb_ivar_get(self, ID_ivar_write_watcher);
|
456
|
-
if (watcher == Qnil) {
|
457
|
-
VALUE args[] = {self, SYM_w};
|
458
|
-
watcher = rb_class_new_instance(2, args, cGyro_IO);
|
459
|
-
rb_ivar_set(self, ID_ivar_write_watcher, watcher);
|
460
|
-
}
|
461
|
-
return watcher;
|
462
|
-
}
|
463
|
-
|
464
|
-
void Init_Gyro_IO() {
|
465
|
-
cGyro_IO = rb_define_class_under(mGyro, "IO", rb_cData);
|
466
|
-
rb_define_alloc_func(cGyro_IO, Gyro_IO_allocate);
|
467
|
-
|
468
|
-
rb_define_method(cGyro_IO, "initialize", Gyro_IO_initialize, 2);
|
469
|
-
rb_define_method(cGyro_IO, "await", Gyro_IO_await, 0);
|
470
|
-
rb_define_method(cGyro_IO, "deactivate_post_fork", Gyro_IO_deactivate_post_fork, 0);
|
471
|
-
|
472
|
-
VALUE cIO = rb_const_get(rb_cObject, rb_intern("IO"));
|
473
|
-
// rb_define_method(cIO, "gets", IO_gets, -1);
|
474
|
-
rb_define_method(cIO, "read", IO_read, -1);
|
475
|
-
rb_define_method(cIO, "readpartial", IO_readpartial, -1);
|
476
|
-
rb_define_method(cIO, "write", IO_write, -1);
|
477
|
-
rb_define_method(cIO, "write_nonblock", IO_write, -1);
|
478
|
-
rb_define_method(cIO, "<<", IO_write_chevron, 1);
|
479
|
-
rb_define_method(cIO, "read_watcher", IO_read_watcher, 0);
|
480
|
-
rb_define_method(cIO, "write_watcher", IO_write_watcher, 0);
|
481
|
-
|
482
|
-
ID_ivar_read_watcher = rb_intern("@read_watcher");
|
483
|
-
ID_ivar_write_watcher = rb_intern("@write_watcher");
|
484
|
-
SYM_r = ID2SYM(rb_intern("r"));
|
485
|
-
SYM_w = ID2SYM(rb_intern("w"));
|
486
|
-
|
487
|
-
rb_global_variable(&SYM_r);
|
488
|
-
rb_global_variable(&SYM_w);
|
489
|
-
}
|