eventmachine 0.12.10-x86-mswin32-60 → 1.0.0.beta.2-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +1 -0
  3. data/README +80 -81
  4. data/Rakefile +7 -370
  5. data/docs/COPYING +60 -60
  6. data/docs/ChangeLog +211 -211
  7. data/docs/DEFERRABLES +246 -133
  8. data/docs/EPOLL +141 -141
  9. data/docs/GNU +281 -281
  10. data/docs/INSTALL +13 -13
  11. data/docs/KEYBOARD +42 -38
  12. data/docs/LEGAL +25 -25
  13. data/docs/LIGHTWEIGHT_CONCURRENCY +130 -70
  14. data/docs/PURE_RUBY +75 -75
  15. data/docs/RELEASE_NOTES +94 -94
  16. data/docs/SMTP +4 -2
  17. data/docs/SPAWNED_PROCESSES +148 -89
  18. data/docs/TODO +8 -8
  19. data/eventmachine.gemspec +19 -26
  20. data/examples/ex_channel.rb +42 -42
  21. data/examples/ex_queue.rb +2 -2
  22. data/examples/ex_tick_loop_array.rb +15 -0
  23. data/examples/ex_tick_loop_counter.rb +32 -0
  24. data/examples/helper.rb +1 -1
  25. data/ext/binder.cpp +0 -1
  26. data/ext/cmain.cpp +36 -25
  27. data/ext/ed.cpp +104 -113
  28. data/ext/ed.h +24 -30
  29. data/ext/em.cpp +349 -283
  30. data/ext/em.h +25 -29
  31. data/ext/eventmachine.h +5 -4
  32. data/ext/extconf.rb +58 -49
  33. data/ext/fastfilereader/extconf.rb +5 -3
  34. data/ext/fastfilereader/mapper.cpp +214 -214
  35. data/ext/fastfilereader/mapper.h +59 -59
  36. data/ext/fastfilereader/rubymain.cpp +127 -127
  37. data/ext/kb.cpp +1 -3
  38. data/ext/page.cpp +107 -107
  39. data/ext/page.h +51 -51
  40. data/ext/pipe.cpp +9 -11
  41. data/ext/project.h +12 -8
  42. data/ext/rubymain.cpp +138 -104
  43. data/java/.classpath +8 -8
  44. data/java/.project +17 -17
  45. data/java/src/com/rubyeventmachine/EmReactor.java +1 -0
  46. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -40
  47. data/lib/em/buftok.rb +138 -138
  48. data/lib/em/callback.rb +25 -25
  49. data/lib/em/channel.rb +1 -1
  50. data/lib/em/connection.rb +6 -1
  51. data/lib/em/deferrable.rb +16 -2
  52. data/lib/em/file_watch.rb +53 -53
  53. data/lib/em/future.rb +61 -61
  54. data/lib/em/iterator.rb +270 -0
  55. data/lib/em/messages.rb +66 -66
  56. data/lib/em/process_watch.rb +43 -43
  57. data/lib/em/protocols.rb +1 -1
  58. data/lib/em/protocols/header_and_content.rb +138 -138
  59. data/lib/em/protocols/httpclient.rb +267 -262
  60. data/lib/em/protocols/line_protocol.rb +28 -0
  61. data/lib/em/protocols/memcache.rb +322 -322
  62. data/lib/em/protocols/postgres3.rb +247 -247
  63. data/lib/em/protocols/saslauth.rb +175 -175
  64. data/lib/em/protocols/smtpserver.rb +640 -547
  65. data/lib/em/protocols/stomp.rb +200 -200
  66. data/lib/em/protocols/tcptest.rb +52 -52
  67. data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +1013 -1022
  68. data/lib/em/queue.rb +1 -0
  69. data/lib/em/spawnable.rb +85 -85
  70. data/lib/em/streamer.rb +130 -130
  71. data/lib/em/tick_loop.rb +85 -0
  72. data/lib/em/timers.rb +2 -1
  73. data/lib/em/version.rb +1 -1
  74. data/lib/eventmachine.rb +40 -84
  75. data/lib/jeventmachine.rb +2 -1
  76. data/lib/rubyeventmachine.rb +2 -0
  77. data/setup.rb +1585 -1585
  78. data/tasks/doc.rake +30 -0
  79. data/tasks/package.rake +85 -0
  80. data/tasks/test.rake +6 -0
  81. data/tests/client.crt +31 -31
  82. data/tests/client.key +51 -51
  83. data/tests/test_attach.rb +13 -3
  84. data/tests/test_basic.rb +60 -95
  85. data/tests/test_channel.rb +3 -2
  86. data/tests/test_defer.rb +49 -47
  87. data/tests/test_deferrable.rb +35 -0
  88. data/tests/test_error_handler.rb +35 -35
  89. data/tests/test_errors.rb +82 -82
  90. data/tests/test_exc.rb +55 -55
  91. data/tests/test_file_watch.rb +49 -49
  92. data/tests/test_futures.rb +198 -198
  93. data/tests/test_handler_check.rb +36 -36
  94. data/tests/test_hc.rb +190 -218
  95. data/tests/test_httpclient.rb +227 -218
  96. data/tests/test_httpclient2.rb +3 -2
  97. data/tests/test_inactivity_timeout.rb +3 -3
  98. data/tests/test_kb.rb +60 -60
  99. data/tests/test_ltp.rb +13 -5
  100. data/tests/test_ltp2.rb +317 -317
  101. data/tests/test_next_tick.rb +1 -1
  102. data/tests/test_object_protocol.rb +36 -36
  103. data/tests/test_pending_connect_timeout.rb +2 -2
  104. data/tests/test_process_watch.rb +50 -48
  105. data/tests/test_proxy_connection.rb +52 -0
  106. data/tests/test_pure.rb +134 -125
  107. data/tests/test_queue.rb +44 -44
  108. data/tests/test_running.rb +42 -42
  109. data/tests/test_sasl.rb +72 -72
  110. data/tests/test_send_file.rb +251 -242
  111. data/tests/test_servers.rb +76 -76
  112. data/tests/test_smtpclient.rb +83 -83
  113. data/tests/test_smtpserver.rb +85 -85
  114. data/tests/test_spawn.rb +322 -322
  115. data/tests/test_ssl_methods.rb +49 -49
  116. data/tests/test_ssl_verify.rb +82 -82
  117. data/tests/test_tick_loop.rb +59 -0
  118. data/tests/test_timers.rb +13 -15
  119. data/tests/test_ud.rb +36 -36
  120. data/tests/testem.rb +31 -31
  121. metadata +66 -51
  122. data/ext/cplusplus.cpp +0 -202
  123. data/ext/emwin.cpp +0 -300
  124. data/ext/emwin.h +0 -94
  125. data/ext/epoll.cpp +0 -26
  126. data/ext/epoll.h +0 -25
  127. data/ext/eventmachine_cpp.h +0 -96
  128. data/ext/files.cpp +0 -94
  129. data/ext/files.h +0 -65
  130. data/ext/sigs.cpp +0 -89
  131. data/ext/sigs.h +0 -32
  132. data/java/src/com/rubyeventmachine/application/Application.java +0 -194
  133. data/java/src/com/rubyeventmachine/application/Connection.java +0 -74
  134. data/java/src/com/rubyeventmachine/application/ConnectionFactory.java +0 -37
  135. data/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +0 -46
  136. data/java/src/com/rubyeventmachine/application/PeriodicTimer.java +0 -38
  137. data/java/src/com/rubyeventmachine/application/Timer.java +0 -54
  138. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +0 -109
  139. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +0 -148
  140. data/java/src/com/rubyeventmachine/tests/EMTest.java +0 -80
  141. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +0 -53
  142. data/java/src/com/rubyeventmachine/tests/TestServers.java +0 -75
  143. data/java/src/com/rubyeventmachine/tests/TestTimers.java +0 -90
  144. data/lib/evma.rb +0 -32
  145. data/lib/evma/callback.rb +0 -32
  146. data/lib/evma/container.rb +0 -75
  147. data/lib/evma/factory.rb +0 -77
  148. data/lib/evma/protocol.rb +0 -87
  149. data/lib/evma/reactor.rb +0 -48
  150. data/web/whatis +0 -7
