eventmachine-maglev- 0.12.10 → 1.0.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/.gitignore +7 -0
  2. data/.yardopts +7 -0
  3. data/Gemfile +3 -0
  4. data/README.md +109 -0
  5. data/Rakefile +14 -368
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +521 -0
  8. data/docs/old/DEFERRABLES +246 -0
  9. data/docs/{KEYBOARD → old/KEYBOARD} +15 -11
  10. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  11. data/docs/old/SMTP +4 -0
  12. data/docs/old/SPAWNED_PROCESSES +148 -0
  13. data/eventmachine.gemspec +20 -26
  14. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  15. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  16. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  17. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  18. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  19. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  20. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  21. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  22. data/examples/{ex_channel.rb → old/ex_channel.rb} +3 -3
  23. data/examples/old/ex_tick_loop_array.rb +15 -0
  24. data/examples/old/ex_tick_loop_counter.rb +32 -0
  25. data/ext/binder.cpp +0 -1
  26. data/ext/cmain.cpp +40 -29
  27. data/ext/ed.cpp +189 -134
  28. data/ext/ed.h +34 -40
  29. data/ext/em.cpp +388 -340
  30. data/ext/em.h +29 -32
  31. data/ext/eventmachine.h +7 -6
  32. data/ext/extconf.rb +57 -48
  33. data/ext/fastfilereader/extconf.rb +5 -3
  34. data/ext/fastfilereader/mapper.cpp +1 -1
  35. data/ext/fastfilereader/rubymain.cpp +0 -1
  36. data/ext/kb.cpp +1 -3
  37. data/ext/pipe.cpp +9 -11
  38. data/ext/project.h +12 -8
  39. data/ext/rubymain.cpp +158 -112
  40. data/java/src/com/rubyeventmachine/EmReactor.java +3 -2
  41. data/lib/em/buftok.rb +35 -63
  42. data/lib/em/callback.rb +43 -11
  43. data/lib/em/channel.rb +22 -15
  44. data/lib/em/completion.rb +303 -0
  45. data/lib/em/connection.rb +341 -208
  46. data/lib/em/deferrable/pool.rb +2 -0
  47. data/lib/em/deferrable.rb +20 -2
  48. data/lib/em/file_watch.rb +37 -18
  49. data/lib/em/iterator.rb +270 -0
  50. data/lib/em/pool.rb +146 -0
  51. data/lib/em/process_watch.rb +5 -4
  52. data/lib/em/processes.rb +8 -4
  53. data/lib/em/protocols/httpclient.rb +27 -11
  54. data/lib/em/protocols/httpclient2.rb +15 -5
  55. data/lib/em/protocols/line_protocol.rb +29 -0
  56. data/lib/em/protocols/memcache.rb +17 -9
  57. data/lib/em/protocols/object_protocol.rb +2 -1
  58. data/lib/em/protocols/postgres3.rb +2 -1
  59. data/lib/em/protocols/smtpclient.rb +19 -11
  60. data/lib/em/protocols/smtpserver.rb +101 -8
  61. data/lib/em/protocols/stomp.rb +9 -7
  62. data/lib/em/protocols/tcptest.rb +3 -2
  63. data/lib/em/protocols.rb +1 -1
  64. data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +188 -205
  65. data/lib/em/queue.rb +23 -13
  66. data/lib/em/resolver.rb +192 -0
  67. data/lib/em/spawnable.rb +9 -10
  68. data/lib/em/streamer.rb +34 -46
  69. data/lib/em/threaded_resource.rb +90 -0
  70. data/lib/em/tick_loop.rb +85 -0
  71. data/lib/em/timers.rb +8 -3
  72. data/lib/em/version.rb +1 -1
  73. data/lib/eventmachine.rb +582 -686
  74. data/lib/jeventmachine.rb +25 -3
  75. data/tasks/package.rake +98 -0
  76. data/tasks/test.rake +8 -0
  77. data/tests/em_test_helper.rb +64 -0
  78. data/tests/test_attach.rb +56 -56
  79. data/tests/test_basic.rb +111 -168
  80. data/tests/test_channel.rb +5 -6
  81. data/tests/test_completion.rb +177 -0
  82. data/tests/test_connection_count.rb +1 -3
  83. data/tests/test_defer.rb +3 -32
  84. data/tests/test_deferrable.rb +35 -0
  85. data/tests/test_epoll.rb +27 -57
  86. data/tests/test_error_handler.rb +10 -7
  87. data/tests/test_exc.rb +6 -33
  88. data/tests/test_file_watch.rb +51 -35
  89. data/tests/test_futures.rb +10 -38
  90. data/tests/test_get_sock_opt.rb +27 -20
  91. data/tests/test_handler_check.rb +1 -3
  92. data/tests/test_hc.rb +49 -112
  93. data/tests/test_httpclient.rb +34 -62
  94. data/tests/test_httpclient2.rb +14 -39
  95. data/tests/test_inactivity_timeout.rb +44 -40
  96. data/tests/test_kb.rb +26 -52
  97. data/tests/test_ltp.rb +27 -71
  98. data/tests/test_ltp2.rb +1 -30
  99. data/tests/test_next_tick.rb +2 -31
  100. data/tests/test_object_protocol.rb +8 -9
  101. data/tests/test_pause.rb +45 -37
  102. data/tests/test_pending_connect_timeout.rb +42 -38
  103. data/tests/test_pool.rb +128 -0
  104. data/tests/test_process_watch.rb +37 -37
  105. data/tests/test_processes.rb +92 -110
  106. data/tests/test_proxy_connection.rb +137 -61
  107. data/tests/test_pure.rb +30 -67
  108. data/tests/test_queue.rb +10 -4
  109. data/tests/test_resolver.rb +55 -0
  110. data/tests/test_running.rb +1 -29
  111. data/tests/test_sasl.rb +8 -33
  112. data/tests/test_send_file.rb +163 -188
  113. data/tests/test_servers.rb +12 -55
  114. data/tests/test_shutdown_hooks.rb +23 -0
  115. data/tests/test_smtpclient.rb +1 -29
  116. data/tests/test_smtpserver.rb +1 -29
  117. data/tests/test_spawn.rb +2 -31
  118. data/tests/test_ssl_args.rb +9 -10
  119. data/tests/test_ssl_methods.rb +1 -3
  120. data/tests/test_ssl_verify.rb +63 -63
  121. data/tests/test_threaded_resource.rb +53 -0
  122. data/tests/test_tick_loop.rb +59 -0
  123. data/tests/test_timers.rb +52 -91
  124. data/tests/test_ud.rb +1 -29
  125. data/tests/test_unbind_reason.rb +31 -0
  126. metadata +113 -70
  127. data/README +0 -82
  128. data/docs/DEFERRABLES +0 -133
  129. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -70
  130. data/docs/SMTP +0 -2
  131. data/docs/SPAWNED_PROCESSES +0 -89
  132. data/ext/cplusplus.cpp +0 -202
  133. data/ext/emwin.cpp +0 -300
  134. data/ext/emwin.h +0 -94
  135. data/ext/epoll.cpp +0 -26
  136. data/ext/epoll.h +0 -25
  137. data/ext/eventmachine_cpp.h +0 -96
  138. data/ext/files.cpp +0 -94
  139. data/ext/files.h +0 -65
  140. data/ext/sigs.cpp +0 -89
  141. data/ext/sigs.h +0 -32
  142. data/java/src/com/rubyeventmachine/application/Application.java +0 -194
  143. data/java/src/com/rubyeventmachine/application/Connection.java +0 -74
  144. data/java/src/com/rubyeventmachine/application/ConnectionFactory.java +0 -37
  145. data/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +0 -46
  146. data/java/src/com/rubyeventmachine/application/PeriodicTimer.java +0 -38
  147. data/java/src/com/rubyeventmachine/application/Timer.java +0 -54
  148. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +0 -109
  149. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +0 -148
  150. data/java/src/com/rubyeventmachine/tests/EMTest.java +0 -80
  151. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +0 -53
  152. data/java/src/com/rubyeventmachine/tests/TestServers.java +0 -75
  153. data/java/src/com/rubyeventmachine/tests/TestTimers.java +0 -90
  154. data/lib/evma/callback.rb +0 -32
  155. data/lib/evma/container.rb +0 -75
  156. data/lib/evma/factory.rb +0 -77
  157. data/lib/evma/protocol.rb +0 -87
  158. data/lib/evma/reactor.rb +0 -48
  159. data/lib/evma.rb +0 -32
  160. data/setup.rb +0 -1585
  161. data/tests/test_errors.rb +0 -82
  162. data/tests/testem.rb +0 -31
  163. data/web/whatis +0 -7
  164. /data/{docs/GNU → GNU} +0 -0
  165. /data/{docs/COPYING → LICENSE} +0 -0
  166. /data/docs/{ChangeLog → old/ChangeLog} +0 -0
  167. /data/docs/{EPOLL → old/EPOLL} +0 -0
  168. /data/docs/{INSTALL → old/INSTALL} +0 -0
  169. /data/docs/{LEGAL → old/LEGAL} +0 -0
  170. /data/docs/{PURE_RUBY → old/PURE_RUBY} +0 -0
  171. /data/docs/{RELEASE_NOTES → old/RELEASE_NOTES} +0 -0
  172. /data/docs/{TODO → old/TODO} +0 -0
  173. /data/examples/{ex_queue.rb → old/ex_queue.rb} +0 -0
  174. /data/examples/{helper.rb → old/helper.rb} +0 -0
