polyphony 0.43 → 0.43.5

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile.lock +2 -2
  5. data/README.md +0 -1
  6. data/docs/_sass/custom/custom.scss +10 -0
  7. data/docs/favicon.ico +0 -0
  8. data/docs/getting-started/overview.md +2 -2
  9. data/docs/index.md +6 -3
  10. data/docs/main-concepts/design-principles.md +23 -34
  11. data/docs/main-concepts/fiber-scheduling.md +1 -1
  12. data/docs/polyphony-logo.png +0 -0
  13. data/examples/adapters/concurrent-ruby.rb +9 -0
  14. data/examples/adapters/redis_blpop.rb +12 -0
  15. data/examples/core/xx-daemon.rb +14 -0
  16. data/examples/performance/mem-usage.rb +34 -28
  17. data/examples/performance/messaging.rb +29 -0
  18. data/examples/performance/multi_snooze.rb +11 -9
  19. data/ext/polyphony/libev_agent.c +181 -151
  20. data/ext/polyphony/libev_queue.c +129 -57
  21. data/ext/polyphony/polyphony.c +0 -6
  22. data/ext/polyphony/polyphony.h +12 -5
  23. data/ext/polyphony/polyphony_ext.c +0 -2
  24. data/ext/polyphony/ring_buffer.c +120 -0
  25. data/ext/polyphony/ring_buffer.h +28 -0
  26. data/ext/polyphony/thread.c +13 -13
  27. data/lib/polyphony.rb +26 -10
  28. data/lib/polyphony/adapters/redis.rb +3 -2
  29. data/lib/polyphony/core/global_api.rb +5 -3
  30. data/lib/polyphony/core/resource_pool.rb +19 -9
  31. data/lib/polyphony/core/thread_pool.rb +1 -1
  32. data/lib/polyphony/extensions/core.rb +40 -0
  33. data/lib/polyphony/extensions/fiber.rb +8 -13
  34. data/lib/polyphony/extensions/io.rb +17 -16
  35. data/lib/polyphony/extensions/socket.rb +12 -2
  36. data/lib/polyphony/version.rb +1 -1
  37. data/test/q.rb +24 -0
  38. data/test/test_agent.rb +13 -7
  39. data/test/test_fiber.rb +3 -3
  40. data/test/test_global_api.rb +50 -17
  41. data/test/test_io.rb +10 -2
  42. data/test/test_queue.rb +26 -1
  43. data/test/test_resource_pool.rb +12 -0
  44. data/test/test_throttler.rb +6 -5
  45. metadata +11 -3
  46. data/ext/polyphony/socket.c +0 -213
@@ -1,6 +1,8 @@
1
+ #include <netdb.h>
2
+ #include <sys/socket.h>
3
+
1
4
  #include "polyphony.h"
2
5
  #include "../libev/ev.h"
3
- #include <sys/socket.h>
4
6
 
5
7
  VALUE cLibevAgent = Qnil;
6
8
  VALUE cTCPSocket;
@@ -128,7 +130,7 @@ VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue
128
130
  GetLibevAgent(self, agent);
129
131
 