data/ext/ed.h CHANGED
@@ -62,7 +62,7 @@ class EventableDescriptor: public Bindable_t
62
62
  bool IsCloseScheduled();
63
63
  virtual void HandleError(){ ScheduleClose (false); }
64
64
 
65
- void SetEventCallback (void (*cb)(const unsigned long, int, const char*, const unsigned long));
65
+ void SetEventCallback (EMCallback);
66
66
 
67
67
  virtual bool GetPeername (struct sockaddr*) {return false;}
68
68
  virtual bool GetSockname (struct sockaddr*) {return false;}
@@ -75,16 +75,16 @@ class EventableDescriptor: public Bindable_t
75
75
  virtual X509 *GetPeerCert() {return NULL;}
76
76
  #endif
77
77
 
78
- virtual float GetCommInactivityTimeout() {return 0.0;}
79
- virtual int SetCommInactivityTimeout (float value) {return 0;}
80
- float GetPendingConnectTimeout();
81
- int SetPendingConnectTimeout (float value);
78
+ virtual uint64_t GetCommInactivityTimeout() {return 0;}
79
+ virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
80
+ uint64_t GetPendingConnectTimeout();
81
+ int SetPendingConnectTimeout (uint64_t value);
82
82
 
83
83
  #ifdef HAVE_EPOLL
84
84
  struct epoll_event *GetEpollEvent() { return &EpollEvent; }
85
85
  #endif
86
86
 
87
- virtual void StartProxy(const unsigned long, const unsigned long);
87
+ virtual void StartProxy(const unsigned long, const unsigned long, const unsigned long);
88
88
  virtual void StopProxy();
89
89
  virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
90
90
  virtual int SendOutboundData(const char*,int){ return -1; }
@@ -92,6 +92,10 @@ class EventableDescriptor: public Bindable_t
92
92
  virtual bool Pause(){ return false; }
93
93
  virtual bool Resume(){ return false; }
94
94
 
95
+ virtual int ReportErrorStatus(){ return 0; }
96
+ virtual bool IsConnectPending(){ return false; }
97
+ virtual uint64_t GetNextHeartbeat();
98
+
95
99
  private:
96
100
  bool bCloseNow;
97
101
  bool bCloseAfterWriting;
@@ -99,12 +103,14 @@ class EventableDescriptor: public Bindable_t
99
103
  protected:
100
104
  int MySocket;
101
105
 
102
- void (*EventCallback)(const unsigned long, int, const char*, const unsigned long);
106
+ EMCallback EventCallback;
103
107
  void _GenericInboundDispatch(const char*, int);
104
108
 
105
- Int64 CreatedAt;
109
+ uint64_t CreatedAt;
106
110
  bool bCallbackUnbind;
107
111
  int UnbindReasonCode;
112
+
113
+ unsigned long BytesToProxy;
108
114
  EventableDescriptor *ProxyTarget;
109
115
  EventableDescriptor *ProxiedFrom;
110
116
 
@@ -115,7 +121,10 @@ class EventableDescriptor: public Bindable_t
115
121
  #endif
116
122
 
117
123
  EventMachine_t *MyEventMachine;