data/ext/em.cpp CHANGED
@@ -20,24 +20,12 @@ See the file COPYING for complete licensing information.
20
20
  // THIS ENTIRE FILE WILL EVENTUALLY BE FOR UNIX BUILDS ONLY.
21
21
  //#ifdef OS_UNIX
22
22
 
23
-
24
23
  #include "project.h"
25
24
 
26
- // Keep a global variable floating around
27
- // with the current loop time as set by the Event Machine.
28
- // This avoids the need for frequent expensive calls to time(NULL);
29
- Int64 gCurrentLoopTime;
30
-
31
- #ifdef OS_WIN32
32
- unsigned gTickCountTickover;
33
- unsigned gLastTickCount;
34
- #endif
35
-
36
-
37
25
  /* The numer of max outstanding timers was once a const enum defined in em.h.
38
26
  * Now we define it here so that users can change its value if necessary.
39
27
  */
40
- static unsigned int MaxOutstandingTimers = 10000;
28
+ static unsigned int MaxOutstandingTimers = 100000;
41
29
 
42
30
 
43
31
  /* Internal helper to convert strings to internet addresses. IPv6-aware.
@@ -79,12 +67,13 @@ void EventMachine_t::SetMaxTimerCount (int count)
79
67
  EventMachine_t::EventMachine_t
80
68
  ******************************/
81
69
 
82
- EventMachine_t::EventMachine_t (void (*event_callback)(const unsigned long, int, const char*, const unsigned long)):
70
+ EventMachine_t::EventMachine_t (EMCallback event_callback):
83
71
  HeartbeatInterval(2000000),
84
72
  EventCallback (event_callback),
85
73
  NextHeartbeatTime (0),
86
74
  LoopBreakerReader (-1),
87
75
  LoopBreakerWriter (-1),
76
+ bTerminateSignalReceived (false),
88
77
  bEpoll (false),
89
78
  epfd (-1),
90
79
  bKqueue (false),
