polyphony 0.40 → 0.43.2

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