118
- int PendingConnectTimeout;
124
+ uint64_t PendingConnectTimeout;
125
+ uint64_t InactivityTimeout;
126
+ uint64_t LastActivity;
127
+ uint64_t NextHeartbeat;
119
128
  };
120
129
 
121
130
 
@@ -149,10 +158,6 @@ class ConnectionDescriptor: public EventableDescriptor
149
158
  ConnectionDescriptor (int, EventMachine_t*);
150
159
  virtual ~ConnectionDescriptor();
151
160
 
152
- static int SendDataToConnection (const unsigned long, const char*, int);
153
- static void CloseConnection (const unsigned long, bool);
154
- static int ReportErrorStatus (const unsigned long);
155
-
156
161
  int SendOutboundData (const char*, int);
157
162
 
158
163
  void SetConnectPending (bool f);
@@ -195,9 +200,11 @@ class ConnectionDescriptor: public EventableDescriptor
195
200
  virtual bool GetPeername (struct sockaddr*);
196
201
  virtual bool GetSockname (struct sockaddr*);
197
202
 
198
- virtual float GetCommInactivityTimeout();
199
- virtual int SetCommInactivityTimeout (float value);
203
+ virtual uint64_t GetCommInactivityTimeout();
204
+ virtual int SetCommInactivityTimeout (uint64_t value);
200
205
 
206
+ virtual int ReportErrorStatus();
207
+ virtual bool IsConnectPending(){ return bConnectPending; }
201
208
 
202
209
  protected:
203
210
  struct OutboundPage {
@@ -236,8 +243,6 @@ class ConnectionDescriptor: public EventableDescriptor
236
243
  #endif
237
244
 
238
245
  bool bIsServer;
239
- Int64 LastIo;
240
- int InactivityTimeout;
241
246
 
242
247
  private:
243
248
  void _UpdateEvents();
@@ -246,7 +251,6 @@ class ConnectionDescriptor: public EventableDescriptor
246
251
  void _DispatchInboundData (const char *buffer, int size);
247
252
  void _DispatchCiphertext();
248
253
  int _SendRawOutboundData (const char*, int);
249
- int _ReportErrorStatus();
250
254
  void _CheckHandshakeStatus();
251
255
 
252
256
  };
@@ -278,11 +282,8 @@ class DatagramDescriptor: public EventableDescriptor
278
282
  virtual bool GetPeername (struct sockaddr*);
279
283
  virtual bool GetSockname (struct sockaddr*);
280
284
 
281
- virtual float GetCommInactivityTimeout();
282
- virtual int SetCommInactivityTimeout (float value);
283
-
284
- static int SendDatagram (const unsigned long, const char*, int, const char*, int);
285
-
285
+ virtual uint64_t GetCommInactivityTimeout();
286
+ virtual int SetCommInactivityTimeout (uint64_t value);
286
287
 
287
288
  protected:
288
289
  struct OutboundPage {
@@ -298,9 +299,6 @@ class DatagramDescriptor: public EventableDescriptor
298
299
  int OutboundDataSize;
299
300
 
300
301
  struct sockaddr_in ReturnAddress;
301
-
302
- Int64 LastIo;
303
- int InactivityTimeout;
304
302
  };
305
303
 
306
304
 
@@ -360,8 +358,6 @@ class PipeDescriptor: public EventableDescriptor
360
358
 
361
359
  protected:
362
360
  bool bReadAttemptedAfterClose;
363
- Int64 LastIo;
364
- int InactivityTimeout;
365
361
 
366
362
  deque<OutboundPage> OutboundPages;
367
363
  int OutboundDataSize;
@@ -393,8 +389,6 @@ class KeyboardDescriptor: public EventableDescriptor
393
389
 
394
390
  protected:
395
391
  bool bReadAttemptedAfterClose;
396
- Int64 LastIo;
397
- int InactivityTimeout;
398
392
 
399
393
  private:
400
394
  void _DispatchInboundData (const char *buffer, int size);
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,7 +304,7 @@ 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];
@@ -353,21 +341,76 @@ EventMachine_t::_UpdateTime
353
341
 
354
342
  void EventMachine_t::_UpdateTime()
355
343
  {
344
+ MyCurrentLoopTime = GetRealTime();
345
+ }
346
+
347
+ /***************************
348
+ EventMachine_t::GetRealTime
349
+ ***************************/
350
+
351
+ uint64_t EventMachine_t::GetRealTime()
352
+ {
353
+ uint64_t current_time;
356
354
  #if defined(OS_UNIX)
357
355
  struct timeval tv;
358
356
  gettimeofday (&tv, NULL);
359
- gCurrentLoopTime = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
357
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
360
358
 
361
359
  #elif defined(OS_WIN32)
362
360
  unsigned tick = GetTickCount();
363
- if (tick < gLastTickCount)
364
- gTickCountTickover += 1;
365
- gLastTickCount = tick;
366
- gCurrentLoopTime = ((Int64)gTickCountTickover << 32) + (Int64)tick;
361
+ if (tick < LastTickCount)
362
+ TickCountTickover += 1;
363
+ LastTickCount = tick;
364
+ current_time = ((uint64_t)TickCountTickover << 32) + (uint64_t)tick;
367
365
 
368
366
  #else
369
- gCurrentLoopTime = (Int64)time(NULL) * 1000000LL;
367
+ current_time = (uint64_t)time(NULL) * 1000000LL;
370
368
  #endif
369
+ return current_time;
370
+ }
371
+
372
+ /***********************************
373
+ EventMachine_t::_DispatchHeartbeats
374
+ ***********************************/
375
+
376
+ void EventMachine_t::_DispatchHeartbeats()
377
+ {
378
+ while (true) {
379
+ multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
380
+ if (i == Heartbeats.end())
381
+ break;
382
+ if (i->first > MyCurrentLoopTime)
383
+ break;
384
+ EventableDescriptor *ed = i->second;
385
+ ed->Heartbeat();
386
+ QueueHeartbeat(ed);
387
+ }
388
+ }
389
+
390
+ /******************************
391
+ EventMachine_t::QueueHeartbeat
392
+ ******************************/
393
+
394
+ void EventMachine_t::QueueHeartbeat(EventableDescriptor *ed)
395
+ {
396
+ uint64_t heartbeat = ed->GetNextHeartbeat();
397
+
398
+ if (heartbeat) {
399
+ #ifndef HAVE_MAKE_PAIR
400
+ Heartbeats.insert (multimap<uint64_t,EventableDescriptor*>::value_type (heartbeat, ed));
401
+ #else
402
+ Heartbeats.insert (make_pair (heartbeat, ed));
403
+ #endif
404
+ }
405
+ }
406
+
407
+ /******************************
408
+ EventMachine_t::ClearHeartbeat
409
+ ******************************/
410
+
411
+ void EventMachine_t::ClearHeartbeat(uint64_t key)
412
+ {
413
+ Heartbeats.erase(key);
371
414
  }