130
132
  if (is_nowait) {
131
- int runnable_count = RARRAY_LEN(queue);
133
+ long runnable_count = LibevQueue_len(queue);
132
134
  agent->run_no_wait_count++;
133
135
  if (agent->run_no_wait_count < runnable_count || agent->run_no_wait_count < 10)
134
136
  return self;
@@ -234,7 +236,7 @@ struct libev_io {
234
236
  VALUE fiber;
235
237
  };
236
238
 
237
- static void LibevAgent_io_callback(EV_P_ ev_io *w, int revents)
239
+ void LibevAgent_io_callback(EV_P_ ev_io *w, int revents)
238
240
  {
239
241
  struct libev_io *watcher = (struct libev_io *)w;
240
242
  Fiber_make_runnable(watcher->fiber, Qnil);
@@ -255,11 +257,32 @@ VALUE libev_agent_await(VALUE self) {
255
257
  return libev_await(agent);
256
258
  }
257
259
 
260
+ VALUE libev_io_wait(struct LibevAgent_t *agent, struct libev_io *watcher, rb_io_t *fptr, int flags) {
261
+ VALUE switchpoint_result;
262
+
263
+ if (watcher->fiber == Qnil) {
264
+ watcher->fiber = rb_fiber_current();
265
+ ev_io_init(&watcher->io, LibevAgent_io_callback, fptr->fd, flags);
266
+ }
267
+ ev_io_start(agent->ev_loop, &watcher->io);
268
+ switchpoint_result = libev_await(agent);
269
+ ev_io_stop(agent->ev_loop, &watcher->io);
270
+
271
+ RB_GC_GUARD(switchpoint_result);
272
+ return switchpoint_result;
273
+ }
274
+
275
+ VALUE libev_snooze() {
276
+ Fiber_make_runnable(rb_fiber_current(), Qnil);
277
+ return Thread_switch_fiber(rb_thread_current());
278
+ }
279
+
258
280
  VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
259
281
  struct LibevAgent_t *agent;
260
282
  struct libev_io watcher;
261
283
  rb_io_t *fptr;
262
- int len = NUM2INT(length);
284
+ long dynamic_len = length == Qnil;
285
+ long len = dynamic_len ? 4096 : NUM2INT(length);
263
286
  int shrinkable = io_setstrbuf(&str, len);
264
287
  char *buf = RSTRING_PTR(str);
265
288
  long total = 0;
@@ -276,44 +299,35 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
276
299
 
277
300
  OBJ_TAINT(str);
278
301
 
279
- while (len > 0) {
280
- int n = read(fptr->fd, buf, len);
281
- if (n == 0)
282
- break;
283
- if (n > 0) {
284
- total = total + n;
285
- buf += n;
286
- len -= n;
287
- if (!read_to_eof || (len == 0)) break;
288
- }
289
- else {
302
+ while (1) {
303
+ ssize_t n = read(fptr->fd, buf, len - total);
304
+ if (n < 0) {
290
305
  int e = errno;
291
- if ((e == EWOULDBLOCK || e == EAGAIN)) {
292
- if (watcher.fiber == Qnil) {
293
- watcher.fiber = rb_fiber_current();
294
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, EV_READ);
295
- }
296
- ev_io_start(agent->ev_loop, &watcher.io);
297
- switchpoint_result = libev_await(agent);
298
- ev_io_stop(agent->ev_loop, &watcher.io);
299
- if (TEST_EXCEPTION(switchpoint_result)) {
300
- goto error;
301
- }
302
- }
303
- else
304
- rb_syserr_fail(e, strerror(e));
305
- // rb_syserr_fail_path(e, fptr->pathv);
306
+ if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
307
+
308
+ switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_READ);
309
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
306
310
  }
307
- }
311
+ else {
312
+ switchpoint_result = libev_snooze();
313
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
308
314
 
309
- if (watcher.fiber == Qnil) {
310
- Fiber_make_runnable(rb_fiber_current(), Qnil);
311
- switchpoint_result = Thread_switch_fiber(rb_thread_current());
312
- if (TEST_EXCEPTION(switchpoint_result)) {
313
- goto error;
315
+ if (n == 0) break; // EOF
316
+ total = total + n;
317
+ if (!read_to_eof) break;
318
+
319
+ if (total == len) {
320
+ if (!dynamic_len) break;
321
+
322
+ rb_str_resize(str, total);
323
+ rb_str_modify_expand(str, len);
324
+ buf = RSTRING_PTR(str) + total;
325
+ shrinkable = 0;
326
+ len += len;
327
+ }
328
+ else buf += n;
314
329
  }
315
330
  }
316
-
317
331
  if (total == 0) return Qnil;
318
332
 
319
333
  io_set_read_length(str, total, shrinkable);
@@ -347,8 +361,8 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
347
361
  struct libev_io watcher;
348
362
  rb_io_t *fptr;
349
363
  VALUE str;
350
- int total;
351
- int len = 8192;
364
+ long total;
365
+ long len = 8192;
352
366
  int shrinkable;
353
367
  char *buf;
354
368
  VALUE switchpoint_result = Qnil;
@@ -366,10 +380,20 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
366
380
  OBJ_TAINT(str);
367
381
 
368
382
  while (1) {
369
- int n = read(fptr->fd, buf, len);
370
- if (n == 0)
371
- break;
372
- if (n > 0) {
383
+ ssize_t n = read(fptr->fd, buf, len);
384
+ if (n < 0) {
385
+ int e = errno;
386
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
387
+
388
+ switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_READ);
389
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
390
+ }
391
+ else {
392
+ switchpoint_result = libev_snooze();
393
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
394
+
395
+ if (n == 0) break; // EOF
396
+
373
397
  total = n;
374
398
  YIELD_STR();
375
399
  Fiber_make_runnable(rb_fiber_current(), Qnil);
@@ -378,24 +402,6 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
378
402
  goto error;
379
403
  }
380
404
  }
381
- else {
382
- int e = errno;
383
- if ((e == EWOULDBLOCK || e == EAGAIN)) {
384
- if (watcher.fiber == Qnil) {
385
- watcher.fiber = rb_fiber_current();
386
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, EV_READ);
387
- }
388
- ev_io_start(agent->ev_loop, &watcher.io);
389
- switchpoint_result = libev_await(agent);
390
- ev_io_stop(agent->ev_loop, &watcher.io);
391
- if (TEST_EXCEPTION(switchpoint_result)) {
392
- goto error;
393
- }
394
- }
395
- else
396
- rb_syserr_fail(e, strerror(e));
397
- // rb_syserr_fail_path(e, fptr->pathv);
398
- }
399
405
  }
400
406
 
401
407
  RB_GC_GUARD(str);
@@ -407,62 +413,60 @@ error:
407
413
  return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
408
414
  }