@@ -95,7 +84,6 @@ EventMachine_t::EventMachine_t (void (*event_callback)(const unsigned long, int,
95
84
  Quantum.tv_sec = 0;
96
85
  Quantum.tv_usec = 90000;
97
86
 
98
- gTerminateSignalReceived = false;
99
87
  // Make sure the current loop time is sane, in case we do any initializations of
100
88
  // objects before we start running.
101
89
  _UpdateTime();
@@ -197,7 +185,7 @@ void EventMachine_t::ScheduleHalt()
197
185
  * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
198
186
  * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
199
187
  */
200
- gTerminateSignalReceived = true;
188
+ bTerminateSignalReceived = true;
201
189
  }
202
190
 
203
191
 
@@ -316,10 +304,14 @@ void EventMachine_t::_InitializeLoopBreaker()
316
304
  #ifdef OS_UNIX
317
305
  int fd[2];
318
306
  if (pipe (fd))
319
- throw std::runtime_error ("no loop breaker");
307
+ throw std::runtime_error (strerror(errno));
320
308
 
321
309
  LoopBreakerWriter = fd[1];
322
310
  LoopBreakerReader = fd[0];
311
+
312
+ /* 16Jan11: Make sure the pipe is non-blocking, so more than 65k loopbreaks
313
+ * in one tick do not fill up the pipe and block the process on write() */
314
+ SetSocketNonblocking (LoopBreakerWriter);
323
315
  #endif
324
316
 
325
317
  #ifdef OS_WIN32
@@ -353,21 +345,87 @@ EventMachine_t::_UpdateTime
353
345
 
354
346
  void EventMachine_t::_UpdateTime()
355
347
  {
348
+ MyCurrentLoopTime = GetRealTime();
349
+ }
350
+
351
+ /***************************
352
+ EventMachine_t::GetRealTime
353
+ ***************************/
354
+
355
+ uint64_t EventMachine_t::GetRealTime()
356
+ {
357
+ uint64_t current_time;
358
+
356
359
  #if defined(OS_UNIX)
357
360
  struct timeval tv;
358
361
  gettimeofday (&tv, NULL);
359
- gCurrentLoopTime = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
362
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
360
363
 
361
364
  #elif defined(OS_WIN32)
362
365
  unsigned tick = GetTickCount();
363
- if (tick < gLastTickCount)
364
- gTickCountTickover += 1;
365
- gLastTickCount = tick;
366
- gCurrentLoopTime = ((Int64)gTickCountTickover << 32) + (Int64)tick;
366
+ if (tick < LastTickCount)
367
+ TickCountTickover += 1;
368
+ LastTickCount = tick;
369
+ current_time = ((uint64_t)TickCountTickover << 32) + (uint64_t)tick;
370
+ current_time *= 1000; // convert to microseconds
367
371
 
368
372
  #else
369
- gCurrentLoopTime = (Int64)time(NULL) * 1000000LL;
373
+ current_time = (uint64_t)time(NULL) * 1000000LL;
370
374
  #endif
375
+
376
+ return current_time;
377
+ }
378
+
379
+ /***********************************
380
+ EventMachine_t::_DispatchHeartbeats
381
+ ***********************************/
382
+
383
+ void EventMachine_t::_DispatchHeartbeats()
384
+ {
385
+ while (true) {
386
+ multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
387
+ if (i == Heartbeats.end())
388
+ break;
389
+ if (i->first > MyCurrentLoopTime)
390
+ break;
391
+ EventableDescriptor *ed = i->second;
392
+ ed->Heartbeat();
393
+ QueueHeartbeat(ed);
394
+ }
395
+ }
396
+
397
+ /******************************
398
+ EventMachine_t::QueueHeartbeat
399
+ ******************************/
400
+
401
+ void EventMachine_t::QueueHeartbeat(EventableDescriptor *ed)
402
+ {
403
+ uint64_t heartbeat = ed->GetNextHeartbeat();
404
+
405
+ if (heartbeat) {
406
+ #ifndef HAVE_MAKE_PAIR
407
+ Heartbeats.insert (multimap<uint64_t,EventableDescriptor*>::value_type (heartbeat, ed));
408
+ #else
409
+ Heartbeats.insert (make_pair (heartbeat, ed));
410
+ #endif
411
+ }
412
+ }
413
+
414
+ /******************************
415
+ EventMachine_t::ClearHeartbeat
416
+ ******************************/
417
+
418
+ void EventMachine_t::ClearHeartbeat(uint64_t key, EventableDescriptor* ed)
419
+ {
420
+ multimap<uint64_t,EventableDescriptor*>::iterator it;
421
+ pair<multimap<uint64_t,EventableDescriptor*>::iterator,multimap<uint64_t,EventableDescriptor*>::iterator> ret;
422
+ ret = Heartbeats.equal_range (key);
423
+ for (it = ret.first; it != ret.second; ++it) {
424
+ if (it->second == ed) {
425
+ Heartbeats.erase (it);
426
+ break;
427
+ }
428
+ }
371
429
  }
372
430
 
373
431
  /*******************
@@ -376,10 +434,6 @@ EventMachine_t::Run
376
434
 
377
435
  void EventMachine_t::Run()
378
436
  {
379
- #ifdef OS_WIN32
380
- HookControlC (true);
381
- #endif
382
-
383
437
  #ifdef HAVE_EPOLL
384
438
  if (bEpoll) {
385
439
  epfd = epoll_create (MaxEpollDescriptors);
@@ -419,8 +473,7 @@ void EventMachine_t::Run()
419
473
 
420
474
  while (true) {
421
475
  _UpdateTime();
422
- if (!_RunTimers())
423
- break;
476
+ _RunTimers();
424
477
 
425
478
  /* _Add must precede _Modify because the same descriptor might
426
479
  * be on both lists during the same pass through the machine,
@@ -431,13 +484,9 @@ void EventMachine_t::Run()
431
484
 
432
485
  if (!_RunOnce())
433
486
  break;
434
- if (gTerminateSignalReceived)
487
+ if (bTerminateSignalReceived)
435
488
  break;
436
489
  }
437
-
438
- #ifdef OS_WIN32
439
- HookControlC (false);
440
- #endif
441
490
  }
442
491
 
443
492
 
@@ -447,12 +496,16 @@ EventMachine_t::_RunOnce
447
496
 
448
497
  bool EventMachine_t::_RunOnce()
449
498
  {
499
+ bool ret;
450
500
  if (bEpoll)
451
- return _RunEpollOnce();
501
+ ret = _RunEpollOnce();
452
502
  else if (bKqueue)
453
- return _RunKqueueOnce();
503
+ ret = _RunKqueueOnce();
454
504
  else
455
- return _RunSelectOnce();
505
+ ret = _RunSelectOnce();
506
+ _DispatchHeartbeats();
507
+ _CleanupSockets();
508
+ return ret;
456
509
  }
457
510
 
458
511
 
@@ -467,12 +520,31 @@ bool EventMachine_t::_RunEpollOnce()
467
520
  assert (epfd != -1);
468
521
  int s;
469
522
 
523
+ timeval tv = _TimeTilNextEvent();
524
+
470
525
  #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
526
+ int ret = 0;
527
+ fd_set fdreads;
528
+
529
+ FD_ZERO(&fdreads);
530
+ FD_SET(epfd, &fdreads);
531
+
532
+ if ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
533
+ if (ret == -1) {
534
+ assert(errno != EINVAL);
535
+ assert(errno != EBADF);
536
+ }
537
+ return true;
538
+ }
539
+
471
540
  TRAP_BEG;
472
- #endif
473
- s = epoll_wait (epfd, epoll_events, MaxEvents, 50);
474
- #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
541
+ s = epoll_wait (epfd, epoll_events, MaxEvents, 0);
475
542
  TRAP_END;
543
+ #else
544
+ int duration = 0;
545
+ duration = duration + (tv.tv_sec * 1000);
546
+ duration = duration + (tv.tv_usec / 1000);
547
+ s = epoll_wait (epfd, epoll_events, MaxEvents, duration);
476
548
  #endif
477
549
 
478
550
  if (s > 0) {
@@ -501,72 +573,6 @@ bool EventMachine_t::_RunEpollOnce()
501
573
  EmSelect (0, NULL, NULL, NULL, &tv);
502
574
  }
503
575
 
504
- { // cleanup dying sockets
505
- // vector::pop_back works in constant time.
506
- // TODO, rip this out and only delete the descriptors we know have died,
507
- // rather than traversing the whole list.
508
- // Modified 05Jan08 per suggestions by Chris Heath. It's possible that
509
- // an EventableDescriptor will have a descriptor value of -1. That will
510
- // happen if EventableDescriptor::Close was called on it. In that case,
511
- // don't call epoll_ctl to remove the socket's filters from the epoll set.
512
- // According to the epoll docs, this happens automatically when the
513
- // descriptor is closed anyway. This is different from the case where
514
- // the socket has already been closed but the descriptor in the ED object
515
- // hasn't yet been set to INVALID_SOCKET.
516
- int i, j;
517
- int nSockets = Descriptors.size();
518
- for (i=0, j=0; i < nSockets; i++) {
519
- EventableDescriptor *ed = Descriptors[i];
520
- assert (ed);
521
- if (ed->ShouldDelete()) {
522
- if (ed->GetSocket() != INVALID_SOCKET) {
523
- assert (bEpoll); // wouldn't be in this method otherwise.
524
- assert (epfd != -1);
525
- int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
526
- // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
527
- if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
528
- char buf [200];
529
- snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
530
- throw std::runtime_error (buf);
531
- }
532
- }
533
-
534
- ModifiedDescriptors.erase (ed);
535
- delete ed;
536
- }
537
- else
538
- Descriptors [j++] = ed;
539
- }
540
- while ((size_t)j < Descriptors.size())
541
- Descriptors.pop_back();
542
-
543
- }
544
-
545
- // TODO, heartbeats.
546
- // Added 14Sep07, its absence was noted by Brian Candler. But the comment was here, indicated
547
- // that this got thought about and not done when EPOLL was originally written. Was there a reason
548
- // not to do it, or was it an oversight? Certainly, running a heartbeat on 50,000 connections every
549
- // two seconds can get to be a real bear, especially if all we're doing is timing out dead ones.
550
- // Maybe there's a better way to do this. (Or maybe it's not that expensive after all.)
551
- //
552
- { // dispatch heartbeats
553
- if (gCurrentLoopTime >= NextHeartbeatTime) {
554
- NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
555
-
556
- for (int i=0; i < Descriptors.size(); i++) {
557
- EventableDescriptor *ed = Descriptors[i];
558
- assert (ed);
559
- ed->Heartbeat();
560
- }
561
- }
562
- }
563
-
564
- #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
565
- if (!rb_thread_alone()) {
566
- rb_thread_schedule();
567
- }
568
- #endif
569
-
570
576
  return true;
571
577
  #else
572
578
  throw std::runtime_error ("epoll is not implemented on this platform");
@@ -582,15 +588,35 @@ bool EventMachine_t::_RunKqueueOnce()
582
588
  {
583
589
  #ifdef HAVE_KQUEUE
584
590
  assert (kqfd != -1);
585
- struct timespec ts = {0, 10000000}; // Too frequent. Use blocking_region
586
-
587
591
  int k;
592
+
593
+ timeval tv = _TimeTilNextEvent();
594
+
595
+ struct timespec ts;
596
+ ts.tv_sec = tv.tv_sec;
597
+ ts.tv_nsec = tv.tv_usec * 1000;
598
+
588
599
  #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
600
+ int ret = 0;
601
+ fd_set fdreads;
602
+
603
+ FD_ZERO(&fdreads);
604
+ FD_SET(kqfd, &fdreads);
605
+
606
+ if ((ret = rb_thread_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
607
+ if (ret == -1) {
608
+ assert(errno != EINVAL);
609
+ assert(errno != EBADF);
610
+ }
611
+ return true;
612
+ }
613
+
589
614
  TRAP_BEG;
590
- #endif
615
+ ts.tv_sec = ts.tv_nsec = 0;
591
616
  k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
592
- #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
593
617
  TRAP_END;
618
+ #else
619
+ k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
594
620
  #endif
595
621
 
596
622
  struct kevent *ke = Karray;
@@ -627,42 +653,6 @@ bool EventMachine_t::_RunKqueueOnce()
627
653
  ++ke;
628
654
  }
629
655
 
630
- { // cleanup dying sockets
631
- // vector::pop_back works in constant time.
632
- // TODO, rip this out and only delete the descriptors we know have died,
633
- // rather than traversing the whole list.
634
- // In kqueue, closing a descriptor automatically removes its event filters.
635
-
636
- int i, j;
637
- int nSockets = Descriptors.size();
638
- for (i=0, j=0; i < nSockets; i++) {
639
- EventableDescriptor *ed = Descriptors[i];
640
- assert (ed);
641
- if (ed->ShouldDelete()) {
642
- ModifiedDescriptors.erase (ed);
643
- delete ed;
644
- }
645
- else
646
- Descriptors [j++] = ed;
647
- }
648
- while ((size_t)j < Descriptors.size())
649
- Descriptors.pop_back();
650
-
651
- }
652
-
653
- { // dispatch heartbeats
654
- if (gCurrentLoopTime >= NextHeartbeatTime) {
655
- NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
656
-
657
- for (unsigned int i=0; i < Descriptors.size(); i++) {
658
- EventableDescriptor *ed = Descriptors[i];
659
- assert (ed);
660
- ed->Heartbeat();
661
- }
662
- }
663
- }
664
-
665
-
666
656
  // TODO, replace this with rb_thread_blocking_region for 1.9 builds.
667
657
  #if defined(BUILD_FOR_RUBY) && !defined(BUILD_FOR_MAGLEV)
668
658
  if (!rb_thread_alone()) {
@@ -677,6 +667,93 @@ bool EventMachine_t::_RunKqueueOnce()
677
667
  }
678
668
 
679
669
 
670
+ /*********************************
671
+ EventMachine_t::_TimeTilNextEvent
672
+ *********************************/
673
+
674
+ timeval EventMachine_t::_TimeTilNextEvent()
675
+ {
676
+ uint64_t next_event = 0;
677
+
678
+ if (!Heartbeats.empty()) {
679
+ multimap<uint64_t,EventableDescriptor*>::iterator heartbeats = Heartbeats.begin();
680
+ next_event = heartbeats->first;
681
+ }
682
+
683
+ if (!Timers.empty()) {
684
+ multimap<uint64_t,Timer_t>::iterator timers = Timers.begin();
685
+ if (next_event == 0 || timers->first < next_event)
686
+ next_event = timers->first;
687
+ }
688
+
689
+ if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
690
+ next_event = MyCurrentLoopTime;
691
+ }
692
+
693
+ timeval tv;
694
+
695
+ if (next_event == 0) {
696
+ tv = Quantum;
697
+ } else {
698
+ if (next_event > MyCurrentLoopTime) {
699
+ uint64_t duration = next_event - MyCurrentLoopTime;
700
+ tv.tv_sec = duration / 1000000;
701
+ tv.tv_usec = duration % 1000000;
702
+ } else {
703
+ tv.tv_sec = tv.tv_usec = 0;
704
+ }
705
+ }
706
+
707
+ return tv;
708
+ }
709
+
710
+ /*******************************
711
+ EventMachine_t::_CleanupSockets
712
+ *******************************/
713
+
714
+ void EventMachine_t::_CleanupSockets()
715
+ {
716
+ // TODO, rip this out and only delete the descriptors we know have died,
717
+ // rather than traversing the whole list.
718
+ // Modified 05Jan08 per suggestions by Chris Heath. It's possible that
719
+ // an EventableDescriptor will have a descriptor value of -1. That will
720
+ // happen if EventableDescriptor::Close was called on it. In that case,
721
+ // don't call epoll_ctl to remove the socket's filters from the epoll set.
722
+ // According to the epoll docs, this happens automatically when the
723
+ // descriptor is closed anyway. This is different from the case where
724
+ // the socket has already been closed but the descriptor in the ED object
725
+ // hasn't yet been set to INVALID_SOCKET.
726
+ // In kqueue, closing a descriptor automatically removes its event filters.
727
+ int i, j;
728
+ int nSockets = Descriptors.size();
729
+ for (i=0, j=0; i < nSockets; i++) {
730
+ EventableDescriptor *ed = Descriptors[i];
731
+ assert (ed);
732
+ if (ed->ShouldDelete()) {
733
+ #ifdef HAVE_EPOLL
734
+ if (bEpoll) {
735
+ assert (epfd != -1);
736
+ if (ed->GetSocket() != INVALID_SOCKET) {
737
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
738
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
739
+ if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
740
+ char buf [200];
741
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
742
+ throw std::runtime_error (buf);
743
+ }
744
+ }
745
+ ModifiedDescriptors.erase(ed);
746
+ }
747
+ #endif
748
+ delete ed;
749
+ }
750
+ else
751
+ Descriptors [j++] = ed;
752
+ }
753
+ while ((size_t)j < Descriptors.size())
754
+ Descriptors.pop_back();
755
+ }
756
+
680
757
  /*********************************
681
758
  EventMachine_t::_ModifyEpollEvent
682
759
  *********************************/