372
415
 
373
416
  /*******************
@@ -376,10 +419,6 @@ EventMachine_t::Run
376
419
 
377
420
  void EventMachine_t::Run()
378
421
  {
379
- #ifdef OS_WIN32
380
- HookControlC (true);
381
- #endif
382
-
383
422
  #ifdef HAVE_EPOLL
384
423
  if (bEpoll) {
385
424
  epfd = epoll_create (MaxEpollDescriptors);
@@ -431,13 +470,9 @@ void EventMachine_t::Run()
431
470
 
432
471
  if (!_RunOnce())
433
472
  break;
434
- if (gTerminateSignalReceived)
473
+ if (bTerminateSignalReceived)
435
474
  break;
436
475
  }
437
-
438
- #ifdef OS_WIN32
439
- HookControlC (false);
440
- #endif
441
476
  }
442
477
 
443
478
 
@@ -447,12 +482,16 @@ EventMachine_t::_RunOnce
447
482
 
448
483
  bool EventMachine_t::_RunOnce()
449
484
  {
485
+ bool ret;
450
486
  if (bEpoll)
451
- return _RunEpollOnce();
487
+ ret = _RunEpollOnce();
452
488
  else if (bKqueue)
453
- return _RunKqueueOnce();
489
+ ret = _RunKqueueOnce();
454
490
  else
455
- return _RunSelectOnce();
491
+ ret = _RunSelectOnce();
492
+ _DispatchHeartbeats();
493
+ _CleanupSockets();
494
+ return ret;
456
495
  }
457
496
 
458
497
 
@@ -467,12 +506,31 @@ bool EventMachine_t::_RunEpollOnce()
467
506
  assert (epfd != -1);
468
507
  int s;
469
508
 
509
+ timeval tv = _TimeTilNextEvent();
510
+
470
511
  #ifdef BUILD_FOR_RUBY
512
+ int ret = 0;
513
+ fd_set fdreads;
514
+
515
+ FD_ZERO(&fdreads);
516
+ FD_SET(epfd, &fdreads);
517
+
518
+ if ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
519
+ if (ret == -1) {
520
+ assert(errno != EINVAL);
521
+ assert(errno != EBADF);
522
+ }
523
+ return true;
524
+ }
525
+
471
526
  TRAP_BEG;
472
- #endif
473
- s = epoll_wait (epfd, epoll_events, MaxEvents, 50);
474
- #ifdef BUILD_FOR_RUBY
527
+ s = epoll_wait (epfd, epoll_events, MaxEvents, 0);
475
528
  TRAP_END;
529
+ #else
530
+ int duration = 0;
531
+ duration = duration + (tv.tv_sec * 1000);
532
+ duration = duration + (tv.tv_usec / 1000);
533
+ s = epoll_wait (epfd, epoll_events, MaxEvents, duration);
476
534
  #endif
477
535
 
478
536
  if (s > 0) {
@@ -501,72 +559,6 @@ bool EventMachine_t::_RunEpollOnce()
501
559
  EmSelect (0, NULL, NULL, NULL, &tv);
502
560
  }
503
561
 
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
- #ifdef BUILD_FOR_RUBY
565
- if (!rb_thread_alone()) {
566
- rb_thread_schedule();
567
- }
568
- #endif
569
-
570
562
  return true;
571
563
  #else
572
564
  throw std::runtime_error ("epoll is not implemented on this platform");
@@ -582,15 +574,33 @@ bool EventMachine_t::_RunKqueueOnce()
582
574
  {
583
575
  #ifdef HAVE_KQUEUE
584
576
  assert (kqfd != -1);
585
- struct timespec ts = {0, 10000000}; // Too frequent. Use blocking_region
586
-
587
577
  int k;
578
+
579
+ timeval tv = _TimeTilNextEvent();
580
+
588
581
  #ifdef BUILD_FOR_RUBY
582
+ int ret = 0;
583
+ fd_set fdreads;
584
+
585
+ FD_ZERO(&fdreads);
586
+ FD_SET(kqfd, &fdreads);
587
+
588
+ if ((ret = rb_thread_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
589
+ if (ret == -1) {
590
+ assert(errno != EINVAL);
591
+ assert(errno != EBADF);
592
+ }
593
+ return true;
594
+ }
595
+
589
596
  TRAP_BEG;
590
- #endif
591
- k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
592
- #ifdef BUILD_FOR_RUBY
597
+ k = kevent (kqfd, NULL, 0, Karray, MaxEvents, NULL);
593
598
  TRAP_END;
599
+ #else
600
+ struct timespec ts;
601
+ ts.tv_sec = tv.tv_sec;
602
+ ts.tv_nsec = tv.tv_usec * 1000;
603
+ k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
594
604
  #endif
595
605
 
596
606
  struct kevent *ke = Karray;
@@ -627,42 +637,6 @@ bool EventMachine_t::_RunKqueueOnce()
627
637
  ++ke;
628
638
  }
629
639
 
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
640
  // TODO, replace this with rb_thread_blocking_region for 1.9 builds.
667
641
  #ifdef BUILD_FOR_RUBY
668
642
  if (!rb_thread_alone()) {
@@ -677,6 +651,93 @@ bool EventMachine_t::_RunKqueueOnce()
677
651
  }
678
652
 
679
653
 
654
+ /*********************************
655
+ EventMachine_t::_TimeTilNextEvent
656
+ *********************************/
657
+
658
+ timeval EventMachine_t::_TimeTilNextEvent()
659
+ {
660
+ uint64_t next_event = 0;
661
+
662
+ if (!Heartbeats.empty()) {
663
+ multimap<uint64_t,EventableDescriptor*>::iterator heartbeats = Heartbeats.begin();
664
+ next_event = heartbeats->first;
665
+ }
666
+
667
+ if (!Timers.empty()) {
668
+ multimap<uint64_t,Timer_t>::iterator timers = Timers.begin();
669
+ if (next_event == 0 || timers->first < next_event)
670
+ next_event = timers->first;
671
+ }
672
+
673
+ if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
674
+ next_event = MyCurrentLoopTime;
675
+ }
676
+
677
+ timeval tv;
678
+
679
+ if (next_event == 0) {
680
+ tv = Quantum;
681
+ } else {
682
+ if (next_event > MyCurrentLoopTime) {
683
+ uint64_t duration = next_event - MyCurrentLoopTime;
684
+ tv.tv_sec = duration / 1000000;
685
+ tv.tv_usec = duration % 1000000;
686
+ } else {
687
+ tv.tv_sec = tv.tv_usec = 0;
688
+ }
689
+ }
690
+
691
+ return tv;
692
+ }
693
+
694
+ /*******************************
695
+ EventMachine_t::_CleanupSockets
696
+ *******************************/
697
+
698
+ void EventMachine_t::_CleanupSockets()
699
+ {
700
+ // TODO, rip this out and only delete the descriptors we know have died,
701
+ // rather than traversing the whole list.
702
+ // Modified 05Jan08 per suggestions by Chris Heath. It's possible that
703
+ // an EventableDescriptor will have a descriptor value of -1. That will
704
+ // happen if EventableDescriptor::Close was called on it. In that case,
705
+ // don't call epoll_ctl to remove the socket's filters from the epoll set.
706
+ // According to the epoll docs, this happens automatically when the
707
+ // descriptor is closed anyway. This is different from the case where
708
+ // the socket has already been closed but the descriptor in the ED object
709
+ // hasn't yet been set to INVALID_SOCKET.
710
+ // In kqueue, closing a descriptor automatically removes its event filters.
711
+ int i, j;
712
+ int nSockets = Descriptors.size();
713
+ for (i=0, j=0; i < nSockets; i++) {
714
+ EventableDescriptor *ed = Descriptors[i];
715
+ assert (ed);
716
+ if (ed->ShouldDelete()) {
717
+ #ifdef HAVE_EPOLL
718
+ if (bEpoll) {
719
+ assert (epfd != -1);
720
+ if (ed->GetSocket() != INVALID_SOCKET) {
721
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
722
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
723
+ if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
724
+ char buf [200];
725
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
726
+ throw std::runtime_error (buf);
727
+ }
728
+ }
729
+ ModifiedDescriptors.erase(ed);
730
+ }
731
+ #endif
732
+ delete ed;
733
+ }
734
+ else
735
+ Descriptors [j++] = ed;
736
+ }
737
+ while ((size_t)j < Descriptors.size())
738
+ Descriptors.pop_back();
739
+ }
740
+
680
741
  /*********************************
681
742
  EventMachine_t::_ModifyEpollEvent
682
743
  *********************************/
