polyphony 0.34 → 0.41

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