@@ -829,7 +906,7 @@ bool EventMachine_t::_RunSelectOnce()
829
906
  { // read and write the sockets
830
907
  //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
831
908
  //timeval tv = Quantum;
832
- SelectData.tv = Quantum;
909
+ SelectData.tv = _TimeTilNextEvent();
833
910
  int s = SelectData._Select();
834
911
  //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
835
912
  //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
@@ -865,48 +942,54 @@ bool EventMachine_t::_RunSelectOnce()
865
942
  _ReadLoopBreaker();
866
943
  }
867
944
  else if (s < 0) {
868
- // select can fail on error in a handful of ways.
869
- // If this happens, then wait for a little while to avoid busy-looping.
870
- // If the error was EINTR, we probably caught SIGCHLD or something,
871
- // so keep the wait short.
872
- timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
873
- EmSelect (0, NULL, NULL, NULL, &tv);
945
+ switch (errno) {
946
+ case EBADF:
947
+ _CleanBadDescriptors();
948
+ break;
949
+ case EINVAL:
950
+ throw std::runtime_error ("Somehow EM passed an invalid nfds or invalid timeout to select(2), please report this!");
951
+ break;
952
+ default:
953
+ // select can fail on error in a handful of ways.
954
+ // If this happens, then wait for a little while to avoid busy-looping.
955
+ // If the error was EINTR, we probably caught SIGCHLD or something,
956
+ // so keep the wait short.
957
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
958
+ EmSelect (0, NULL, NULL, NULL, &tv);
959
+ }
874
960
  }
