eventmachine 0.12.10-x86-mswin32-60 → 1.0.0.beta.2-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/README +80 -81
- data/Rakefile +7 -370
- data/docs/COPYING +60 -60
- data/docs/ChangeLog +211 -211
- data/docs/DEFERRABLES +246 -133
- data/docs/EPOLL +141 -141
- data/docs/GNU +281 -281
- data/docs/INSTALL +13 -13
- data/docs/KEYBOARD +42 -38
- data/docs/LEGAL +25 -25
- data/docs/LIGHTWEIGHT_CONCURRENCY +130 -70
- data/docs/PURE_RUBY +75 -75
- data/docs/RELEASE_NOTES +94 -94
- data/docs/SMTP +4 -2
- data/docs/SPAWNED_PROCESSES +148 -89
- data/docs/TODO +8 -8
- data/eventmachine.gemspec +19 -26
- data/examples/ex_channel.rb +42 -42
- data/examples/ex_queue.rb +2 -2
- data/examples/ex_tick_loop_array.rb +15 -0
- data/examples/ex_tick_loop_counter.rb +32 -0
- data/examples/helper.rb +1 -1
- data/ext/binder.cpp +0 -1
- data/ext/cmain.cpp +36 -25
- data/ext/ed.cpp +104 -113
- data/ext/ed.h +24 -30
- data/ext/em.cpp +349 -283
- data/ext/em.h +25 -29
- data/ext/eventmachine.h +5 -4
- data/ext/extconf.rb +58 -49
- data/ext/fastfilereader/extconf.rb +5 -3
- data/ext/fastfilereader/mapper.cpp +214 -214
- data/ext/fastfilereader/mapper.h +59 -59
- data/ext/fastfilereader/rubymain.cpp +127 -127
- data/ext/kb.cpp +1 -3
- data/ext/page.cpp +107 -107
- data/ext/page.h +51 -51
- data/ext/pipe.cpp +9 -11
- data/ext/project.h +12 -8
- data/ext/rubymain.cpp +138 -104
- data/java/.classpath +8 -8
- data/java/.project +17 -17
- data/java/src/com/rubyeventmachine/EmReactor.java +1 -0
- data/java/src/com/rubyeventmachine/EmReactorException.java +40 -40
- data/lib/em/buftok.rb +138 -138
- data/lib/em/callback.rb +25 -25
- data/lib/em/channel.rb +1 -1
- data/lib/em/connection.rb +6 -1
- data/lib/em/deferrable.rb +16 -2
- data/lib/em/file_watch.rb +53 -53
- data/lib/em/future.rb +61 -61
- data/lib/em/iterator.rb +270 -0
- data/lib/em/messages.rb +66 -66
- data/lib/em/process_watch.rb +43 -43
- data/lib/em/protocols.rb +1 -1
- data/lib/em/protocols/header_and_content.rb +138 -138
- data/lib/em/protocols/httpclient.rb +267 -262
- data/lib/em/protocols/line_protocol.rb +28 -0
- data/lib/em/protocols/memcache.rb +322 -322
- data/lib/em/protocols/postgres3.rb +247 -247
- data/lib/em/protocols/saslauth.rb +175 -175
- data/lib/em/protocols/smtpserver.rb +640 -547
- data/lib/em/protocols/stomp.rb +200 -200
- data/lib/em/protocols/tcptest.rb +52 -52
- data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +1013 -1022
- data/lib/em/queue.rb +1 -0
- data/lib/em/spawnable.rb +85 -85
- data/lib/em/streamer.rb +130 -130
- data/lib/em/tick_loop.rb +85 -0
- data/lib/em/timers.rb +2 -1
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +40 -84
- data/lib/jeventmachine.rb +2 -1
- data/lib/rubyeventmachine.rb +2 -0
- data/setup.rb +1585 -1585
- data/tasks/doc.rake +30 -0
- data/tasks/package.rake +85 -0
- data/tasks/test.rake +6 -0
- data/tests/client.crt +31 -31
- data/tests/client.key +51 -51
- data/tests/test_attach.rb +13 -3
- data/tests/test_basic.rb +60 -95
- data/tests/test_channel.rb +3 -2
- data/tests/test_defer.rb +49 -47
- data/tests/test_deferrable.rb +35 -0
- data/tests/test_error_handler.rb +35 -35
- data/tests/test_errors.rb +82 -82
- data/tests/test_exc.rb +55 -55
- data/tests/test_file_watch.rb +49 -49
- data/tests/test_futures.rb +198 -198
- data/tests/test_handler_check.rb +36 -36
- data/tests/test_hc.rb +190 -218
- data/tests/test_httpclient.rb +227 -218
- data/tests/test_httpclient2.rb +3 -2
- data/tests/test_inactivity_timeout.rb +3 -3
- data/tests/test_kb.rb +60 -60
- data/tests/test_ltp.rb +13 -5
- data/tests/test_ltp2.rb +317 -317
- data/tests/test_next_tick.rb +1 -1
- data/tests/test_object_protocol.rb +36 -36
- data/tests/test_pending_connect_timeout.rb +2 -2
- data/tests/test_process_watch.rb +50 -48
- data/tests/test_proxy_connection.rb +52 -0
- data/tests/test_pure.rb +134 -125
- data/tests/test_queue.rb +44 -44
- data/tests/test_running.rb +42 -42
- data/tests/test_sasl.rb +72 -72
- data/tests/test_send_file.rb +251 -242
- data/tests/test_servers.rb +76 -76
- data/tests/test_smtpclient.rb +83 -83
- data/tests/test_smtpserver.rb +85 -85
- data/tests/test_spawn.rb +322 -322
- data/tests/test_ssl_methods.rb +49 -49
- data/tests/test_ssl_verify.rb +82 -82
- data/tests/test_tick_loop.rb +59 -0
- data/tests/test_timers.rb +13 -15
- data/tests/test_ud.rb +36 -36
- data/tests/testem.rb +31 -31
- metadata +66 -51
- data/ext/cplusplus.cpp +0 -202
- data/ext/emwin.cpp +0 -300
- data/ext/emwin.h +0 -94
- data/ext/epoll.cpp +0 -26
- data/ext/epoll.h +0 -25
- data/ext/eventmachine_cpp.h +0 -96
- data/ext/files.cpp +0 -94
- data/ext/files.h +0 -65
- data/ext/sigs.cpp +0 -89
- data/ext/sigs.h +0 -32
- data/java/src/com/rubyeventmachine/application/Application.java +0 -194
- data/java/src/com/rubyeventmachine/application/Connection.java +0 -74
- data/java/src/com/rubyeventmachine/application/ConnectionFactory.java +0 -37
- data/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +0 -46
- data/java/src/com/rubyeventmachine/application/PeriodicTimer.java +0 -38
- data/java/src/com/rubyeventmachine/application/Timer.java +0 -54
- data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +0 -109
- data/java/src/com/rubyeventmachine/tests/ConnectTest.java +0 -148
- data/java/src/com/rubyeventmachine/tests/EMTest.java +0 -80
- data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +0 -53
- data/java/src/com/rubyeventmachine/tests/TestServers.java +0 -75
- data/java/src/com/rubyeventmachine/tests/TestTimers.java +0 -90
- data/lib/evma.rb +0 -32
- data/lib/evma/callback.rb +0 -32
- data/lib/evma/container.rb +0 -75
- data/lib/evma/factory.rb +0 -77
- data/lib/evma/protocol.rb +0 -87
- data/lib/evma/reactor.rb +0 -48
- 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 (
|
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
|
79
|
-
virtual int SetCommInactivityTimeout (
|
80
|
-
|
81
|
-
int SetPendingConnectTimeout (
|
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
|
-
|
106
|
+
EMCallback EventCallback;
|
103
107
|
void _GenericInboundDispatch(const char*, int);
|
104
108
|
|
105
|
-
|
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
|
-
|
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
|
199
|
-
virtual int SetCommInactivityTimeout (
|
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
|
-
|
282
|
-
|
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 =
|
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 (
|
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
|
-
|
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 (
|
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
|
-
|
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 <
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
-
|
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 (
|
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
|
-
|
487
|
+
ret = _RunEpollOnce();
|
452
488
|
else if (bKqueue)
|
453
|
-
|
489
|
+
ret = _RunKqueueOnce();
|
454
490
|
else
|
455
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
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
|
-
|
879
|
-
|
880
|
-
|
950
|
+
void EventMachine_t::_CleanBadDescriptors()
|
951
|
+
{
|
952
|
+
size_t i;
|
881
953
|
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
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
|
-
|
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
|
-
|
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)(
|
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<
|
1009
|
+
multimap<uint64_t,Timer_t>::iterator i = Timers.begin();
|
943
1010
|
if (i == Timers.end())
|
944
1011
|
break;
|
945
|
-
if (i->first >
|
1012
|
+
if (i->first > MyCurrentLoopTime)
|
946
1013
|
break;
|
947
1014
|
if (EventCallback)
|
948
|
-
(*EventCallback) (
|
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
|
-
|
971
|
-
fire_at += ((
|
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 <
|
977
|
-
|
978
|
-
|
1046
|
+
if (tick < LastTickCount)
|
1047
|
+
TickCountTickover += 1;
|
1048
|
+
LastTickCount = tick;
|
979
1049
|
|
980
|
-
|
981
|
-
fire_at += (
|
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<
|
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<
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1157
|
+
close (sd);
|
1085
1158
|
throw std::runtime_error ("couldn't bind to address");
|
1086
1159
|
}
|
1087
1160
|
}
|
1088
1161
|
|
1089
|
-
unsigned long out =
|
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
|
-
|
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 =
|
1293
|
+
unsigned long out = 0;
|
1219
1294
|
|
1220
1295
|
if (!server || !*server)
|
1221
|
-
return
|
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
|
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
|
-
|
1243
|
-
return
|
1317
|
+
close (fd);
|
1318
|
+
return 0;
|
1244
1319
|
}
|
1245
1320
|
|
1246
1321
|
// Set the newly-connected socket nonblocking.
|
1247
1322
|
if (!SetSocketNonblocking (fd)) {
|
1248
|
-
|
1249
|
-
return
|
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
|
-
|
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
|
1528
|
+
return 0;
|
1454
1529
|
|
1455
|
-
unsigned long output_binding =
|
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
|
-
|
1535
|
-
return
|
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 =
|
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
|
-
|
1596
|
-
return
|
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 =
|
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
|
-
|
1866
|
-
return
|
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
|
1978
|
+
return 0;
|
1928
1979
|
int j;
|
1929
|
-
for (j=0; j <
|
1980
|
+
for (j=0; j < 2048 && cmd_strings[j]; j++)
|
1930
1981
|
;
|
1931
|
-
if ((j==0) || (j==
|
1932
|
-
return
|
1982
|
+
if ((j==0) || (j==2048))
|
1983
|
+
return 0;
|
1933
1984
|
|
1934
|
-
unsigned long output_binding =
|
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
|
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
|
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,
|
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
|
-
|
2225
|
+
char buffer[1024];
|
2174
2226
|
|
2175
2227
|
assert(EventCallback);
|
2176
2228
|
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
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
|