polyphony 0.38 → 0.43
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 +25 -2
- 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 +0 -30
- 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/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 +1 -1
- 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/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/{gyro/gyro.c → polyphony/polyphony.c} +16 -40
- data/ext/{gyro/gyro.h → polyphony/polyphony.h} +19 -39
- data/ext/polyphony/polyphony_ext.c +23 -0
- data/ext/{gyro → polyphony}/socket.c +21 -18
- data/ext/polyphony/thread.c +206 -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 +27 -9
- 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 +14 -1
- 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 +4 -4
- data/test/test_io.rb +46 -24
- 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 +37 -16
- data/test/test_trace.rb +6 -5
- metadata +40 -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_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/thread.c +0 -308
- data/ext/gyro/timer.c +0 -149
- data/test/test_timer.rb +0 -56
data/ext/gyro/child.c
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
#include "gyro.h"
|
2
|
-
|
3
|
-
struct Gyro_Child {
|
4
|
-
struct ev_child ev_child;
|
5
|
-
struct ev_loop *ev_loop;
|
6
|
-
int active;
|
7
|
-
int pid;
|
8
|
-
VALUE self;
|
9
|
-
VALUE fiber;
|
10
|
-
VALUE selector;
|
11
|
-
};
|
12
|
-
|
13
|
-
static VALUE cGyro_Child = Qnil;
|
14
|
-
|
15
|
-
static void Gyro_Child_mark(void *ptr) {
|
16
|
-
struct Gyro_Child *child = ptr;
|
17
|
-
if (child->fiber != Qnil) {
|
18
|
-
rb_gc_mark(child->fiber);
|
19
|
-
}
|
20
|
-
if (child->selector != Qnil) {
|
21
|
-
rb_gc_mark(child->selector);
|
22
|
-
}
|
23
|
-
}
|
24
|
-
|
25
|
-
static void Gyro_Child_free(void *ptr) {
|
26
|
-
struct Gyro_Child *child = ptr;
|
27
|
-
switch (child->active) {
|
28
|
-
case GYRO_WATCHER_POST_FORK:
|
29
|
-
return;
|
30
|
-
case 1:
|
31
|
-
ev_clear_pending(child->ev_loop, &child->ev_child);
|
32
|
-
ev_child_stop(child->ev_loop, &child->ev_child);
|
33
|
-
default:
|
34
|
-
xfree(child);
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
static size_t Gyro_Child_size(const void *ptr) {
|
39
|
-
return sizeof(struct Gyro_Child);
|
40
|
-
}
|
41
|
-
|
42
|
-
static const rb_data_type_t Gyro_Child_type = {
|
43
|
-
"Gyro_Child",
|
44
|
-
{Gyro_Child_mark, Gyro_Child_free, Gyro_Child_size,},
|
45
|
-
0, 0, 0
|
46
|
-
};
|
47
|
-
|
48
|
-
static VALUE Gyro_Child_allocate(VALUE klass) {
|
49
|
-
struct Gyro_Child *child = ALLOC(struct Gyro_Child);
|
50
|
-
return TypedData_Wrap_Struct(klass, &Gyro_Child_type, child);
|
51
|
-
}
|
52
|
-
|
53
|
-
inline void child_activate(struct Gyro_Child *child) {
|
54
|
-
if (child->active) return;
|
55
|
-
|
56
|
-
child->active = 1;
|
57
|
-
child->fiber = rb_fiber_current();
|
58
|
-
child->selector = Thread_current_event_selector();
|
59
|
-
child->ev_loop = Gyro_Selector_ev_loop(child->selector);
|
60
|
-
Gyro_Selector_add_active_watcher(child->selector, child->self);
|
61
|
-
ev_child_start(child->ev_loop, &child->ev_child);
|
62
|
-
}
|
63
|
-
|
64
|
-
inline void child_deactivate(struct Gyro_Child *child) {
|
65
|
-
if (!child->active) return;
|
66
|
-
|
67
|
-
ev_child_stop(child->ev_loop, &child->ev_child);
|
68
|
-
Gyro_Selector_remove_active_watcher(child->selector, child->self);
|
69
|
-
child->active = 0;
|
70
|
-
child->ev_loop = 0;
|
71
|
-
child->selector = Qnil;
|
72
|
-
child->fiber = Qnil;
|
73
|
-
}
|
74
|
-
|
75
|
-
VALUE Gyro_Child_resume_value(struct ev_child *ev_child) {
|
76
|
-
int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
|
77
|
-
|
78
|
-
return rb_ary_new_from_args(
|
79
|
-
2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
|
80
|
-
);
|
81
|
-
}
|
82
|
-
|
83
|
-
void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
|
84
|
-
struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
|
85
|
-
|
86
|
-
VALUE resume_value = Gyro_Child_resume_value(ev_child);
|
87
|
-
Fiber_make_runnable(child->fiber, resume_value);
|
88
|
-
|
89
|
-
child_deactivate(child);
|
90
|
-
}
|
91
|
-
|
92
|
-
#define GetGyro_Child(obj, child) \
|
93
|
-
TypedData_Get_Struct((obj), struct Gyro_Child, &Gyro_Child_type, (child))
|
94
|
-
|
95
|
-
static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
|
96
|
-
struct Gyro_Child *child;
|
97
|
-
|
98
|
-
GetGyro_Child(self, child);
|
99
|
-
|
100
|
-
child->self = self;
|
101
|
-
child->fiber = Qnil;
|
102
|
-
child->selector = Qnil;
|
103
|
-
child->pid = NUM2INT(pid);
|
104
|
-
child->active = 0;
|
105
|
-
child->ev_loop = 0;
|
106
|
-
|
107
|
-
ev_child_init(&child->ev_child, Gyro_Child_callback, child->pid, 0);
|
108
|
-
|
109
|
-
return Qnil;
|
110
|
-
}
|
111
|
-
|
112
|
-
static VALUE Gyro_Child_await(VALUE self) {
|
113
|
-
struct Gyro_Child *child;
|
114
|
-
GetGyro_Child(self, child);
|
115
|
-
|
116
|
-
child_activate(child);
|
117
|
-
VALUE ret = Gyro_switchpoint();
|
118
|
-
child_deactivate(child);
|
119
|
-
|
120
|
-
TEST_RESUME_EXCEPTION(ret);
|
121
|
-
RB_GC_GUARD(ret);
|
122
|
-
return ret;
|
123
|
-
}
|
124
|
-
|
125
|
-
VALUE Gyro_Child_deactivate_post_fork(VALUE self) {
|
126
|
-
struct Gyro_Child *child;
|
127
|
-
GetGyro_Child(self, child);
|
128
|
-
|
129
|
-
if (child->active)
|
130
|
-
child->active = GYRO_WATCHER_POST_FORK;
|
131
|
-
return self;
|
132
|
-
}
|
133
|
-
|
134
|
-
void Init_Gyro_Child() {
|
135
|
-
cGyro_Child = rb_define_class_under(mGyro, "Child", rb_cData);
|
136
|
-
rb_define_alloc_func(cGyro_Child, Gyro_Child_allocate);
|
137
|
-
|
138
|
-
rb_define_method(cGyro_Child, "initialize", Gyro_Child_initialize, 1);
|
139
|
-
rb_define_method(cGyro_Child, "await", Gyro_Child_await, 0);
|
140
|
-
rb_define_method(cGyro_Child, "deactivate_post_fork", Gyro_Child_deactivate_post_fork, 0);
|
141
|
-
}
|
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
|
-
}
|