409
415
 
410
- VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
416
+ VALUE LibevAgent_write(int argc, VALUE *argv, VALUE self) {
411
417
  struct LibevAgent_t *agent;
412
418
  struct libev_io watcher;
413
419
  rb_io_t *fptr;
414
420
  VALUE switchpoint_result = Qnil;
421
+ VALUE io;
422
+ VALUE underlying_io;
423
+ long total_written = 0;
424
+ int arg_idx = 1;
415
425
 
416
- char *buf = StringValuePtr(str);
417
- int len = RSTRING_LEN(str);
418
- int left = len;
419
-
420
- VALUE underlying_io = rb_iv_get(io, "@io");
426
+ if (argc < 2)
427
+ rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
428
+
429
+ io = argv[0];
430
+ underlying_io = rb_iv_get(io, "@io");
421
431
  if (underlying_io != Qnil) io = underlying_io;
422
432
  GetLibevAgent(self, agent);
423
433
  io = rb_io_get_write_io(io);
424
434
  GetOpenFile(io, fptr);
425
435
  watcher.fiber = Qnil;
426
436
 
427
- while (left > 0) {
428
- int result = write(fptr->fd, buf, left);
429
- if (result < 0) {
430
- int e = errno;
431
- if (e == EAGAIN) {
432
- if (watcher.fiber == Qnil) {
433
- watcher.fiber = rb_fiber_current();
434
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, EV_WRITE);
435
- }
436
- ev_io_start(agent->ev_loop, &watcher.io);
437
- switchpoint_result = libev_await(agent);
438
- ev_io_stop(agent->ev_loop, &watcher.io);
439
- if (TEST_EXCEPTION(switchpoint_result))
440
- goto error;
437
+ while (arg_idx < argc) {
438
+ VALUE str = argv[arg_idx];
439
+ char *buf = StringValuePtr(str);
440
+ long len = RSTRING_LEN(str);
441
+ long left = len;
442
+
443
+ while (left > 0) {
444
+ ssize_t n = write(fptr->fd, buf, left);
445
+ if (n < 0) {
446
+ int e = errno;
447
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
448
+
449
+ switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_WRITE);
450
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
441
451
  }
442
452
  else {
443
- rb_syserr_fail(e, strerror(e));
444
- // rb_syserr_fail_path(e, fptr->pathv);
445
-
453
+ buf += n;
454
+ left -= n;
446
455
  }
447
456
  }
448
- else {
449
- buf += result;
450
- left -= result;
451
- }
457
+ total_written += len;
458
+ arg_idx++;
452
459
  }
453
460
 
454
461
  if (watcher.fiber == Qnil) {
455
- Fiber_make_runnable(rb_fiber_current(), Qnil);
456
- switchpoint_result = Thread_switch_fiber(rb_thread_current());
457
- if (TEST_EXCEPTION(switchpoint_result)) {
458
- goto error;
459
- }
462
+ switchpoint_result = libev_snooze();
463
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
460
464
  }
461
465
 
462
466
  RB_GC_GUARD(watcher.fiber);
463
467
  RB_GC_GUARD(switchpoint_result);
464
468
 
465
- return INT2NUM(len);
469
+ return INT2NUM(total_written);
466
470
  error:
467
471
  return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
468
472
  }
@@ -488,50 +492,39 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
488
492
  fd = accept(fptr->fd, &addr, &len);
489
493
  if (fd < 0) {
490
494
  int e = errno;
491
- if (e == EWOULDBLOCK || e == EAGAIN) {
492
- if (watcher.fiber == Qnil) {
493
- watcher.fiber = rb_fiber_current();
494
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, EV_READ);
495
- }
496
- ev_io_start(agent->ev_loop, &watcher.io);
497
- switchpoint_result = libev_await(agent);
498
- ev_io_stop(agent->ev_loop, &watcher.io);
499
-
500
- TEST_RESUME_EXCEPTION(switchpoint_result);
501
- RB_GC_GUARD(watcher.fiber);
502
- RB_GC_GUARD(switchpoint_result);
503
- }
504
- else
505
- rb_syserr_fail(e, strerror(e));
506
- // rb_syserr_fail_path(e, fptr->pathv);
495
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
496
+
497
+ switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_READ);
498
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
507
499
  }