875
961
  }
876
962
 
963
+ return true;
964
+ }
877
965
 
878
- { // dispatch heartbeats
879
- if (gCurrentLoopTime >= NextHeartbeatTime) {
880
- NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
966
+ void EventMachine_t::_CleanBadDescriptors()
967
+ {
968
+ size_t i;
881
969
 
882
- for (i=0; i < Descriptors.size(); i++) {
883
- EventableDescriptor *ed = Descriptors[i];
884
- assert (ed);
885
- ed->Heartbeat();
886
- }
887
- }
888
- }
970
+ for (i = 0; i < Descriptors.size(); i++) {
971
+ EventableDescriptor *ed = Descriptors[i];
972
+ if (ed->ShouldDelete())
973
+ continue;
889
974
 
890
- { // cleanup dying sockets
891
- // vector::pop_back works in constant time.
892
- int i, j;
893
- int nSockets = Descriptors.size();
894
- for (i=0, j=0; i < nSockets; i++) {
895
- EventableDescriptor *ed = Descriptors[i];
896
- assert (ed);
897
- if (ed->ShouldDelete())
898
- delete ed;
899
- else
900
- Descriptors [j++] = ed;
901
- }
902
- while ((size_t)j < Descriptors.size())
903
- Descriptors.pop_back();
975
+ int sd = ed->GetSocket();
904
976
 
905
- }
977
+ struct timeval tv;
978
+ tv.tv_sec = 0;
979
+ tv.tv_usec = 0;
906
980
 
907
- return true;
908
- }
981
+ fd_set fds;
982
+ FD_ZERO(&fds);
983
+ FD_SET(sd, &fds);
984
+
985
+ int ret = select(sd + 1, &fds, NULL, NULL, &tv);
909
986
 
987
+ if (ret == -1) {
988
+ if (errno == EBADF)
989
+ ed->ScheduleClose(false);
990
+ }
991
+ }
992
+ }
910
993
 
911
994
  /********************************
912
995
  EventMachine_t::_ReadLoopBreaker
@@ -921,7 +1004,7 @@ void EventMachine_t::_ReadLoopBreaker()
921
1004
  char buffer [1024];
922
1005
  read (LoopBreakerReader, buffer, sizeof(buffer));
923
1006
  if (EventCallback)
924
- (*EventCallback)(NULL, EM_LOOPBREAK_SIGNAL, "", 0);
1007
+ (*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0);
925
1008
  }
926
1009
 
927
1010
 
@@ -929,26 +1012,24 @@ void EventMachine_t::_ReadLoopBreaker()
929
1012
  EventMachine_t::_RunTimers
930
1013
  **************************/
931
1014
 