@@ -829,7 +890,7 @@ bool EventMachine_t::_RunSelectOnce()
829
890
  { // read and write the sockets
830
891
  //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
831
892
  //timeval tv = Quantum;
832
- SelectData.tv = Quantum;
893
+ SelectData.tv = _TimeTilNextEvent();
833
894
  int s = SelectData._Select();
834
895
  //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
835
896
  //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
@@ -865,48 +926,54 @@ bool EventMachine_t::_RunSelectOnce()
865
926
  _ReadLoopBreaker();
866
927
  }
867
928
  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);
929
+ switch (errno) {
930
+ case EBADF:
931
+ _CleanBadDescriptors();
932
+ break;
933
+ case EINVAL:
934
+ throw std::runtime_error ("Somehow EM passed an invalid nfds or invalid timeout to select(2), please report this!");
935
+ break;
936
+ default:
937
+ // select can fail on error in a handful of ways.
938
+ // If this happens, then wait for a little while to avoid busy-looping.
939
+ // If the error was EINTR, we probably caught SIGCHLD or something,
940
+ // so keep the wait short.
941
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
942
+ EmSelect (0, NULL, NULL, NULL, &tv);
943
+ }
874
944
  }
875
945
  }
876
946
 
947
+ return true;
948
+ }
877
949
 