508
500
  else {
509
- VALUE connection = rb_obj_alloc(cTCPSocket);
501
+ VALUE socket;
510
502
  rb_io_t *fp;
511
- MakeOpenFile(connection, fp);
503
+ switchpoint_result = libev_snooze();
504
+ if (TEST_EXCEPTION(switchpoint_result)) {
505
+ close(fd); // close fd since we're raising an exception
506
+ goto error;
507
+ }
508
+
509
+ socket = rb_obj_alloc(cTCPSocket);
510
+ MakeOpenFile(socket, fp);
512
511
  rb_update_max_fd(fd);
513
512
  fp->fd = fd;
514
513
  fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
515
- rb_io_ascii8bit_binmode(connection);
514
+ rb_io_ascii8bit_binmode(socket);
516
515
  rb_io_set_nonblock(fp);
517
516
  rb_io_synchronized(fp);
518
517
 
519
518
  // if (rsock_do_not_reverse_lookup) {
520
519
  // fp->mode |= FMODE_NOREVLOOKUP;
521
520
  // }
522
-
523
- if (watcher.fiber == Qnil) {
524
- Fiber_make_runnable(rb_fiber_current(), Qnil);
525
- switchpoint_result = Thread_switch_fiber(rb_thread_current());
526
- if (TEST_EXCEPTION(switchpoint_result)) {
527
- return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
528
- }
529
- }
530
-
531
- return connection;
521
+ return socket;
532
522
  }
533
523
  }
524
+ RB_GC_GUARD(switchpoint_result);
534
525
  return Qnil;
526
+ error:
527
+ return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
535
528
  }
536
529
 
537
530
  VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
@@ -542,7 +535,7 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
542
535
  struct sockaddr addr;
543
536
  socklen_t len = (socklen_t)sizeof addr;
544
537
  VALUE switchpoint_result = Qnil;
545
- VALUE connection = Qnil;
538
+ VALUE socket = Qnil;
546
539
  VALUE underlying_sock = rb_iv_get(sock, "@io");
547
540
  if (underlying_sock != Qnil) sock = underlying_sock;
548
541
 
@@ -555,46 +548,82 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
555
548
  fd = accept(fptr->fd, &addr, &len);
556
549
  if (fd < 0) {
557
550
  int e = errno;
558
- if (e == EWOULDBLOCK || e == EAGAIN) {
559
- if (watcher.fiber == Qnil) {
560
- watcher.fiber = rb_fiber_current();
561
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, EV_READ);
562
- }
563
- ev_io_start(agent->ev_loop, &watcher.io);
564
- switchpoint_result = libev_await(agent);
565
- ev_io_stop(agent->ev_loop, &watcher.io);
566
-
567
- TEST_RESUME_EXCEPTION(switchpoint_result);
568
- }
569
- else
570
- rb_syserr_fail(e, strerror(e));
571
- // rb_syserr_fail_path(e, fptr->pathv);
551
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
552
+
553
+ switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_READ);
554
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
572
555
  }
573
556
  else {
574
557
  rb_io_t *fp;
575
- connection = rb_obj_alloc(cTCPSocket);
576
- MakeOpenFile(connection, fp);
558
+ switchpoint_result = libev_snooze();
559
+ if (TEST_EXCEPTION(switchpoint_result)) {
560
+ close(fd); // close fd since we're raising an exception
561
+ goto error;
562
+ }
563
+
564
+ socket = rb_obj_alloc(cTCPSocket);
565
+ MakeOpenFile(socket, fp);
577
566
  rb_update_max_fd(fd);
578
567
  fp->fd = fd;
579
568
  fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
580
- rb_io_ascii8bit_binmode(connection);
569
+ rb_io_ascii8bit_binmode(socket);
581
570
  rb_io_set_nonblock(fp);
582
571
  rb_io_synchronized(fp);
583
572
 
584
- rb_yield(connection);
585
- connection = Qnil;
586
-
587
- Fiber_make_runnable(rb_fiber_current(), Qnil);
588
- switchpoint_result = Thread_switch_fiber(rb_thread_current());
589
- TEST_RESUME_EXCEPTION(switchpoint_result);
573
+ rb_yield(socket);
574
+ socket = Qnil;
590
575
  }