932
- bool EventMachine_t::_RunTimers()
1015
+ void EventMachine_t::_RunTimers()
933
1016
  {
934
1017
  // These are caller-defined timer handlers.
935
- // Return T/F to indicate whether we should continue the main loop.
936
1018
  // We rely on the fact that multimaps sort by their keys to avoid
937
1019
  // inspecting the whole list every time we come here.
938
1020
  // Just keep inspecting and processing the list head until we hit
939
1021
  // one that hasn't expired yet.
940
1022
 
941
1023
  while (true) {
942
- multimap<Int64,Timer_t>::iterator i = Timers.begin();
1024
+ multimap<uint64_t,Timer_t>::iterator i = Timers.begin();
943
1025
  if (i == Timers.end())
944
1026
  break;
945
- if (i->first > gCurrentLoopTime)
1027
+ if (i->first > MyCurrentLoopTime)
946
1028
  break;
947
1029
  if (EventCallback)
948
- (*EventCallback) (NULL, EM_TIMER_FIRED, NULL, i->second.GetBinding());
1030
+ (*EventCallback) (0, EM_TIMER_FIRED, NULL, i->second.GetBinding());
949
1031
  Timers.erase (i);
950
1032
  }
951
- return true;
952
1033
  }
953
1034
 
954
1035
 
@@ -961,31 +1042,15 @@ const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
961
1042
  {
962
1043
  if (Timers.size() > MaxOutstandingTimers)
963
1044
  return false;
964
- // Don't use the global loop-time variable here, because we might
965
- // get called before the main event machine is running.
966
1045
 
967
- #ifdef OS_UNIX
968
- struct timeval tv;
969
- gettimeofday (&tv, NULL);
970
- Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
971
- fire_at += ((Int64)milliseconds) * 1000LL;
972
- #endif
973
-
974
- #ifdef OS_WIN32
975
- unsigned tick = GetTickCount();
976
- if (tick < gLastTickCount)
977
- gTickCountTickover += 1;
978
- gLastTickCount = tick;
979
-
980
- Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick;
981
- fire_at += (Int64)milliseconds;
982
- #endif
1046
+ uint64_t fire_at = GetRealTime();
1047
+ fire_at += ((uint64_t)milliseconds) * 1000LL;
983
1048
 
984
1049
  Timer_t t;
985
1050
  #ifndef HAVE_MAKE_PAIR
986
- multimap<Int64,Timer_t>::iterator i = Timers.insert (multimap<Int64,Timer_t>::value_type (fire_at, t));
1051
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (multimap<uint64_t,Timer_t>::value_type (fire_at, t));
987
1052
  #else
988
- multimap<Int64,Timer_t>::iterator i = Timers.insert (make_pair (fire_at, t));
1053
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (make_pair (fire_at, t));
989
1054
  #endif
990
1055
  return i->second.GetBinding();
991
1056
  }
@@ -1030,41 +1095,16 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1030
1095
  bind_as = *bind_as_ptr; // copy because name2address points to a static
1031
1096
 
1032
1097
  int sd = socket (family, SOCK_STREAM, 0);
1033
- if (sd == INVALID_SOCKET)
1034
- throw std::runtime_error ("unable to create new socket");
1035
-
1036
- /*
1037
- sockaddr_in pin;
1038
- unsigned long HostAddr;
1039
-
1040
- HostAddr = inet_addr (server);
1041
- if (HostAddr == INADDR_NONE) {
1042
- hostent *hp = gethostbyname ((char*)server); // Windows requires (char*)
1043
- if (!hp) {
1044
- // TODO: This gives the caller a fatal error. Not good.
1045
- // They can respond by catching RuntimeError (blecch).
1046
- // Possibly we need to fire an unbind event and provide
1047
- // a status code so user code can detect the cause of the
1048
- // failure.
1049
- return NULL;
1050
- }
1051
- HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
1098
+ if (sd == INVALID_SOCKET) {
1099
+ char buf [200];
1100
+ snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
1101
+ throw std::runtime_error (buf);
1052
1102
  }
1053
1103
 
1054
- memset (&pin, 0, sizeof(pin));
1055
- pin.sin_family = AF_INET;
1056
- pin.sin_addr.s_addr = HostAddr;
1057
- pin.sin_port = htons (port);
1058
-
1059
- int sd = socket (AF_INET, SOCK_STREAM, 0);
1060
- if (sd == INVALID_SOCKET)
1061
- return NULL;
1062
- */
1063
-
1064
1104
  // From here on, ALL error returns must close the socket.
1065
1105
  // Set the new socket nonblocking.
1066
1106
  if (!SetSocketNonblocking (sd)) {
1067
- closesocket (sd);
1107
+ close (sd);
1068
1108
  throw std::runtime_error ("unable to set socket as non-blocking");
1069
1109
  }
1070
1110
  // Disable slow-start (Nagle algorithm).
@@ -1077,16 +1117,17 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1077
1117
  int bind_to_size, bind_to_family;
1078
1118
  struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
1079
1119
  if (!bind_to) {
1080
- closesocket (sd);
1120
+ close (sd);
1081
1121
  throw std::runtime_error ("invalid bind address");
1082
1122
  }
1083
1123
  if (bind (sd, bind_to, bind_to_size) < 0) {
1084
- closesocket (sd);
1124
+ close (sd);
1085
1125
  throw std::runtime_error ("couldn't bind to address");
1086
1126
  }
1087
1127
  }
1088
1128
 
1089
- unsigned long out = NULL;
1129
+ unsigned long out = 0;
1130
+ int e = 0;
1090
1131
 
1091
1132
  #ifdef OS_UNIX
1092
1133
  //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
@@ -1120,7 +1161,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1120
1161
  else if (errno == EINPROGRESS) {
1121
1162
  // Errno will generally always be EINPROGRESS, but on Linux
1122
1163
  // we have to look at getsockopt to be sure what really happened.
1123
- int error;
1164
+ int error = 0;
1124
1165
  socklen_t len;
1125
1166
  len = sizeof(error);
1126
1167
  int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
@@ -1134,30 +1175,37 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1134
1175
  cd->SetConnectPending (true);
1135
1176
  Add (cd);
1136
1177
  out = cd->GetBinding();
1137
- }
1138
- else {
1139
- /* This could be connection refused or some such thing.
1140
- * We will come here on Linux if a localhost connection fails.
1141
- * Changed 16Jul06: Originally this branch was a no-op, and
1142
- * we'd drop down to the end of the method, close the socket,
1143
- * and return NULL, which would cause the caller to GET A
1144
- * FATAL EXCEPTION. Now we keep the socket around but schedule an
1145
- * immediate close on it, so the caller will get a close-event
1146
- * scheduled on it. This was only an issue for localhost connections
1147
- * to non-listening ports. We may eventually need to revise this
1148
- * revised behavior, in case it causes problems like making it hard
1149
- * for people to know that a failure occurred.
1150
- */
1151
- ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1152
- if (!cd)
1153
- throw std::runtime_error ("no connection allocated");
1154
- cd->ScheduleClose (false);
1155
- Add (cd);
1156
- out = cd->GetBinding();
1178
+ } else {
1179
+ // Fall through to the !out case below.
1180
+ e = error;
1157
1181
  }