878
- { // dispatch heartbeats
879
- if (gCurrentLoopTime >= NextHeartbeatTime) {
880
- NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
950
+ void EventMachine_t::_CleanBadDescriptors()
951
+ {
952
+ size_t i;
881
953
 
882
- for (i=0; i < Descriptors.size(); i++) {
883
- EventableDescriptor *ed = Descriptors[i];
884
- assert (ed);
885
- ed->Heartbeat();
886
- }
887
- }
888
- }
954
+ for (i = 0; i < Descriptors.size(); i++) {
955
+ EventableDescriptor *ed = Descriptors[i];
956
+ if (ed->ShouldDelete())
957
+ continue;
889
958
 
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();
959
+ int sd = ed->GetSocket();
904
960
 
905
- }
961
+ struct timeval tv;
962
+ tv.tv_sec = 0;
963
+ tv.tv_usec = 0;
906
964
 
907
- return true;
908
- }
965
+ fd_set fds;
966
+ FD_ZERO(&fds);
967
+ FD_SET(sd, &fds);
968
+
969
+ int ret = select(sd + 1, &fds, NULL, NULL, &tv);
909
970
 
971
+ if (ret == -1) {
972
+ if (errno == EBADF)
973
+ ed->ScheduleClose(false);
974
+ }
975
+ }
976
+ }
910
977
 
911
978
  /********************************
912
979
  EventMachine_t::_ReadLoopBreaker
@@ -921,7 +988,7 @@ void EventMachine_t::_ReadLoopBreaker()
921
988
  char buffer [1024];
922
989
  read (LoopBreakerReader, buffer, sizeof(buffer));
923
990
  if (EventCallback)
924
- (*EventCallback)(NULL, EM_LOOPBREAK_SIGNAL, "", 0);
991
+ (*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0);
925
992
  }
926
993
 
927
994
 
@@ -939,13 +1006,13 @@ bool EventMachine_t::_RunTimers()
939
1006
  // one that hasn't expired yet.
940
1007
 
941
1008
  while (true) {
942
- multimap<Int64,Timer_t>::iterator i = Timers.begin();
1009
+ multimap<uint64_t,Timer_t>::iterator i = Timers.begin();
943
1010
  if (i == Timers.end())
944
1011
  break;
945
- if (i->first > gCurrentLoopTime)
1012
+ if (i->first > MyCurrentLoopTime)
946
1013
  break;
947
1014
  if (EventCallback)
948
- (*EventCallback) (NULL, EM_TIMER_FIRED, NULL, i->second.GetBinding());
1015
+ (*EventCallback) (0, EM_TIMER_FIRED, NULL, i->second.GetBinding());
949
1016
  Timers.erase (i);
950
1017
  }
951
1018
  return true;
@@ -964,28 +1031,31 @@ const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
964
1031
  // Don't use the global loop-time variable here, because we might
965
1032
  // get called before the main event machine is running.
966
1033
 
1034
+ // XXX This should be replaced with a call to _GetRealTime(), but I don't
1035
+ // understand if this is a bug or not? For OS_UNIX we multiply the argument
1036
+ // milliseconds by 1000, but for OS_WIN32 we do not? This needs to be sorted out.
967
1037
  #ifdef OS_UNIX
968
1038
  struct timeval tv;
969
1039
  gettimeofday (&tv, NULL);
970
- Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
971
- fire_at += ((Int64)milliseconds) * 1000LL;
1040
+ uint64_t fire_at = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
1041
+ fire_at += ((uint64_t)milliseconds) * 1000LL;
972
1042
  #endif
973
1043
 
974
1044
  #ifdef OS_WIN32
975
1045
  unsigned tick = GetTickCount();
976
- if (tick < gLastTickCount)
977
- gTickCountTickover += 1;
978
- gLastTickCount = tick;
1046
+ if (tick < LastTickCount)
1047
+ TickCountTickover += 1;
1048
+ LastTickCount = tick;
979
1049
 
980
- Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick;
981
- fire_at += (Int64)milliseconds;
1050
+ uint64_t fire_at = ((uint64_t)TickCountTickover << 32) + (uint64_t)tick;
1051
+ fire_at += (uint64_t)milliseconds;
982
1052
  #endif
983
1053
 
984
1054
  Timer_t t;
985
1055
  #ifndef HAVE_MAKE_PAIR
986
- multimap<Int64,Timer_t>::iterator i = Timers.insert (multimap<Int64,Timer_t>::value_type (fire_at, t));
1056
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (multimap<uint64_t,Timer_t>::value_type (fire_at, t));
987
1057
  #else
988
- multimap<Int64,Timer_t>::iterator i = Timers.insert (make_pair (fire_at, t));
1058
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (make_pair (fire_at, t));
989
1059
  #endif
990
1060
  return i->second.GetBinding();
991
1061
  }
@@ -1030,8 +1100,11 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1030
1100
  bind_as = *bind_as_ptr; // copy because name2address points to a static
1031
1101
 
1032
1102
  int sd = socket (family, SOCK_STREAM, 0);
1033
- if (sd == INVALID_SOCKET)
1034
- throw std::runtime_error ("unable to create new socket");
1103
+ if (sd == INVALID_SOCKET) {
1104
+ char buf [200];
1105
+ snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
1106
+ throw std::runtime_error (buf);
1107
+ }
1035
1108
 
1036
1109
  /*
1037
1110
  sockaddr_in pin;
@@ -1064,7 +1137,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1064
1137
  // From here on, ALL error returns must close the socket.
1065
1138
  // Set the new socket nonblocking.
1066
1139
  if (!SetSocketNonblocking (sd)) {
1067
- closesocket (sd);
1140
+ close (sd);
1068
1141
  throw std::runtime_error ("unable to set socket as non-blocking");
1069
1142
  }
1070
1143
  // Disable slow-start (Nagle algorithm).
@@ -1077,16 +1150,16 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1077
1150
  int bind_to_size, bind_to_family;
1078
1151
  struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
1079
1152
  if (!bind_to) {
1080
- closesocket (sd);
1153
+ close (sd);
1081
1154
  throw std::runtime_error ("invalid bind address");
1082
1155
  }
1083
1156
  if (bind (sd, bind_to, bind_to_size) < 0) {
1084
- closesocket (sd);
1157
+ close (sd);
1085
1158
  throw std::runtime_error ("couldn't bind to address");
1086
1159
  }
1087
1160
  }
1088
1161
 
1089
- unsigned long out = NULL;
1162
+ unsigned long out = 0;
1090
1163
 
1091
1164
  #ifdef OS_UNIX
1092
1165
  //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
@@ -1135,29 +1208,31 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1135
1208
  Add (cd);
1136
1209
  out = cd->GetBinding();
1137
1210
  }
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();
1157
- }
1158
1211
  }
1159
1212
  else {
1160
- // The error from connect was something other then EINPROGRESS.
1213
+ // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
1214
+ // Fall through to the !out case below
1215
+ }
1216
+
1217
+ if (!out) {
1218
+ /* This could be connection refused or some such thing.
1219
+ * We will come here on Linux if a localhost connection fails.
1220
+ * Changed 16Jul06: Originally this branch was a no-op, and
1221
+ * we'd drop down to the end of the method, close the socket,
1222
+ * and return NULL, which would cause the caller to GET A
1223
+ * FATAL EXCEPTION. Now we keep the socket around but schedule an
1224
+ * immediate close on it, so the caller will get a close-event
1225
+ * scheduled on it. This was only an issue for localhost connections
1226
+ * to non-listening ports. We may eventually need to revise this
1227
+ * revised behavior, in case it causes problems like making it hard
1228
+ * for people to know that a failure occurred.
1229
+ */
1230
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1231
+ if (!cd)
1232
+ throw std::runtime_error ("no connection allocated");
1233
+ cd->ScheduleClose (false);
1234
+ Add (cd);
1235
+ out = cd->GetBinding();
1161
1236
  }
