polyphony 0.36 → 0.42

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