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.
- 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
|