1158
1182
  }
1159
1183
  else {
1160
- // The error from connect was something other then EINPROGRESS.
1184
+ // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
1185
+ // Fall through to the !out case below
1186
+ e = errno;
1187
+ }
1188
+
1189
+ if (!out) {
1190
+ /* This could be connection refused or some such thing.
1191
+ * We will come here on Linux if a localhost connection fails.
1192
+ * Changed 16Jul06: Originally this branch was a no-op, and
1193
+ * we'd drop down to the end of the method, close the socket,
1194
+ * and return NULL, which would cause the caller to GET A
1195
+ * FATAL EXCEPTION. Now we keep the socket around but schedule an
1196
+ * immediate close on it, so the caller will get a close-event
1197
+ * scheduled on it. This was only an issue for localhost connections
1198
+ * to non-listening ports. We may eventually need to revise this
1199
+ * revised behavior, in case it causes problems like making it hard
1200
+ * for people to know that a failure occurred.
1201
+ */
1202
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1203
+ if (!cd)
1204
+ throw std::runtime_error ("no connection allocated");
1205
+ cd->SetUnbindReasonCode(e);
1206
+ cd->ScheduleClose (false);
1207
+ Add (cd);
1208
+ out = cd->GetBinding();
1161
1209
  }
1162
1210
  #endif
1163
1211
 
@@ -1190,7 +1238,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1190
1238
  #endif
1191
1239
 
1192
1240
  if (!out)
1193
- closesocket (sd);
1241
+ close (sd);
1194
1242
  return out;
1195
1243
  }
1196
1244
 
@@ -1215,10 +1263,10 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1215
1263
  // The whole rest of this function is only compiled on Unix systems.
1216
1264
  #ifdef OS_UNIX
1217
1265
 
1218
- unsigned long out = NULL;
1266
+ unsigned long out = 0;
1219
1267
 
1220
1268
  if (!server || !*server)
1221
- return NULL;
1269
+ return 0;
1222
1270
 
1223
1271
  sockaddr_un pun;
1224
1272
  memset (&pun, 0, sizeof(pun));
@@ -1234,19 +1282,19 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1234
1282
 
1235
1283
  int fd = socket (AF_LOCAL, SOCK_STREAM, 0);
1236
1284
  if (fd == INVALID_SOCKET)
1237
- return NULL;
1285
+ return 0;
1238
1286
 
1239
1287
  // From here on, ALL error returns must close the socket.
1240
1288
  // NOTE: At this point, the socket is still a blocking socket.
1241
1289
  if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) {
1242
- closesocket (fd);
1243
- return NULL;
1290
+ close (fd);
1291
+ return 0;
1244
1292
  }
1245
1293
 
1246
1294
  // Set the newly-connected socket nonblocking.
1247
1295
  if (!SetSocketNonblocking (fd)) {
1248
- closesocket (fd);
1249
- return NULL;
1296
+ close (fd);
1297
+ return 0;
1250
1298
  }
1251
1299
 
1252
1300
  // Set up a connection descriptor and add it to the event-machine.
@@ -1261,7 +1309,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1261
1309
  out = cd->GetBinding();
1262
1310
 
1263
1311
  if (!out)
1264
- closesocket (fd);
1312
+ close (fd);
1265
1313
 
1266
1314
  return out;
1267
1315
  #endif
@@ -1450,9 +1498,9 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1450
1498
  int family, bind_size;
1451
1499
  struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1452
1500
  if (!bind_here)
1453
- return NULL;
1501
+ return 0;
1454
1502
 
1455
- unsigned long output_binding = NULL;
1503
+ unsigned long output_binding = 0;
1456
1504
 
1457
1505
  //struct sockaddr_in sin;
1458
1506
 
@@ -1461,25 +1509,6 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1461
1509
  goto fail;
1462
1510
  }
1463
1511
 
1464
- /*
1465
- memset (&sin, 0, sizeof(sin));
1466
- sin.sin_family = AF_INET;
1467
- sin.sin_addr.s_addr = INADDR_ANY;
1468
- sin.sin_port = htons (port);
1469
-
1470
- if (server && *server) {
1471
- sin.sin_addr.s_addr = inet_addr (server);
1472
- if (sin.sin_addr.s_addr == INADDR_NONE) {
1473
- hostent *hp = gethostbyname ((char*)server); // Windows requires the cast.
1474
- if (hp == NULL) {
1475
- //__warning ("hostname not resolved: ", server);
1476
- goto fail;
1477
- }
1478
- sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1479
- }
1480
- }
1481
- */
1482
-
1483
1512
  { // set reuseaddr to improve performance on restarts.
1484
1513
  int oval = 1;
1485
1514
  if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) {
@@ -1531,8 +1560,8 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1531
1560
 
1532
1561
  fail:
1533
1562
  if (sd_accept != INVALID_SOCKET)
1534
- closesocket (sd_accept);
1535
- return NULL;
1563
+ close (sd_accept);
1564
+ return 0;
1536
1565
  }
1537
1566
 
1538
1567
 
@@ -1542,7 +1571,7 @@ EventMachine_t::OpenDatagramSocket
1542
1571
 
1543
1572
  const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int port)
1544
1573
  {
1545
- unsigned long output_binding = NULL;
1574
+ unsigned long output_binding = 0;
1546
1575
 
1547
1576
  int sd = socket (AF_INET, SOCK_DGRAM, 0);
1548
1577
  if (sd == INVALID_SOCKET)
@@ -1592,8 +1621,8 @@ const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int
1592
1621
 
1593
1622
  fail:
1594
1623
  if (sd != INVALID_SOCKET)
1595
- closesocket (sd);
1596
- return NULL;
1624
+ close (sd);
1625
+ return 0;
1597
1626
  }
1598
1627
 
1599
1628
 
@@ -1702,6 +1731,7 @@ void EventMachine_t::_AddNewDescriptors()
1702
1731
  */
1703
1732
  #endif
1704
1733
 
1734
+ QueueHeartbeat(ed);
1705
1735
  Descriptors.push_back (ed);
1706
1736
  }
1707
1737
  NewDescriptors.clear();
@@ -1758,28 +1788,31 @@ void EventMachine_t::Modify (EventableDescriptor *ed)
1758
1788
  }
1759
1789
 
1760
1790
 
1761
- /***********************************
1762
- EventMachine_t::_OpenFileForWriting
1763
- ***********************************/
1791
+ /***********************
1792
+ EventMachine_t::Closing
1793
+ ***********************/
1764
1794
 