591
576
  }
592
577
 
593
- RB_GC_GUARD(connection);
578
+ RB_GC_GUARD(socket);
594
579
  RB_GC_GUARD(watcher.fiber);
595
580
  RB_GC_GUARD(switchpoint_result);
581
+ return Qnil;
582
+ error:
583
+ return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
596
584
  }
597
585
 
586
+ // VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
587
+ // struct LibevAgent_t *agent;
588
+ // struct libev_io watcher;
589
+ // rb_io_t *fptr;
590
+ // struct sockaddr_in addr;
591
+ // char *host_buf = StringValueCStr(host);
592
+ // VALUE switchpoint_result = Qnil;
593
+ // VALUE underlying_sock = rb_iv_get(sock, "@io");
594
+ // if (underlying_sock != Qnil) sock = underlying_sock;
595
+
596
+ // GetLibevAgent(self, agent);
597
+ // GetOpenFile(sock, fptr);
598
+ // rb_io_set_nonblock(fptr);
599
+ // watcher.fiber = Qnil;
600
+
601
+ // addr.sin_family = AF_INET;
602
+ // addr.sin_addr.s_addr = inet_addr(host_buf);
603
+ // addr.sin_port = htons(NUM2INT(port));
604
+
605
+ // while (1) {
606
+ // int result = connect(fptr->fd, &addr, sizeof(addr));
607
+ // if (result < 0) {
608
+ // int e = errno;
609
+ // if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
610
+
611
+ // switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_WRITE);
612
+ // if (TEST_EXCEPTION(switchpoint_result)) goto error;
613
+ // }
614
+ // else {
615
+ // switchpoint_result = libev_snooze();
616
+ // if (TEST_EXCEPTION(switchpoint_result)) goto error;
617
+
618
+ // return sock;
619
+ // }
620
+ // }
621
+ // RB_GC_GUARD(switchpoint_result);
622
+ // return Qnil;
623
+ // error:
624
+ // return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
625
+ // }
626
+
598
627
  VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write) {
599
628
  struct LibevAgent_t *agent;
600
629
  struct libev_io watcher;
@@ -624,7 +653,7 @@ struct libev_timer {
624
653
  VALUE fiber;
625
654
  };
626
655
 
627
- static void LibevAgent_timer_callback(EV_P_ ev_timer *w, int revents)
656
+ void LibevAgent_timer_callback(EV_P_ ev_timer *w, int revents)
628
657
  {
629
658
  struct libev_timer *watcher = (struct libev_timer *)w;
630
659
  Fiber_make_runnable(watcher->fiber, Qnil);
@@ -654,7 +683,7 @@ struct libev_child {
654
683
  VALUE fiber;
655
684
  };
656
685
 
657
- static void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
686
+ void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
658
687
  {
659
688
  struct libev_child *watcher = (struct libev_child *)w;
660
689
  int exit_status = w->rstatus >> 8; // weird, why should we do this?
@@ -709,9 +738,10 @@ void Init_LibevAgent() {
709
738
 
710
739
  rb_define_method(cLibevAgent, "read", LibevAgent_read, 4);
711
740
  rb_define_method(cLibevAgent, "read_loop", LibevAgent_read_loop, 1);
712
- rb_define_method(cLibevAgent, "write", LibevAgent_write, 2);
741
+ rb_define_method(cLibevAgent, "write", LibevAgent_write, -1);
713
742
  rb_define_method(cLibevAgent, "accept", LibevAgent_accept, 1);
714
743
  rb_define_method(cLibevAgent, "accept_loop", LibevAgent_accept_loop, 1);
744
+ // rb_define_method(cLibevAgent, "connect", LibevAgent_accept, 3);
715
745
  rb_define_method(cLibevAgent, "wait_io", LibevAgent_wait_io, 2);
716
746
  rb_define_method(cLibevAgent, "sleep", LibevAgent_sleep, 1);
717
747
  rb_define_method(cLibevAgent, "waitpid", LibevAgent_waitpid, 1);