1162
1237
  #endif
1163
1238
 
@@ -1190,7 +1265,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1190
1265
  #endif
1191
1266
 
1192
1267
  if (!out)
1193
- closesocket (sd);
1268
+ close (sd);
1194
1269
  return out;
1195
1270
  }
1196
1271
 
@@ -1215,10 +1290,10 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1215
1290
  // The whole rest of this function is only compiled on Unix systems.
1216
1291
  #ifdef OS_UNIX
1217
1292
 
1218
- unsigned long out = NULL;
1293
+ unsigned long out = 0;
1219
1294
 
1220
1295
  if (!server || !*server)
1221
- return NULL;
1296
+ return 0;
1222
1297
 
1223
1298
  sockaddr_un pun;
1224
1299
  memset (&pun, 0, sizeof(pun));
@@ -1234,19 +1309,19 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1234
1309
 
1235
1310
  int fd = socket (AF_LOCAL, SOCK_STREAM, 0);
1236
1311
  if (fd == INVALID_SOCKET)
1237
- return NULL;
1312
+ return 0;
1238
1313
 
1239
1314
  // From here on, ALL error returns must close the socket.
1240
1315
  // NOTE: At this point, the socket is still a blocking socket.
1241
1316
  if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) {
1242
- closesocket (fd);
1243
- return NULL;
1317
+ close (fd);
1318
+ return 0;
1244
1319
  }
1245
1320
 
1246
1321
  // Set the newly-connected socket nonblocking.
1247
1322
  if (!SetSocketNonblocking (fd)) {
1248
- closesocket (fd);
1249
- return NULL;
1323
+ close (fd);
1324
+ return 0;
1250
1325
  }
1251
1326
 
1252
1327
  // Set up a connection descriptor and add it to the event-machine.
@@ -1261,7 +1336,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1261
1336
  out = cd->GetBinding();
1262
1337
 
1263
1338
  if (!out)
1264
- closesocket (fd);
1339
+ close (fd);
1265
1340
 
1266
1341
  return out;
1267
1342
  #endif
@@ -1450,9 +1525,9 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1450
1525
  int family, bind_size;
1451
1526
  struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1452
1527
  if (!bind_here)
1453
- return NULL;
1528
+ return 0;
1454
1529
 
1455
- unsigned long output_binding = NULL;
1530
+ unsigned long output_binding = 0;
1456
1531
 
1457
1532
  //struct sockaddr_in sin;
1458
1533
 
@@ -1531,8 +1606,8 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1531
1606
 
1532
1607
  fail:
1533
1608
  if (sd_accept != INVALID_SOCKET)
1534
- closesocket (sd_accept);
1535
- return NULL;
1609
+ close (sd_accept);
1610
+ return 0;
1536
1611
  }
1537
1612
 
1538
1613
 
@@ -1542,7 +1617,7 @@ EventMachine_t::OpenDatagramSocket
1542
1617
 
1543
1618
  const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int port)
1544
1619
  {
1545
- unsigned long output_binding = NULL;
1620
+ unsigned long output_binding = 0;
1546
1621
 
1547
1622
  int sd = socket (AF_INET, SOCK_DGRAM, 0);
1548
1623
  if (sd == INVALID_SOCKET)
@@ -1592,8 +1667,8 @@ const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int
1592
1667
 
1593
1668
  fail:
1594
1669
  if (sd != INVALID_SOCKET)
1595
- closesocket (sd);
1596
- return NULL;
1670
+ close (sd);
1671
+ return 0;
1597
1672
  }
1598
1673
 
1599
1674
 