1765
- const unsigned long EventMachine_t::_OpenFileForWriting (const char *filename)
1795
+ void EventMachine_t::Closing (EventableDescriptor *ed)
1766
1796
  {
1767
- /*
1768
- * Return the binding-text of the newly-opened file,
1769
- * or NULL if there was a problem.
1770
- */
1771
-
1772
- if (!filename || !*filename)
1773
- return NULL;
1774
-
1775
- int fd = open (filename, O_CREAT|O_TRUNC|O_WRONLY|O_NONBLOCK, 0644);
1776
-
1777
- FileStreamDescriptor *fsd = new FileStreamDescriptor (fd, this);
1778
- if (!fsd)
1779
- throw std::runtime_error ("no file-stream allocated");
1780
- Add (fsd);
1781
- return fsd->GetBinding();
1782
-
1797
+ if (!ed)
1798
+ throw std::runtime_error ("modified bad descriptor");
1799
+ #ifdef HAVE_EPOLL
1800
+ // cut/paste from _CleanupSockets(). The error handling could be
1801
+ // refactored out of there, but it is cut/paste all over the
1802
+ // file already.
1803
+ if (bEpoll) {
1804
+ assert (epfd != -1);
1805
+ assert (ed->GetSocket() != INVALID_SOCKET);
1806
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
1807
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
1808
+ if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
1809
+ char buf [200];
1810
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
1811
+ throw std::runtime_error (buf);
1812
+ }
1813
+ ModifiedDescriptors.erase(ed);
1814
+ }
1815
+ #endif
1783
1816
  }
1784
1817
 
1785
1818
 
@@ -1802,7 +1835,7 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1802
1835
 
1803
1836
  // The whole rest of this function is only compiled on Unix systems.
1804
1837
  #ifdef OS_UNIX
1805
- unsigned long output_binding = NULL;
1838
+ unsigned long output_binding = 0;
1806
1839
 
1807
1840
  struct sockaddr_un s_sun;
1808
1841
 
@@ -1862,8 +1895,8 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1862
1895
 
1863
1896
  fail:
1864
1897
  if (sd_accept != INVALID_SOCKET)
1865
- closesocket (sd_accept);
1866
- return NULL;
1898
+ close (sd_accept);
1899
+ return 0;
1867
1900
  #endif // OS_UNIX
1868
1901
  }
1869
1902
 
@@ -1924,18 +1957,18 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1924
1957
  #ifdef OS_UNIX
1925
1958
  // Make sure the incoming array of command strings is sane.
1926
1959
  if (!cmd_strings)
1927
- return NULL;
1960
+ return 0;
1928
1961
  int j;
1929
- for (j=0; j < 100 && cmd_strings[j]; j++)
1962
+ for (j=0; j < 2048 && cmd_strings[j]; j++)
1930
1963
  ;
1931
- if ((j==0) || (j==100))
1932
- return NULL;
1964
+ if ((j==0) || (j==2048))
1965
+ return 0;
1933
1966
 
1934
- unsigned long output_binding = NULL;
1967
+ unsigned long output_binding = 0;
1935
1968
 
1936
1969
  int sv[2];
1937
1970
  if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
1938
- return NULL;
1971
+ return 0;
1939
1972
  // from here, all early returns must close the pair of sockets.
1940
1973
 
1941
1974
  // Set the parent side of the socketpair nonblocking.
@@ -1945,7 +1978,7 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1945
1978
  if (!SetSocketNonblocking (sv[0])) {
1946
1979
  close (sv[0]);
1947
1980
  close (sv[1]);
1948
- return NULL;
1981
+ return 0;
1949
1982
  }
1950
1983
 
1951
1984
  pid_t f = fork();
@@ -2005,7 +2038,7 @@ const unsigned long EventMachine_t::WatchPid (int pid)
2005
2038
  {
2006
2039
  #ifdef HAVE_KQUEUE
2007
2040
  if (!bKqueue)
2008
- throw std::runtime_error("must enable kqueue");
2041
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support");
2009
2042
 
2010
2043
  struct kevent event;
2011
2044
  int kqres;
@@ -2094,7 +2127,8 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2094
2127
  Add(inotify);
2095
2128
  }
2096
2129
 
2097
- wd = inotify_add_watch(inotify->GetSocket(), fpath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF);
2130
+ wd = inotify_add_watch(inotify->GetSocket(), fpath,
2131
+ IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_MOVE) ;
2098
2132
  if (wd == -1) {
2099
2133
  char errbuf[300];
2100
2134
  sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno));
@@ -2104,7 +2138,7 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2104
2138
 
2105
2139
  #ifdef HAVE_KQUEUE
2106
2140
  if (!bKqueue)
2107
- throw std::runtime_error("must enable kqueue");
2141
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support");
2108
2142
 
2109
2143
  // With kqueue we have to open the file first and use the resulting fd to register for events
2110
2144
  wd = open(fpath, O_RDONLY);
@@ -2170,19 +2204,33 @@ EventMachine_t::_ReadInotify_Events
2170
2204
  void EventMachine_t::_ReadInotifyEvents()
2171
2205
  {
2172
2206
  #ifdef HAVE_INOTIFY
2173
- struct inotify_event event;
2207
+ char buffer[1024];
2174
2208
 
2175
2209
  assert(EventCallback);
2176
2210
 
2177
- while (read(inotify->GetSocket(), &event, INOTIFY_EVENT_SIZE) > 0) {
2178
- assert(event.len == 0);
2179
- if (event.mask & IN_MODIFY)
2180
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "modified", 8);
2181
- if (event.mask & IN_MOVE_SELF)
2182
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "moved", 5);
2183
- if (event.mask & IN_DELETE_SELF) {
2184
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
2185
- UnwatchFile ((int)event.wd);
2211
+ for (;;) {
2212
+ int returned = read(inotify->GetSocket(), buffer, sizeof(buffer));
2213
+ assert(!(returned == 0 || returned == -1 && errno == EINVAL));
2214
+ if (returned <= 0) {
2215
+ break;
2216
+ }
2217
+ int current = 0;
2218
+ while (current < returned) {
2219
+ struct inotify_event* event = (struct inotify_event*)(buffer+current);
2220
+ map<int, Bindable_t*>::const_iterator bindable = Files.find(event->wd);
2221
+ if (bindable != Files.end()) {
2222
+ if (event->mask & (IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE)){
2223
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "modified", 8);
2224
+ }
2225
+ if (event->mask & IN_MOVE_SELF){
2226
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "moved", 5);
2227
+ }
2228
+ if (event->mask & IN_DELETE_SELF) {
2229
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
2230
+ UnwatchFile ((int)event->wd);
2231
+ }
2232
+ }
2233
+ current += sizeof(struct inotify_event) + event->len;
2186
2234
  }
2187
2235
  }
2188
2236
  #endif