@@ -1702,6 +1777,7 @@ void EventMachine_t::_AddNewDescriptors()
1702
1777
  */
1703
1778
  #endif
1704
1779
 
1780
+ QueueHeartbeat(ed);
1705
1781
  Descriptors.push_back (ed);
1706
1782
  }
1707
1783
  NewDescriptors.clear();
@@ -1758,31 +1834,6 @@ void EventMachine_t::Modify (EventableDescriptor *ed)
1758
1834
  }
1759
1835
 
1760
1836
 
1761
- /***********************************
1762
- EventMachine_t::_OpenFileForWriting
1763
- ***********************************/
1764
-
1765
- const unsigned long EventMachine_t::_OpenFileForWriting (const char *filename)
1766
- {
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
-
1783
- }
1784
-
1785
-
1786
1837
  /**************************************
1787
1838
  EventMachine_t::CreateUnixDomainServer
1788
1839
  **************************************/
@@ -1802,7 +1853,7 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1802
1853
 
1803
1854
  // The whole rest of this function is only compiled on Unix systems.
1804
1855
  #ifdef OS_UNIX
1805
- unsigned long output_binding = NULL;
1856
+ unsigned long output_binding = 0;
1806
1857
 
1807
1858
  struct sockaddr_un s_sun;
1808
1859
 
@@ -1862,8 +1913,8 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1862
1913
 
1863
1914
  fail:
1864
1915
  if (sd_accept != INVALID_SOCKET)
1865
- closesocket (sd_accept);
1866
- return NULL;
1916
+ close (sd_accept);
1917
+ return 0;
1867
1918
  #endif // OS_UNIX
1868
1919
  }
1869
1920
 
@@ -1924,18 +1975,18 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1924
1975
  #ifdef OS_UNIX
1925
1976
  // Make sure the incoming array of command strings is sane.
1926
1977
  if (!cmd_strings)
1927
- return NULL;
1978
+ return 0;
1928
1979
  int j;
1929
- for (j=0; j < 100 && cmd_strings[j]; j++)
1980
+ for (j=0; j < 2048 && cmd_strings[j]; j++)
1930
1981
  ;
1931
- if ((j==0) || (j==100))
1932
- return NULL;
1982
+ if ((j==0) || (j==2048))
1983
+ return 0;
1933
1984
 
1934
- unsigned long output_binding = NULL;
1985
+ unsigned long output_binding = 0;
1935
1986
 
1936
1987
  int sv[2];
1937
1988
  if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
1938
- return NULL;
1989
+ return 0;
1939
1990
  // from here, all early returns must close the pair of sockets.
1940
1991
 
1941
1992
  // Set the parent side of the socketpair nonblocking.
@@ -1945,7 +1996,7 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1945
1996
  if (!SetSocketNonblocking (sv[0])) {
1946
1997
  close (sv[0]);
1947
1998
  close (sv[1]);
1948
- return NULL;
1999
+ return 0;
1949
2000
  }
1950
2001
 
1951
2002
  pid_t f = fork();
@@ -2005,7 +2056,7 @@ const unsigned long EventMachine_t::WatchPid (int pid)
2005
2056
  {
2006
2057
  #ifdef HAVE_KQUEUE
2007
2058
  if (!bKqueue)
2008
- throw std::runtime_error("must enable kqueue");
2059
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support");
2009
2060
 
2010
2061
  struct kevent event;
2011
2062
  int kqres;
@@ -2094,7 +2145,8 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2094
2145
  Add(inotify);
2095
2146
  }
2096
2147
 
2097
- wd = inotify_add_watch(inotify->GetSocket(), fpath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF);
2148
+ wd = inotify_add_watch(inotify->GetSocket(), fpath,
2149
+ IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_MOVE) ;
2098
2150
  if (wd == -1) {
2099
2151
  char errbuf[300];
2100
2152
  sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno));
@@ -2104,7 +2156,7 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2104
2156
 
2105
2157
  #ifdef HAVE_KQUEUE
2106
2158
  if (!bKqueue)
2107
- throw std::runtime_error("must enable kqueue");
2159
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support");
2108
2160
 
2109
2161
  // With kqueue we have to open the file first and use the resulting fd to register for events
2110
2162
  wd = open(fpath, O_RDONLY);
@@ -2170,19 +2222,33 @@ EventMachine_t::_ReadInotify_Events
2170
2222
  void EventMachine_t::_ReadInotifyEvents()
2171
2223
  {
2172
2224
  #ifdef HAVE_INOTIFY
2173
- struct inotify_event event;
2225
+ char buffer[1024];
2174
2226
 
2175
2227
  assert(EventCallback);
2176
2228
 
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);
2229
+ for (;;) {
2230
+ int returned = read(inotify->GetSocket(), buffer, sizeof(buffer));
2231
+ assert(!(returned == 0 || returned == -1 && errno == EINVAL));
2232
+ if (returned <= 0) {
2233
+ break;
2234
+ }
2235
+ int current = 0;
2236
+ while (current < returned) {
2237
+ struct inotify_event* event = (struct inotify_event*)(buffer+current);
2238
+ map<int, Bindable_t*>::const_iterator bindable = Files.find(event->wd);
2239
+ if (bindable != Files.end()) {
2240
+ if (event->mask & (IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE)){
2241
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "modified", 8);
2242
+ }
2243
+ if (event->mask & IN_MOVE_SELF){
2244
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "moved", 5);
2245
+ }
2246
+ if (event->mask & IN_DELETE_SELF) {
2247
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
2248
+ UnwatchFile ((int)event->wd);
2249
+ }
2250
+ }
2251
+ current += sizeof(struct inotify_event) + event->len;
2186
2252
  }
2187
2253
  }
2188
2254
  #endif