eventmachine 1.0.3-x86-mingw32 → 1.2.0.dev.2-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +84 -1
- data/README.md +6 -7
- data/ext/binder.cpp +10 -10
- data/ext/binder.h +5 -5
- data/ext/cmain.cpp +173 -61
- data/ext/ed.cpp +262 -127
- data/ext/ed.h +50 -30
- data/ext/em.cpp +491 -445
- data/ext/em.h +101 -36
- data/ext/eventmachine.h +67 -51
- data/ext/extconf.rb +124 -31
- data/ext/fastfilereader/extconf.rb +9 -2
- data/ext/fastfilereader/mapper.cpp +3 -1
- data/ext/fastfilereader/rubymain.cpp +7 -7
- data/ext/kb.cpp +1 -1
- data/ext/pipe.cpp +11 -4
- data/ext/project.h +26 -6
- data/ext/rubymain.cpp +408 -201
- data/ext/ssl.cpp +167 -20
- data/ext/ssl.h +11 -2
- data/java/src/com/rubyeventmachine/EmReactor.java +16 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +2 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +55 -10
- data/lib/1.9/fastfilereaderext.so +0 -0
- data/lib/1.9/rubyeventmachine.so +0 -0
- data/lib/2.0/fastfilereaderext.so +0 -0
- data/lib/2.0/rubyeventmachine.so +0 -0
- data/lib/2.1/fastfilereaderext.so +0 -0
- data/lib/2.1/rubyeventmachine.so +0 -0
- data/lib/2.2/fastfilereaderext.so +0 -0
- data/lib/2.2/rubyeventmachine.so +0 -0
- data/lib/2.3/fastfilereaderext.so +0 -0
- data/lib/2.3/rubyeventmachine.so +0 -0
- data/lib/em/buftok.rb +34 -85
- data/lib/em/channel.rb +5 -0
- data/lib/em/completion.rb +2 -2
- data/lib/em/connection.rb +62 -4
- data/lib/em/iterator.rb +30 -48
- data/lib/em/pool.rb +1 -1
- data/lib/em/protocols/httpclient.rb +31 -11
- data/lib/em/protocols/line_and_text.rb +4 -4
- data/lib/em/protocols/linetext2.rb +44 -39
- data/lib/em/protocols/smtpclient.rb +60 -31
- data/lib/em/protocols/smtpserver.rb +32 -9
- data/lib/em/pure_ruby.rb +8 -3
- data/lib/em/queue.rb +16 -7
- data/lib/em/resolver.rb +64 -24
- data/lib/em/threaded_resource.rb +2 -2
- data/lib/em/tick_loop.rb +19 -19
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +96 -49
- data/lib/jeventmachine.rb +17 -0
- data/rakelib/package.rake +31 -4
- data/tests/dhparam.pem +13 -0
- data/tests/em_test_helper.rb +87 -0
- data/tests/test_attach.rb +25 -0
- data/tests/test_basic.rb +27 -38
- data/tests/test_channel.rb +14 -1
- data/tests/test_completion.rb +1 -0
- data/tests/test_connection_count.rb +22 -1
- data/tests/test_connection_write.rb +35 -0
- data/tests/test_defer.rb +17 -0
- data/tests/test_epoll.rb +26 -14
- data/tests/test_file_watch.rb +1 -0
- data/tests/test_fork.rb +75 -0
- data/tests/test_httpclient.rb +43 -0
- data/tests/test_idle_connection.rb +6 -4
- data/tests/test_ipv4.rb +125 -0
- data/tests/test_ipv6.rb +131 -0
- data/tests/test_iterator.rb +115 -0
- data/tests/test_kb.rb +19 -25
- data/tests/test_ltp2.rb +20 -0
- data/tests/test_many_fds.rb +22 -0
- data/tests/test_pause.rb +29 -0
- data/tests/test_pool.rb +2 -0
- data/tests/test_process_watch.rb +2 -0
- data/tests/test_processes.rb +7 -7
- data/tests/test_queue.rb +14 -0
- data/tests/test_resolver.rb +56 -7
- data/tests/test_set_sock_opt.rb +2 -0
- data/tests/test_smtpclient.rb +20 -0
- data/tests/test_ssl_args.rb +2 -2
- data/tests/test_ssl_dhparam.rb +83 -0
- data/tests/test_ssl_ecdh_curve.rb +79 -0
- data/tests/test_ssl_extensions.rb +49 -0
- data/tests/test_ssl_methods.rb +22 -5
- data/tests/test_ssl_protocols.rb +246 -0
- data/tests/test_ssl_verify.rb +103 -59
- data/tests/test_system.rb +4 -0
- data/tests/test_threaded_resource.rb +8 -0
- data/tests/test_unbind_reason.rb +5 -1
- metadata +173 -107
- data/.gitignore +0 -21
- data/.travis.yml +0 -12
- data/.yardopts +0 -7
- data/Gemfile +0 -2
- data/Rakefile +0 -20
- data/eventmachine.gemspec +0 -36
- data/rakelib/cpp.rake_example +0 -77
data/ext/ed.h
CHANGED
@@ -27,7 +27,7 @@ class SslBox_t; // forward reference
|
|
27
27
|
#endif
|
28
28
|
|
29
29
|
bool SetSocketNonblocking (SOCKET);
|
30
|
-
|
30
|
+
bool SetFdCloexec (int);
|
31
31
|
|
32
32
|
/*************************
|
33
33
|
class EventableDescriptor
|
@@ -36,10 +36,10 @@ class EventableDescriptor
|
|
36
36
|
class EventableDescriptor: public Bindable_t
|
37
37
|
{
|
38
38
|
public:
|
39
|
-
EventableDescriptor (
|
39
|
+
EventableDescriptor (SOCKET, EventMachine_t*);
|
40
40
|
virtual ~EventableDescriptor();
|
41
41
|
|
42
|
-
|
42
|
+
SOCKET GetSocket() {return MySocket;}
|
43
43
|
void SetSocketInvalid() { MySocket = INVALID_SOCKET; }
|
44
44
|
void Close();
|
45
45
|
|
@@ -69,14 +69,18 @@ class EventableDescriptor: public Bindable_t
|
|
69
69
|
virtual bool GetSubprocessPid (pid_t*) {return false;}
|
70
70
|
|
71
71
|
virtual void StartTls() {}
|
72
|
-
virtual void SetTlsParms (const char
|
72
|
+
virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int) {}
|
73
73
|
|
74
74
|
#ifdef WITH_SSL
|
75
75
|
virtual X509 *GetPeerCert() {return NULL;}
|
76
|
+
virtual int GetCipherBits() {return -1;}
|
77
|
+
virtual const char *GetCipherName() {return NULL;}
|
78
|
+
virtual const char *GetCipherProtocol() {return NULL;}
|
79
|
+
virtual const char *GetSNIHostname() {return NULL;}
|
76
80
|
#endif
|
77
81
|
|
78
82
|
virtual uint64_t GetCommInactivityTimeout() {return 0;}
|
79
|
-
virtual int SetCommInactivityTimeout (uint64_t
|
83
|
+
virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
|
80
84
|
uint64_t GetPendingConnectTimeout();
|
81
85
|
int SetPendingConnectTimeout (uint64_t value);
|
82
86
|
uint64_t GetLastActivity() { return LastActivity; }
|
@@ -85,11 +89,15 @@ class EventableDescriptor: public Bindable_t
|
|
85
89
|
struct epoll_event *GetEpollEvent() { return &EpollEvent; }
|
86
90
|
#endif
|
87
91
|
|
88
|
-
|
92
|
+
#ifdef HAVE_KQUEUE
|
93
|
+
bool GetKqueueArmWrite() { return bKqueueArmWrite; }
|
94
|
+
#endif
|
95
|
+
|
96
|
+
virtual void StartProxy(const uintptr_t, const unsigned long, const unsigned long);
|
89
97
|
virtual void StopProxy();
|
90
98
|
virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; };
|
91
99
|
virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
|
92
|
-
virtual int SendOutboundData(const char*,
|
100
|
+
virtual int SendOutboundData(const char*,unsigned long){ return -1; }
|
93
101
|
virtual bool IsPaused(){ return bPaused; }
|
94
102
|
virtual bool Pause(){ bPaused = true; return bPaused; }
|
95
103
|
virtual bool Resume(){ bPaused = false; return bPaused; }
|
@@ -104,12 +112,12 @@ class EventableDescriptor: public Bindable_t
|
|
104
112
|
bool bCloseAfterWriting;
|
105
113
|
|
106
114
|
protected:
|
107
|
-
|
115
|
+
SOCKET MySocket;
|
108
116
|
bool bAttached;
|
109
117
|
bool bWatchOnly;
|
110
118
|
|
111
119
|
EMCallback EventCallback;
|
112
|
-
void _GenericInboundDispatch(const char
|
120
|
+
void _GenericInboundDispatch(const char *buffer, unsigned long size);
|
113
121
|
|
114
122
|
uint64_t CreatedAt;
|
115
123
|
bool bCallbackUnbind;
|
@@ -126,6 +134,10 @@ class EventableDescriptor: public Bindable_t
|
|
126
134
|
struct epoll_event EpollEvent;
|
127
135
|
#endif
|
128
136
|
|
137
|
+
#ifdef HAVE_KQUEUE
|
138
|
+
bool bKqueueArmWrite;
|
139
|
+
#endif
|
140
|
+
|
129
141
|
EventMachine_t *MyEventMachine;
|
130
142
|
uint64_t PendingConnectTimeout;
|
131
143
|
uint64_t InactivityTimeout;
|
@@ -143,7 +155,7 @@ class LoopbreakDescriptor
|
|
143
155
|
class LoopbreakDescriptor: public EventableDescriptor
|
144
156
|
{
|
145
157
|
public:
|
146
|
-
LoopbreakDescriptor (
|
158
|
+
LoopbreakDescriptor (SOCKET, EventMachine_t*);
|
147
159
|
virtual ~LoopbreakDescriptor() {}
|
148
160
|
|
149
161
|
virtual void Read();
|
@@ -162,10 +174,10 @@ class ConnectionDescriptor
|
|
162
174
|
class ConnectionDescriptor: public EventableDescriptor
|
163
175
|
{
|
164
176
|
public:
|
165
|
-
ConnectionDescriptor (
|
177
|
+
ConnectionDescriptor (SOCKET, EventMachine_t*);
|
166
178
|
virtual ~ConnectionDescriptor();
|
167
179
|
|
168
|
-
int SendOutboundData (const char*,
|
180
|
+
int SendOutboundData (const char*, unsigned long);
|
169
181
|
|
170
182
|
void SetConnectPending (bool f);
|
171
183
|
virtual void ScheduleClose (bool after_writing);
|
@@ -193,10 +205,14 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
193
205
|
virtual int GetOutboundDataSize() {return OutboundDataSize;}
|
194
206
|
|
195
207
|
virtual void StartTls();
|
196
|
-
virtual void SetTlsParms (const char
|
208
|
+
virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int);
|
197
209
|
|
198
210
|
#ifdef WITH_SSL
|
199
211
|
virtual X509 *GetPeerCert();
|
212
|
+
virtual int GetCipherBits();
|
213
|
+
virtual const char *GetCipherName();
|
214
|
+
virtual const char *GetCipherProtocol();
|
215
|
+
virtual const char *GetSNIHostname();
|
200
216
|
virtual bool VerifySslPeer(const char*);
|
201
217
|
virtual void AcceptSslPeer();
|
202
218
|
#endif
|
@@ -215,7 +231,7 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
215
231
|
protected:
|
216
232
|
struct OutboundPage {
|
217
233
|
OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
|
218
|
-
void Free() {if (Buffer) free ((
|
234
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
219
235
|
const char *Buffer;
|
220
236
|
int Length;
|
221
237
|
int Offset;
|
@@ -237,8 +253,14 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
237
253
|
SslBox_t *SslBox;
|
238
254
|
std::string CertChainFilename;
|
239
255
|
std::string PrivateKeyFilename;
|
256
|
+
std::string CipherList;
|
257
|
+
std::string EcdhCurve;
|
258
|
+
std::string DhParam;
|
259
|
+
int Protocols;
|
240
260
|
bool bHandshakeSignaled;
|
241
261
|
bool bSslVerifyPeer;
|
262
|
+
bool bSslFailIfNoPeerCert;
|
263
|
+
std::string SniHostName;
|
242
264
|
bool bSslPeerAccepted;
|
243
265
|
#endif
|
244
266
|
|
@@ -252,9 +274,9 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
252
274
|
void _UpdateEvents();
|
253
275
|
void _UpdateEvents(bool, bool);
|
254
276
|
void _WriteOutboundData();
|
255
|
-
void _DispatchInboundData (const char *buffer,
|
277
|
+
void _DispatchInboundData (const char *buffer, unsigned long size);
|
256
278
|
void _DispatchCiphertext();
|
257
|
-
int _SendRawOutboundData (const char
|
279
|
+
int _SendRawOutboundData (const char *buffer, unsigned long size);
|
258
280
|
void _CheckHandshakeStatus();
|
259
281
|
|
260
282
|
};
|
@@ -267,7 +289,7 @@ class DatagramDescriptor
|
|
267
289
|
class DatagramDescriptor: public EventableDescriptor
|
268
290
|
{
|
269
291
|
public:
|
270
|
-
DatagramDescriptor (
|
292
|
+
DatagramDescriptor (SOCKET, EventMachine_t*);
|
271
293
|
virtual ~DatagramDescriptor();
|
272
294
|
|
273
295
|
virtual void Read();
|
@@ -277,8 +299,8 @@ class DatagramDescriptor: public EventableDescriptor
|
|
277
299
|
virtual bool SelectForRead() {return true;}
|
278
300
|
virtual bool SelectForWrite();
|
279
301
|
|
280
|
-
int SendOutboundData (const char*,
|
281
|
-
int SendOutboundDatagram (const char*,
|
302
|
+
int SendOutboundData (const char*, unsigned long);
|
303
|
+
int SendOutboundDatagram (const char*, unsigned long, const char*, int);
|
282
304
|
|
283
305
|
// Do we have any data to write? This is used by ShouldDelete.
|
284
306
|
virtual int GetOutboundDataSize() {return OutboundDataSize;}
|
@@ -291,18 +313,18 @@ class DatagramDescriptor: public EventableDescriptor
|
|
291
313
|
|
292
314
|
protected:
|
293
315
|
struct OutboundPage {
|
294
|
-
OutboundPage (const char *b, int l, struct
|
295
|
-
void Free() {if (Buffer) free ((
|
316
|
+
OutboundPage (const char *b, int l, struct sockaddr_in6 f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
|
317
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
296
318
|
const char *Buffer;
|
297
319
|
int Length;
|
298
320
|
int Offset;
|
299
|
-
struct
|
321
|
+
struct sockaddr_in6 From;
|
300
322
|
};
|
301
323
|
|
302
324
|
deque<OutboundPage> OutboundPages;
|
303
325
|
int OutboundDataSize;
|
304
326
|
|
305
|
-
struct
|
327
|
+
struct sockaddr_in6 ReturnAddress;
|
306
328
|
};
|
307
329
|
|
308
330
|
|
@@ -313,7 +335,7 @@ class AcceptorDescriptor
|
|
313
335
|
class AcceptorDescriptor: public EventableDescriptor
|
314
336
|
{
|
315
337
|
public:
|
316
|
-
AcceptorDescriptor (
|
338
|
+
AcceptorDescriptor (SOCKET, EventMachine_t*);
|
317
339
|
virtual ~AcceptorDescriptor();
|
318
340
|
|
319
341
|
virtual void Read();
|
@@ -325,7 +347,7 @@ class AcceptorDescriptor: public EventableDescriptor
|
|
325
347
|
|
326
348
|
virtual bool GetSockname (struct sockaddr*, socklen_t*);
|
327
349
|
|
328
|
-
static void StopAcceptor (const
|
350
|
+
static void StopAcceptor (const uintptr_t binding);
|
329
351
|
};
|
330
352
|
|
331
353
|
/********************
|
@@ -336,7 +358,7 @@ class PipeDescriptor
|
|
336
358
|
class PipeDescriptor: public EventableDescriptor
|
337
359
|
{
|
338
360
|
public:
|
339
|
-
PipeDescriptor (
|
361
|
+
PipeDescriptor (SOCKET, pid_t, EventMachine_t*);
|
340
362
|
virtual ~PipeDescriptor();
|
341
363
|
|
342
364
|
virtual void Read();
|
@@ -346,7 +368,7 @@ class PipeDescriptor: public EventableDescriptor
|
|
346
368
|
virtual bool SelectForRead();
|
347
369
|
virtual bool SelectForWrite();
|
348
370
|
|
349
|
-
int SendOutboundData (const char*,
|
371
|
+
int SendOutboundData (const char*, unsigned long);
|
350
372
|
virtual int GetOutboundDataSize() {return OutboundDataSize;}
|
351
373
|
|
352
374
|
virtual bool GetSubprocessPid (pid_t*);
|
@@ -354,7 +376,7 @@ class PipeDescriptor: public EventableDescriptor
|
|
354
376
|
protected:
|
355
377
|
struct OutboundPage {
|
356
378
|
OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
|
357
|
-
void Free() {if (Buffer) free ((
|
379
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
358
380
|
const char *Buffer;
|
359
381
|
int Length;
|
360
382
|
int Offset;
|
@@ -418,5 +440,3 @@ class InotifyDescriptor: public EventableDescriptor
|
|
418
440
|
};
|
419
441
|
|
420
442
|
#endif // __EventableDescriptor__H_
|
421
|
-
|
422
|
-
|
data/ext/em.cpp
CHANGED
@@ -27,11 +27,36 @@ See the file COPYING for complete licensing information.
|
|
27
27
|
*/
|
28
28
|
static unsigned int MaxOutstandingTimers = 100000;
|
29
29
|
|
30
|
+
/* The number of accept() done at once in a single tick when the acceptor
|
31
|
+
* socket becomes readable.
|
32
|
+
*/
|
33
|
+
static unsigned int SimultaneousAcceptCount = 10;
|
30
34
|
|
31
|
-
/* Internal helper to
|
32
|
-
*
|
35
|
+
/* Internal helper to create a socket with SOCK_CLOEXEC set, and fall
|
36
|
+
* back to fcntl'ing it if the headers/runtime don't support it.
|
33
37
|
*/
|
34
|
-
|
38
|
+
SOCKET EmSocket (int domain, int type, int protocol)
|
39
|
+
{
|
40
|
+
SOCKET sd;
|
41
|
+
#ifdef HAVE_SOCKET_CLOEXEC
|
42
|
+
sd = socket (domain, type | SOCK_CLOEXEC, protocol);
|
43
|
+
if (sd == INVALID_SOCKET) {
|
44
|
+
sd = socket (domain, type, protocol);
|
45
|
+
if (sd < 0) {
|
46
|
+
return sd;
|
47
|
+
}
|
48
|
+
SetFdCloexec(sd);
|
49
|
+
}
|
50
|
+
#else
|
51
|
+
sd = socket (domain, type, protocol);
|
52
|
+
if (sd == INVALID_SOCKET) {
|
53
|
+
return sd;
|
54
|
+
}
|
55
|
+
SetFdCloexec(sd);
|
56
|
+
#endif
|
57
|
+
return sd;
|
58
|
+
}
|
59
|
+
|
35
60
|
|
36
61
|
/***************************************
|
37
62
|
STATIC EventMachine_t::GetMaxTimerCount
|
@@ -61,30 +86,56 @@ void EventMachine_t::SetMaxTimerCount (int count)
|
|
61
86
|
MaxOutstandingTimers = count;
|
62
87
|
}
|
63
88
|
|
89
|
+
int EventMachine_t::GetSimultaneousAcceptCount()
|
90
|
+
{
|
91
|
+
return SimultaneousAcceptCount;
|
92
|
+
}
|
93
|
+
|
94
|
+
void EventMachine_t::SetSimultaneousAcceptCount (int count)
|
95
|
+
{
|
96
|
+
if (count < 1)
|
97
|
+
count = 1;
|
98
|
+
SimultaneousAcceptCount = count;
|
99
|
+
}
|
64
100
|
|
65
101
|
|
66
102
|
/******************************
|
67
103
|
EventMachine_t::EventMachine_t
|
68
104
|
******************************/
|
69
105
|
|
70
|
-
EventMachine_t::EventMachine_t (EMCallback event_callback):
|
106
|
+
EventMachine_t::EventMachine_t (EMCallback event_callback, Poller_t poller):
|
107
|
+
NumCloseScheduled (0),
|
71
108
|
HeartbeatInterval(2000000),
|
72
109
|
EventCallback (event_callback),
|
73
|
-
|
74
|
-
|
75
|
-
LoopBreakerWriter (-1),
|
76
|
-
NumCloseScheduled (0),
|
110
|
+
LoopBreakerReader (INVALID_SOCKET),
|
111
|
+
LoopBreakerWriter (INVALID_SOCKET),
|
77
112
|
bTerminateSignalReceived (false),
|
78
|
-
|
113
|
+
Poller (poller),
|
79
114
|
epfd (-1),
|
80
|
-
|
81
|
-
|
82
|
-
inotify (NULL)
|
115
|
+
kqfd (-1)
|
116
|
+
#ifdef HAVE_INOTIFY
|
117
|
+
, inotify (NULL)
|
118
|
+
#endif
|
83
119
|
{
|
84
120
|
// Default time-slice is just smaller than one hundred mills.
|
85
121
|
Quantum.tv_sec = 0;
|
86
122
|
Quantum.tv_usec = 90000;
|
87
123
|
|
124
|
+
// Override the requested poller back to default if needed.
|
125
|
+
#if !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
|
126
|
+
Poller = Poller_Default;
|
127
|
+
#endif
|
128
|
+
|
129
|
+
/* Initialize monotonic timekeeping on OS X before the first call to GetRealTime */
|
130
|
+
#ifdef OS_DARWIN
|
131
|
+
(void) mach_timebase_info(&mach_timebase);
|
132
|
+
#endif
|
133
|
+
|
134
|
+
#ifdef OS_WIN32
|
135
|
+
TickCountTickover = 0;
|
136
|
+
LastTickCount = 0;
|
137
|
+
#endif
|
138
|
+
|
88
139
|
// Make sure the current loop time is sane, in case we do any initializations of
|
89
140
|
// objects before we start running.
|
90
141
|
_UpdateTime();
|
@@ -101,6 +152,7 @@ EventMachine_t::EventMachine_t (EMCallback event_callback):
|
|
101
152
|
#endif
|
102
153
|
|
103
154
|
_InitializeLoopBreaker();
|
155
|
+
SelectData = new SelectData_t();
|
104
156
|
}
|
105
157
|
|
106
158
|
|
@@ -130,40 +182,8 @@ EventMachine_t::~EventMachine_t()
|
|
130
182
|
close (epfd);
|
131
183
|
if (kqfd != -1)
|
132
184
|
close (kqfd);
|
133
|
-
}
|
134
|
-
|
135
|
-
|
136
|
-
/*************************
|
137
|
-
EventMachine_t::_UseEpoll
|
138
|
-
*************************/
|
139
|
-
|
140
|
-
void EventMachine_t::_UseEpoll()
|
141
|
-
{
|
142
|
-
/* Temporary.
|
143
|
-
* Use an internal flag to switch in epoll-based functionality until we determine
|
144
|
-
* how it should be integrated properly and the extent of the required changes.
|
145
|
-
* A permanent solution needs to allow the integration of additional technologies,
|
146
|
-
* like kqueue and Solaris's events.
|
147
|
-
*/
|
148
|
-
|
149
|
-
#ifdef HAVE_EPOLL
|
150
|
-
bEpoll = true;
|
151
|
-
#endif
|
152
|
-
}
|
153
|
-
|
154
|
-
/**************************
|
155
|
-
EventMachine_t::_UseKqueue
|
156
|
-
**************************/
|
157
|
-
|
158
|
-
void EventMachine_t::_UseKqueue()
|
159
|
-
{
|
160
|
-
/* Temporary.
|
161
|
-
* See comments under _UseEpoll.
|
162
|
-
*/
|
163
185
|
|
164
|
-
|
165
|
-
bKqueue = true;
|
166
|
-
#endif
|
186
|
+
delete SelectData;
|
167
187
|
}
|
168
188
|
|
169
189
|
|
@@ -173,23 +193,32 @@ EventMachine_t::ScheduleHalt
|
|
173
193
|
|
174
194
|
void EventMachine_t::ScheduleHalt()
|
175
195
|
{
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
196
|
+
/* This is how we stop the machine.
|
197
|
+
* This can be called by clients. Signal handlers will probably
|
198
|
+
* set the global flag.
|
199
|
+
* For now this means there can only be one EventMachine ever running at a time.
|
200
|
+
*
|
201
|
+
* IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
|
202
|
+
* because it may be called from signal handlers invoked from code that we don't
|
203
|
+
* control. At this writing (20Sep06), EM does NOT install any signal handlers of
|
204
|
+
* its own.
|
205
|
+
*
|
206
|
+
* We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
|
207
|
+
* The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
|
208
|
+
*/
|
189
209
|
bTerminateSignalReceived = true;
|
190
|
-
}
|
191
210
|
|
211
|
+
/* Signal the loopbreaker so we break out of long-running select/epoll/kqueue and
|
212
|
+
* notice the halt boolean is set. Signalling the loopbreaker also uses a single
|
213
|
+
* signal-safe syscall.
|
214
|
+
*/
|
215
|
+
SignalLoopBreaker();
|
216
|
+
}
|
192
217
|
|
218
|
+
bool EventMachine_t::Stopping()
|
219
|
+
{
|
220
|
+
return bTerminateSignalReceived;
|
221
|
+
}
|
193
222
|
|
194
223
|
/*******************************
|
195
224
|
EventMachine_t::SetTimerQuantum
|
@@ -212,45 +241,54 @@ void EventMachine_t::SetTimerQuantum (int interval)
|
|
212
241
|
(STATIC) EventMachine_t::SetuidString
|
213
242
|
*************************************/
|
214
243
|
|
244
|
+
#ifdef OS_UNIX
|
215
245
|
void EventMachine_t::SetuidString (const char *username)
|
216
246
|
{
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
247
|
+
/* This method takes a caller-supplied username and tries to setuid
|
248
|
+
* to that user. There is no meaningful implementation (and no error)
|
249
|
+
* on Windows. On Unix, a failure to setuid the caller-supplied string
|
250
|
+
* causes a fatal abort, because presumably the program is calling here
|
251
|
+
* in order to fulfill a security requirement. If we fail silently,
|
252
|
+
* the user may continue to run with too much privilege.
|
253
|
+
*
|
254
|
+
* TODO, we need to decide on and document a way of generating C++ level errors
|
255
|
+
* that can be wrapped in documented Ruby exceptions, so users can catch
|
256
|
+
* and handle them. And distinguish it from errors that we WON'T let the Ruby
|
257
|
+
* user catch (like security-violations and resource-overallocation).
|
258
|
+
* A setuid failure here would be in the latter category.
|
259
|
+
*/
|
230
260
|
|
231
|
-
|
232
|
-
|
233
|
-
throw std::runtime_error ("setuid_string failed: no username specified");
|
261
|
+
if (!username || !*username)
|
262
|
+
throw std::runtime_error ("setuid_string failed: no username specified");
|
234
263
|
|
235
|
-
|
236
|
-
|
237
|
-
|
264
|
+
errno = 0;
|
265
|
+
struct passwd *p = getpwnam (username);
|
266
|
+
if (!p) {
|
267
|
+
if (errno) {
|
268
|
+
char buf[200];
|
269
|
+
snprintf (buf, sizeof(buf)-1, "setuid_string failed: %s", strerror(errno));
|
270
|
+
throw std::runtime_error (buf);
|
271
|
+
} else {
|
272
|
+
throw std::runtime_error ("setuid_string failed: unknown username");
|
273
|
+
}
|
274
|
+
}
|
238
275
|
|
239
|
-
|
240
|
-
|
276
|
+
if (setuid (p->pw_uid) != 0)
|
277
|
+
throw std::runtime_error ("setuid_string failed: no setuid");
|
241
278
|
|
242
|
-
|
243
|
-
#endif
|
279
|
+
// Success.
|
244
280
|
}
|
245
|
-
|
281
|
+
#else
|
282
|
+
void EventMachine_t::SetuidString (const char *username UNUSED) { }
|
283
|
+
#endif
|
246
284
|
|
247
285
|
/****************************************
|
248
286
|
(STATIC) EventMachine_t::SetRlimitNofile
|
249
287
|
****************************************/
|
250
288
|
|
289
|
+
#ifdef OS_UNIX
|
251
290
|
int EventMachine_t::SetRlimitNofile (int nofiles)
|
252
291
|
{
|
253
|
-
#ifdef OS_UNIX
|
254
292
|
struct rlimit rlim;
|
255
293
|
getrlimit (RLIMIT_NOFILE, &rlim);
|
256
294
|
if (nofiles >= 0) {
|
@@ -263,14 +301,10 @@ int EventMachine_t::SetRlimitNofile (int nofiles)
|
|
263
301
|
}
|
264
302
|
getrlimit (RLIMIT_NOFILE, &rlim);
|
265
303
|
return rlim.rlim_cur;
|
266
|
-
#endif
|
267
|
-
|
268
|
-
#ifdef OS_WIN32
|
269
|
-
// No meaningful implementation on Windows.
|
270
|
-
return 0;
|
271
|
-
#endif
|
272
304
|
}
|
273
|
-
|
305
|
+
#else
|
306
|
+
int EventMachine_t::SetRlimitNofile (int nofiles UNUSED) { return 0; }
|
307
|
+
#endif
|
274
308
|
|
275
309
|
/*********************************
|
276
310
|
EventMachine_t::SignalLoopBreaker
|
@@ -279,7 +313,7 @@ EventMachine_t::SignalLoopBreaker
|
|
279
313
|
void EventMachine_t::SignalLoopBreaker()
|
280
314
|
{
|
281
315
|
#ifdef OS_UNIX
|
282
|
-
write (LoopBreakerWriter, "", 1);
|
316
|
+
(void)write (LoopBreakerWriter, "", 1);
|
283
317
|
#endif
|
284
318
|
#ifdef OS_WIN32
|
285
319
|
sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
|
@@ -303,8 +337,18 @@ void EventMachine_t::_InitializeLoopBreaker()
|
|
303
337
|
|
304
338
|
#ifdef OS_UNIX
|
305
339
|
int fd[2];
|
340
|
+
#if defined (HAVE_CLOEXEC) && defined (HAVE_PIPE2)
|
341
|
+
int pipestatus = pipe2(fd, O_CLOEXEC);
|
342
|
+
if (pipestatus < 0) {
|
343
|
+
if (pipe(fd))
|
344
|
+
throw std::runtime_error (strerror(errno));
|
345
|
+
}
|
346
|
+
#else
|
306
347
|
if (pipe (fd))
|
307
348
|
throw std::runtime_error (strerror(errno));
|
349
|
+
#endif
|
350
|
+
if (!SetFdCloexec(fd[0]) || !SetFdCloexec(fd[1]))
|
351
|
+
throw std::runtime_error (strerror(errno));
|
308
352
|
|
309
353
|
LoopBreakerWriter = fd[1];
|
310
354
|
LoopBreakerReader = fd[0];
|
@@ -315,7 +359,7 @@ void EventMachine_t::_InitializeLoopBreaker()
|
|
315
359
|
#endif
|
316
360
|
|
317
361
|
#ifdef OS_WIN32
|
318
|
-
|
362
|
+
SOCKET sd = EmSocket (AF_INET, SOCK_DGRAM, 0);
|
319
363
|
if (sd == INVALID_SOCKET)
|
320
364
|
throw std::runtime_error ("no loop breaker socket");
|
321
365
|
SetSocketNonblocking (sd);
|
@@ -337,6 +381,43 @@ void EventMachine_t::_InitializeLoopBreaker()
|
|
337
381
|
throw std::runtime_error ("no loop breaker");
|
338
382
|
LoopBreakerReader = sd;
|
339
383
|
#endif
|
384
|
+
|
385
|
+
#ifdef HAVE_EPOLL
|
386
|
+
if (Poller == Poller_Epoll) {
|
387
|
+
epfd = epoll_create (MaxEpollDescriptors);
|
388
|
+
if (epfd == -1) {
|
389
|
+
char buf[200];
|
390
|
+
snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
|
391
|
+
throw std::runtime_error (buf);
|
392
|
+
}
|
393
|
+
int cloexec = fcntl (epfd, F_GETFD, 0);
|
394
|
+
assert (cloexec >= 0);
|
395
|
+
cloexec |= FD_CLOEXEC;
|
396
|
+
fcntl (epfd, F_SETFD, cloexec);
|
397
|
+
|
398
|
+
assert (LoopBreakerReader >= 0);
|
399
|
+
LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
|
400
|
+
assert (ld);
|
401
|
+
Add (ld);
|
402
|
+
}
|
403
|
+
#endif
|
404
|
+
|
405
|
+
#ifdef HAVE_KQUEUE
|
406
|
+
if (Poller == Poller_Kqueue) {
|
407
|
+
kqfd = kqueue();
|
408
|
+
if (kqfd == -1) {
|
409
|
+
char buf[200];
|
410
|
+
snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
|
411
|
+
throw std::runtime_error (buf);
|
412
|
+
}
|
413
|
+
// cloexec not needed. By definition, kqueues are not carried across forks.
|
414
|
+
|
415
|
+
assert (LoopBreakerReader >= 0);
|
416
|
+
LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
|
417
|
+
assert (ld);
|
418
|
+
Add (ld);
|
419
|
+
}
|
420
|
+
#endif
|
340
421
|
}
|
341
422
|
|
342
423
|
/***************************
|
@@ -352,16 +433,49 @@ void EventMachine_t::_UpdateTime()
|
|
352
433
|
EventMachine_t::GetRealTime
|
353
434
|
***************************/
|
354
435
|
|
436
|
+
// Two great writeups of cross-platform monotonic time are at:
|
437
|
+
// http://www.python.org/dev/peps/pep-0418
|
438
|
+
// http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking
|
439
|
+
// Uncomment the #pragma messages to confirm which compile-time option was used
|
355
440
|
uint64_t EventMachine_t::GetRealTime()
|
356
441
|
{
|
357
442
|
uint64_t current_time;
|
358
443
|
|
359
|
-
#if defined(
|
444
|
+
#if defined(HAVE_CONST_CLOCK_MONOTONIC_RAW)
|
445
|
+
// #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC_RAW"
|
446
|
+
// Linux 2.6.28 and above
|
447
|
+
struct timespec tv;
|
448
|
+
clock_gettime (CLOCK_MONOTONIC_RAW, &tv);
|
449
|
+
current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
|
450
|
+
|
451
|
+
#elif defined(HAVE_CONST_CLOCK_MONOTONIC)
|
452
|
+
// #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC"
|
453
|
+
// Linux, FreeBSD 5.0 and above, Solaris 8 and above, OpenBSD, NetBSD, DragonflyBSD
|
454
|
+
struct timespec tv;
|
455
|
+
clock_gettime (CLOCK_MONOTONIC, &tv);
|
456
|
+
current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
|
457
|
+
|
458
|
+
#elif defined(HAVE_GETHRTIME)
|
459
|
+
// #pragma message "GetRealTime: gethrtime"
|
460
|
+
// Solaris and HP-UX
|
461
|
+
current_time = (uint64_t)gethrtime() / 1000;
|
462
|
+
|
463
|
+
#elif defined(OS_DARWIN)
|
464
|
+
// #pragma message "GetRealTime: mach_absolute_time"
|
465
|
+
// Mac OS X
|
466
|
+
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
|
467
|
+
current_time = mach_absolute_time() * mach_timebase.numer / mach_timebase.denom / 1000;
|
468
|
+
|
469
|
+
#elif defined(OS_UNIX)
|
470
|
+
// #pragma message "GetRealTime: gettimeofday"
|
471
|
+
// Unix fallback
|
360
472
|
struct timeval tv;
|
361
473
|
gettimeofday (&tv, NULL);
|
362
474
|
current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
|
363
475
|
|
364
476
|
#elif defined(OS_WIN32)
|
477
|
+
// #pragma message "GetRealTime: GetTickCount"
|
478
|
+
// Future improvement: use GetTickCount64 in Windows Vista / Server 2008
|
365
479
|
unsigned tick = GetTickCount();
|
366
480
|
if (tick < LastTickCount)
|
367
481
|
TickCountTickover += 1;
|
@@ -370,6 +484,8 @@ uint64_t EventMachine_t::GetRealTime()
|
|
370
484
|
current_time *= 1000; // convert to microseconds
|
371
485
|
|
372
486
|
#else
|
487
|
+
// #pragma message "GetRealTime: time"
|
488
|
+
// Universal fallback
|
373
489
|
current_time = (uint64_t)time(NULL) * 1000000LL;
|
374
490
|
#endif
|
375
491
|
|
@@ -382,15 +498,27 @@ EventMachine_t::_DispatchHeartbeats
|
|
382
498
|
|
383
499
|
void EventMachine_t::_DispatchHeartbeats()
|
384
500
|
{
|
501
|
+
// Store the first processed heartbeat descriptor and bail out if
|
502
|
+
// we see it again. This fixes an infinite loop in case the system time
|
503
|
+
// is changed out from underneath MyCurrentLoopTime.
|
504
|
+
const EventableDescriptor *head = NULL;
|
505
|
+
|
385
506
|
while (true) {
|
386
507
|
multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
|
387
508
|
if (i == Heartbeats.end())
|
388
509
|
break;
|
389
510
|
if (i->first > MyCurrentLoopTime)
|
390
511
|
break;
|
512
|
+
|
391
513
|
EventableDescriptor *ed = i->second;
|
514
|
+
if (ed == head)
|
515
|
+
break;
|
516
|
+
|
392
517
|
ed->Heartbeat();
|
393
518
|
QueueHeartbeat(ed);
|
519
|
+
|
520
|
+
if (head == NULL)
|
521
|
+
head = ed;
|
394
522
|
}
|
395
523
|
}
|
396
524
|
|
@@ -434,75 +562,44 @@ EventMachine_t::Run
|
|
434
562
|
|
435
563
|
void EventMachine_t::Run()
|
436
564
|
{
|
437
|
-
|
438
|
-
if (bEpoll) {
|
439
|
-
epfd = epoll_create (MaxEpollDescriptors);
|
440
|
-
if (epfd == -1) {
|
441
|
-
char buf[200];
|
442
|
-
snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
|
443
|
-
throw std::runtime_error (buf);
|
444
|
-
}
|
445
|
-
int cloexec = fcntl (epfd, F_GETFD, 0);
|
446
|
-
assert (cloexec >= 0);
|
447
|
-
cloexec |= FD_CLOEXEC;
|
448
|
-
fcntl (epfd, F_SETFD, cloexec);
|
449
|
-
|
450
|
-
assert (LoopBreakerReader >= 0);
|
451
|
-
LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
|
452
|
-
assert (ld);
|
453
|
-
Add (ld);
|
454
|
-
}
|
455
|
-
#endif
|
456
|
-
|
457
|
-
#ifdef HAVE_KQUEUE
|
458
|
-
if (bKqueue) {
|
459
|
-
kqfd = kqueue();
|
460
|
-
if (kqfd == -1) {
|
461
|
-
char buf[200];
|
462
|
-
snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
|
463
|
-
throw std::runtime_error (buf);
|
464
|
-
}
|
465
|
-
// cloexec not needed. By definition, kqueues are not carried across forks.
|
466
|
-
|
467
|
-
assert (LoopBreakerReader >= 0);
|
468
|
-
LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
|
469
|
-
assert (ld);
|
470
|
-
Add (ld);
|
471
|
-
}
|
472
|
-
#endif
|
473
|
-
|
474
|
-
while (true) {
|
475
|
-
_UpdateTime();
|
476
|
-
_RunTimers();
|
477
|
-
|
478
|
-
/* _Add must precede _Modify because the same descriptor might
|
479
|
-
* be on both lists during the same pass through the machine,
|
480
|
-
* and to modify a descriptor before adding it would fail.
|
481
|
-
*/
|
482
|
-
_AddNewDescriptors();
|
483
|
-
_ModifyDescriptors();
|
484
|
-
|
485
|
-
_RunOnce();
|
486
|
-
if (bTerminateSignalReceived)
|
487
|
-
break;
|
488
|
-
}
|
565
|
+
while (RunOnce()) ;
|
489
566
|
}
|
490
567
|
|
568
|
+
/***********************
|
569
|
+
EventMachine_t::RunOnce
|
570
|
+
***********************/
|
491
571
|
|
492
|
-
|
493
|
-
EventMachine_t::_RunOnce
|
494
|
-
************************/
|
495
|
-
|
496
|
-
void EventMachine_t::_RunOnce()
|
572
|
+
bool EventMachine_t::RunOnce()
|
497
573
|
{
|
498
|
-
|
574
|
+
_UpdateTime();
|
575
|
+
_RunTimers();
|
576
|
+
|
577
|
+
/* _Add must precede _Modify because the same descriptor might
|
578
|
+
* be on both lists during the same pass through the machine,
|
579
|
+
* and to modify a descriptor before adding it would fail.
|
580
|
+
*/
|
581
|
+
_AddNewDescriptors();
|
582
|
+
_ModifyDescriptors();
|
583
|
+
|
584
|
+
switch (Poller) {
|
585
|
+
case Poller_Epoll:
|
499
586
|
_RunEpollOnce();
|
500
|
-
|
587
|
+
break;
|
588
|
+
case Poller_Kqueue:
|
501
589
|
_RunKqueueOnce();
|
502
|
-
|
590
|
+
break;
|
591
|
+
case Poller_Default:
|
503
592
|
_RunSelectOnce();
|
593
|
+
break;
|
594
|
+
}
|
595
|
+
|
504
596
|
_DispatchHeartbeats();
|
505
597
|
_CleanupSockets();
|
598
|
+
|
599
|
+
if (bTerminateSignalReceived)
|
600
|
+
return false;
|
601
|
+
|
602
|
+
return true;
|
506
603
|
}
|
507
604
|
|
508
605
|
|
@@ -583,9 +680,9 @@ void EventMachine_t::_RunEpollOnce()
|
|
583
680
|
EventMachine_t::_RunKqueueOnce
|
584
681
|
******************************/
|
585
682
|
|
683
|
+
#ifdef HAVE_KQUEUE
|
586
684
|
void EventMachine_t::_RunKqueueOnce()
|
587
685
|
{
|
588
|
-
#ifdef HAVE_KQUEUE
|
589
686
|
assert (kqfd != -1);
|
590
687
|
int k;
|
591
688
|
|
@@ -663,10 +760,13 @@ void EventMachine_t::_RunKqueueOnce()
|
|
663
760
|
rb_thread_schedule();
|
664
761
|
}
|
665
762
|
#endif
|
666
|
-
|
763
|
+
}
|
764
|
+
#else
|
765
|
+
void EventMachine_t::_RunKqueueOnce()
|
766
|
+
{
|
667
767
|
throw std::runtime_error ("kqueue is not implemented on this platform");
|
668
|
-
#endif
|
669
768
|
}
|
769
|
+
#endif
|
670
770
|
|
671
771
|
|
672
772
|
/*********************************
|
@@ -675,7 +775,7 @@ EventMachine_t::_TimeTilNextEvent
|
|
675
775
|
|
676
776
|
timeval EventMachine_t::_TimeTilNextEvent()
|
677
777
|
{
|
678
|
-
// 29jul11: Changed calculation base from MyCurrentLoopTime to the
|
778
|
+
// 29jul11: Changed calculation base from MyCurrentLoopTime to the
|
679
779
|
// real time. As MyCurrentLoopTime is set at the beginning of an
|
680
780
|
// iteration and this calculation is done at the end, evenmachine
|
681
781
|
// will potentially oversleep by the amount of time the iteration
|
@@ -697,10 +797,12 @@ timeval EventMachine_t::_TimeTilNextEvent()
|
|
697
797
|
if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
|
698
798
|
next_event = current_time;
|
699
799
|
}
|
700
|
-
|
800
|
+
|
701
801
|
timeval tv;
|
702
802
|
|
703
|
-
if (
|
803
|
+
if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
|
804
|
+
tv.tv_sec = tv.tv_usec = 0;
|
805
|
+
} else if (next_event == 0) {
|
704
806
|
tv = Quantum;
|
705
807
|
} else {
|
706
808
|
if (next_event > current_time) {
|
@@ -739,7 +841,7 @@ void EventMachine_t::_CleanupSockets()
|
|
739
841
|
assert (ed);
|
740
842
|
if (ed->ShouldDelete()) {
|
741
843
|
#ifdef HAVE_EPOLL
|
742
|
-
if (
|
844
|
+
if (Poller == Poller_Epoll) {
|
743
845
|
assert (epfd != -1);
|
744
846
|
if (ed->GetSocket() != INVALID_SOCKET) {
|
745
847
|
int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
|
@@ -766,10 +868,10 @@ void EventMachine_t::_CleanupSockets()
|
|
766
868
|
EventMachine_t::_ModifyEpollEvent
|
767
869
|
*********************************/
|
768
870
|
|
871
|
+
#ifdef HAVE_EPOLL
|
769
872
|
void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
|
770
873
|
{
|
771
|
-
|
772
|
-
if (bEpoll) {
|
874
|
+
if (Poller == Poller_Epoll) {
|
773
875
|
assert (epfd != -1);
|
774
876
|
assert (ed);
|
775
877
|
assert (ed->GetSocket() != INVALID_SOCKET);
|
@@ -780,9 +882,10 @@ void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
|
|
780
882
|
throw std::runtime_error (buf);
|
781
883
|
}
|
782
884
|
}
|
783
|
-
#endif
|
784
885
|
}
|
785
|
-
|
886
|
+
#else
|
887
|
+
void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed UNUSED) { }
|
888
|
+
#endif
|
786
889
|
|
787
890
|
|
788
891
|
/**************************
|
@@ -792,22 +895,28 @@ SelectData_t::SelectData_t
|
|
792
895
|
SelectData_t::SelectData_t()
|
793
896
|
{
|
794
897
|
maxsocket = 0;
|
795
|
-
|
796
|
-
|
797
|
-
|
898
|
+
rb_fd_init (&fdreads);
|
899
|
+
rb_fd_init (&fdwrites);
|
900
|
+
rb_fd_init (&fderrors);
|
798
901
|
}
|
799
902
|
|
903
|
+
SelectData_t::~SelectData_t()
|
904
|
+
{
|
905
|
+
rb_fd_term (&fdreads);
|
906
|
+
rb_fd_term (&fdwrites);
|
907
|
+
rb_fd_term (&fderrors);
|
908
|
+
}
|
800
909
|
|
801
910
|
#ifdef BUILD_FOR_RUBY
|
802
911
|
/*****************
|
803
912
|
_SelectDataSelect
|
804
913
|
*****************/
|
805
914
|
|
806
|
-
#
|
915
|
+
#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
807
916
|
static VALUE _SelectDataSelect (void *v)
|
808
917
|
{
|
809
918
|
SelectData_t *sd = (SelectData_t*)v;
|
810
|
-
sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
|
919
|
+
sd->nSockets = select (sd->maxsocket+1, rb_fd_ptr(&(sd->fdreads)), rb_fd_ptr(&(sd->fdwrites)), rb_fd_ptr(&(sd->fderrors)), &(sd->tv));
|
811
920
|
return Qnil;
|
812
921
|
}
|
813
922
|
#endif
|
@@ -818,18 +927,27 @@ SelectData_t::_Select
|
|
818
927
|
|
819
928
|
int SelectData_t::_Select()
|
820
929
|
{
|
821
|
-
#
|
930
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
931
|
+
// added in ruby 1.9.3
|
932
|
+
rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
|
933
|
+
return nSockets;
|
934
|
+
#elif defined(HAVE_TBR)
|
935
|
+
// added in ruby 1.9.1, deprecated in ruby 2.0.0
|
822
936
|
rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
|
823
937
|
return nSockets;
|
824
|
-
#
|
825
|
-
|
826
|
-
#ifndef HAVE_TBR
|
938
|
+
#else
|
827
939
|
return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
|
828
940
|
#endif
|
829
941
|
}
|
830
942
|
#endif
|
831
943
|
|
832
|
-
|
944
|
+
void SelectData_t::_Clear()
|
945
|
+
{
|
946
|
+
maxsocket = 0;
|
947
|
+
rb_fd_zero (&fdreads);
|
948
|
+
rb_fd_zero (&fdwrites);
|
949
|
+
rb_fd_zero (&fderrors);
|
950
|
+
}
|
833
951
|
|
834
952
|
/******************************
|
835
953
|
EventMachine_t::_RunSelectOnce
|
@@ -846,56 +964,51 @@ void EventMachine_t::_RunSelectOnce()
|
|
846
964
|
// however it has the same problem interoperating with Ruby
|
847
965
|
// threads that select does.
|
848
966
|
|
849
|
-
|
850
|
-
|
851
|
-
fd_set fdreads, fdwrites;
|
852
|
-
FD_ZERO (&fdreads);
|
853
|
-
FD_ZERO (&fdwrites);
|
854
|
-
|
855
|
-
int maxsocket = 0;
|
856
|
-
*/
|
967
|
+
// Get ready for select()
|
968
|
+
SelectData->_Clear();
|
857
969
|
|
858
970
|
// Always read the loop-breaker reader.
|
859
971
|
// Changed 23Aug06, provisionally implemented for Windows with a UDP socket
|
860
972
|
// running on localhost with a randomly-chosen port. (*Puke*)
|
861
973
|
// Windows has a version of the Unix pipe() library function, but it doesn't
|
862
974
|
// give you back descriptors that are selectable.
|
863
|
-
|
864
|
-
if (SelectData
|
865
|
-
SelectData
|
975
|
+
rb_fd_set (LoopBreakerReader, &(SelectData->fdreads));
|
976
|
+
if (SelectData->maxsocket < LoopBreakerReader)
|
977
|
+
SelectData->maxsocket = LoopBreakerReader;
|
866
978
|
|
867
979
|
// prepare the sockets for reading and writing
|
868
980
|
size_t i;
|
869
981
|
for (i = 0; i < Descriptors.size(); i++) {
|
870
982
|
EventableDescriptor *ed = Descriptors[i];
|
871
983
|
assert (ed);
|
872
|
-
|
984
|
+
SOCKET sd = ed->GetSocket();
|
873
985
|
if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
|
874
986
|
continue;
|
875
987
|
assert (sd != INVALID_SOCKET);
|
876
988
|
|
877
989
|
if (ed->SelectForRead())
|
878
|
-
|
990
|
+
rb_fd_set (sd, &(SelectData->fdreads));
|
879
991
|
if (ed->SelectForWrite())
|
880
|
-
|
992
|
+
rb_fd_set (sd, &(SelectData->fdwrites));
|
881
993
|
|
882
994
|
#ifdef OS_WIN32
|
883
995
|
/* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable.
|
884
996
|
Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html
|
885
997
|
*/
|
886
|
-
|
998
|
+
if (ed->IsConnectPending())
|
999
|
+
rb_fd_set (sd, &(SelectData->fderrors));
|
887
1000
|
#endif
|
888
1001
|
|
889
|
-
if (SelectData
|
890
|
-
SelectData
|
1002
|
+
if (SelectData->maxsocket < sd)
|
1003
|
+
SelectData->maxsocket = sd;
|
891
1004
|
}
|
892
1005
|
|
893
1006
|
|
894
1007
|
{ // read and write the sockets
|
895
1008
|
//timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
|
896
1009
|
//timeval tv = Quantum;
|
897
|
-
SelectData
|
898
|
-
int s = SelectData
|
1010
|
+
SelectData->tv = _TimeTilNextEvent();
|
1011
|
+
int s = SelectData->_Select();
|
899
1012
|
//rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
|
900
1013
|
//int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
|
901
1014
|
//int s = SelectData.nSockets;
|
@@ -913,20 +1026,24 @@ void EventMachine_t::_RunSelectOnce()
|
|
913
1026
|
for (i=0; i < Descriptors.size(); i++) {
|
914
1027
|
EventableDescriptor *ed = Descriptors[i];
|
915
1028
|
assert (ed);
|
916
|
-
|
1029
|
+
SOCKET sd = ed->GetSocket();
|
917
1030
|
if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
|
918
1031
|
continue;
|
919
1032
|
assert (sd != INVALID_SOCKET);
|
920
1033
|
|
921
|
-
if (
|
922
|
-
|
923
|
-
|
1034
|
+
if (rb_fd_isset (sd, &(SelectData->fdwrites))) {
|
1035
|
+
// Double-check SelectForWrite() still returns true. If not, one of the callbacks must have
|
1036
|
+
// modified some value since we checked SelectForWrite() earlier in this method.
|
1037
|
+
if (ed->SelectForWrite())
|
1038
|
+
ed->Write();
|
1039
|
+
}
|
1040
|
+
if (rb_fd_isset (sd, &(SelectData->fdreads)))
|
924
1041
|
ed->Read();
|
925
|
-
if (
|
1042
|
+
if (rb_fd_isset (sd, &(SelectData->fderrors)))
|
926
1043
|
ed->HandleError();
|
927
1044
|
}
|
928
1045
|
|
929
|
-
if (
|
1046
|
+
if (rb_fd_isset (LoopBreakerReader, &(SelectData->fdreads)))
|
930
1047
|
_ReadLoopBreaker();
|
931
1048
|
}
|
932
1049
|
else if (s < 0) {
|
@@ -958,17 +1075,18 @@ void EventMachine_t::_CleanBadDescriptors()
|
|
958
1075
|
if (ed->ShouldDelete())
|
959
1076
|
continue;
|
960
1077
|
|
961
|
-
|
1078
|
+
SOCKET sd = ed->GetSocket();
|
962
1079
|
|
963
1080
|
struct timeval tv;
|
964
1081
|
tv.tv_sec = 0;
|
965
1082
|
tv.tv_usec = 0;
|
966
1083
|
|
967
|
-
|
968
|
-
|
969
|
-
|
1084
|
+
rb_fdset_t fds;
|
1085
|
+
rb_fd_init(&fds);
|
1086
|
+
rb_fd_set(sd, &fds);
|
970
1087
|
|
971
|
-
int ret =
|
1088
|
+
int ret = rb_fd_select(sd + 1, &fds, NULL, NULL, &tv);
|
1089
|
+
rb_fd_term(&fds);
|
972
1090
|
|
973
1091
|
if (ret == -1) {
|
974
1092
|
if (errno == EBADF)
|
@@ -988,7 +1106,7 @@ void EventMachine_t::_ReadLoopBreaker()
|
|
988
1106
|
* and send a loop-break event back to user code.
|
989
1107
|
*/
|
990
1108
|
char buffer [1024];
|
991
|
-
read (LoopBreakerReader, buffer, sizeof(buffer));
|
1109
|
+
(void)read (LoopBreakerReader, buffer, sizeof(buffer));
|
992
1110
|
if (EventCallback)
|
993
1111
|
(*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0);
|
994
1112
|
}
|
@@ -1024,7 +1142,7 @@ void EventMachine_t::_RunTimers()
|
|
1024
1142
|
EventMachine_t::InstallOneshotTimer
|
1025
1143
|
***********************************/
|
1026
1144
|
|
1027
|
-
const
|
1145
|
+
const uintptr_t EventMachine_t::InstallOneshotTimer (int milliseconds)
|
1028
1146
|
{
|
1029
1147
|
if (Timers.size() > MaxOutstandingTimers)
|
1030
1148
|
return false;
|
@@ -1046,7 +1164,7 @@ const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
|
|
1046
1164
|
EventMachine_t::ConnectToServer
|
1047
1165
|
*******************************/
|
1048
1166
|
|
1049
|
-
const
|
1167
|
+
const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port)
|
1050
1168
|
{
|
1051
1169
|
/* We want to spend no more than a few seconds waiting for a connection
|
1052
1170
|
* to a remote host. So we use a nonblocking connect.
|
@@ -1074,13 +1192,15 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1074
1192
|
if (!server || !*server || !port)
|
1075
1193
|
throw std::runtime_error ("invalid server or port");
|
1076
1194
|
|
1077
|
-
|
1078
|
-
|
1079
|
-
if (!
|
1080
|
-
|
1081
|
-
|
1195
|
+
struct sockaddr_storage bind_as;
|
1196
|
+
size_t bind_as_len = sizeof bind_as;
|
1197
|
+
if (!name2address (server, port, (struct sockaddr *)&bind_as, &bind_as_len)) {
|
1198
|
+
char buf [200];
|
1199
|
+
snprintf (buf, sizeof(buf)-1, "unable to resolve server address: %s", strerror(errno));
|
1200
|
+
throw std::runtime_error (buf);
|
1201
|
+
}
|
1082
1202
|
|
1083
|
-
|
1203
|
+
SOCKET sd = EmSocket (bind_as.ss_family, SOCK_STREAM, 0);
|
1084
1204
|
if (sd == INVALID_SOCKET) {
|
1085
1205
|
char buf [200];
|
1086
1206
|
snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
|
@@ -1100,24 +1220,23 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1100
1220
|
setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
|
1101
1221
|
|
1102
1222
|
if (bind_addr) {
|
1103
|
-
|
1104
|
-
|
1105
|
-
if (!bind_to) {
|
1223
|
+
struct sockaddr_storage bind_to;
|
1224
|
+
size_t bind_to_len = sizeof bind_to;
|
1225
|
+
if (!name2address (bind_addr, bind_port, (struct sockaddr *)&bind_to, &bind_to_len)) {
|
1106
1226
|
close (sd);
|
1107
1227
|
throw std::runtime_error ("invalid bind address");
|
1108
1228
|
}
|
1109
|
-
if (bind (sd, bind_to,
|
1229
|
+
if (bind (sd, (struct sockaddr *)&bind_to, bind_to_len) < 0) {
|
1110
1230
|
close (sd);
|
1111
1231
|
throw std::runtime_error ("couldn't bind to address");
|
1112
1232
|
}
|
1113
1233
|
}
|
1114
1234
|
|
1115
|
-
|
1116
|
-
int e = 0;
|
1235
|
+
uintptr_t out = 0;
|
1117
1236
|
|
1118
1237
|
#ifdef OS_UNIX
|
1119
|
-
|
1120
|
-
if (connect (sd, &bind_as,
|
1238
|
+
int e_reason = 0;
|
1239
|
+
if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
|
1121
1240
|
// This is a connect success, which Linux appears
|
1122
1241
|
// never to give when the socket is nonblocking,
|
1123
1242
|
// even if the connection is intramachine or to
|
@@ -1163,13 +1282,13 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1163
1282
|
out = cd->GetBinding();
|
1164
1283
|
} else {
|
1165
1284
|
// Fall through to the !out case below.
|
1166
|
-
|
1285
|
+
e_reason = error;
|
1167
1286
|
}
|
1168
1287
|
}
|
1169
1288
|
else {
|
1170
1289
|
// The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
|
1171
1290
|
// Fall through to the !out case below
|
1172
|
-
|
1291
|
+
e_reason = errno;
|
1173
1292
|
}
|
1174
1293
|
|
1175
1294
|
if (!out) {
|
@@ -1188,7 +1307,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1188
1307
|
ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
|
1189
1308
|
if (!cd)
|
1190
1309
|
throw std::runtime_error ("no connection allocated");
|
1191
|
-
cd->SetUnbindReasonCode(
|
1310
|
+
cd->SetUnbindReasonCode (e_reason);
|
1192
1311
|
cd->ScheduleClose (false);
|
1193
1312
|
Add (cd);
|
1194
1313
|
out = cd->GetBinding();
|
@@ -1196,8 +1315,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1196
1315
|
#endif
|
1197
1316
|
|
1198
1317
|
#ifdef OS_WIN32
|
1199
|
-
|
1200
|
-
if (connect (sd, &bind_as, bind_size) == 0) {
|
1318
|
+
if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
|
1201
1319
|
// This is a connect success, which Windows appears
|
1202
1320
|
// never to give when the socket is nonblocking,
|
1203
1321
|
// even if the connection is intramachine or to
|
@@ -1232,7 +1350,8 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1232
1350
|
EventMachine_t::ConnectToUnixServer
|
1233
1351
|
***********************************/
|
1234
1352
|
|
1235
|
-
|
1353
|
+
#ifdef OS_UNIX
|
1354
|
+
const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
|
1236
1355
|
{
|
1237
1356
|
/* Connect to a Unix-domain server, which by definition is running
|
1238
1357
|
* on the same host.
|
@@ -1241,15 +1360,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
|
|
1241
1360
|
* is always local and can always be fulfilled immediately.
|
1242
1361
|
*/
|
1243
1362
|
|
1244
|
-
|
1245
|
-
throw std::runtime_error ("unix-domain connection unavailable on this platform");
|
1246
|
-
return 0;
|
1247
|
-
#endif
|
1248
|
-
|
1249
|
-
// The whole rest of this function is only compiled on Unix systems.
|
1250
|
-
#ifdef OS_UNIX
|
1251
|
-
|
1252
|
-
unsigned long out = 0;
|
1363
|
+
uintptr_t out = 0;
|
1253
1364
|
|
1254
1365
|
if (!server || !*server)
|
1255
1366
|
return 0;
|
@@ -1266,7 +1377,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
|
|
1266
1377
|
|
1267
1378
|
strcpy (pun.sun_path, server);
|
1268
1379
|
|
1269
|
-
|
1380
|
+
SOCKET fd = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
|
1270
1381
|
if (fd == INVALID_SOCKET)
|
1271
1382
|
return 0;
|
1272
1383
|
|
@@ -1298,18 +1409,28 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
|
|
1298
1409
|
close (fd);
|
1299
1410
|
|
1300
1411
|
return out;
|
1301
|
-
#endif
|
1302
1412
|
}
|
1413
|
+
#else
|
1414
|
+
const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server UNUSED)
|
1415
|
+
{
|
1416
|
+
throw std::runtime_error ("unix-domain connection unavailable on this platform");
|
1417
|
+
}
|
1418
|
+
#endif
|
1303
1419
|
|
1304
1420
|
/************************
|
1305
1421
|
EventMachine_t::AttachFD
|
1306
1422
|
************************/
|
1307
1423
|
|
1308
|
-
const
|
1424
|
+
const uintptr_t EventMachine_t::AttachFD (SOCKET fd, bool watch_mode)
|
1309
1425
|
{
|
1310
1426
|
#ifdef OS_UNIX
|
1311
|
-
if (fcntl(fd, F_GETFL, 0) < 0)
|
1312
|
-
|
1427
|
+
if (fcntl(fd, F_GETFL, 0) < 0) {
|
1428
|
+
if (errno) {
|
1429
|
+
throw std::runtime_error (strerror(errno));
|
1430
|
+
} else {
|
1431
|
+
throw std::runtime_error ("invalid file descriptor");
|
1432
|
+
}
|
1433
|
+
}
|
1313
1434
|
#endif
|
1314
1435
|
|
1315
1436
|
#ifdef OS_WIN32
|
@@ -1348,7 +1469,7 @@ const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
|
|
1348
1469
|
|
1349
1470
|
Add (cd);
|
1350
1471
|
|
1351
|
-
const
|
1472
|
+
const uintptr_t out = cd->GetBinding();
|
1352
1473
|
return out;
|
1353
1474
|
}
|
1354
1475
|
|
@@ -1361,10 +1482,10 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1361
1482
|
if (!ed)
|
1362
1483
|
throw std::runtime_error ("detaching bad descriptor");
|
1363
1484
|
|
1364
|
-
|
1485
|
+
SOCKET fd = ed->GetSocket();
|
1365
1486
|
|
1366
1487
|
#ifdef HAVE_EPOLL
|
1367
|
-
if (
|
1488
|
+
if (Poller == Poller_Epoll) {
|
1368
1489
|
if (ed->GetSocket() != INVALID_SOCKET) {
|
1369
1490
|
assert (epfd != -1);
|
1370
1491
|
int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
|
@@ -1379,7 +1500,7 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1379
1500
|
#endif
|
1380
1501
|
|
1381
1502
|
#ifdef HAVE_KQUEUE
|
1382
|
-
if (
|
1503
|
+
if (Poller == Poller_Kqueue) {
|
1383
1504
|
// remove any read/write events for this fd
|
1384
1505
|
struct kevent k;
|
1385
1506
|
#ifdef __NetBSD__
|
@@ -1399,6 +1520,14 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1399
1520
|
// Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
|
1400
1521
|
ModifiedDescriptors.erase (ed);
|
1401
1522
|
|
1523
|
+
// Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
|
1524
|
+
for (size_t i = 0; i < NewDescriptors.size(); i++) {
|
1525
|
+
if (ed == NewDescriptors[i]) {
|
1526
|
+
NewDescriptors.erase(NewDescriptors.begin() + i);
|
1527
|
+
break;
|
1528
|
+
}
|
1529
|
+
}
|
1530
|
+
|
1402
1531
|
// Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
|
1403
1532
|
// and also to prevent anyone from calling close() on the detached fd
|
1404
1533
|
ed->SetSocketInvalid();
|
@@ -1410,66 +1539,30 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1410
1539
|
name2address
|
1411
1540
|
************/
|
1412
1541
|
|
1413
|
-
|
1542
|
+
bool EventMachine_t::name2address (const char *server, int port, struct sockaddr *addr, size_t *addr_len)
|
1414
1543
|
{
|
1415
|
-
// THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.
|
1416
|
-
// Check the more-common cases first.
|
1417
|
-
// Return NULL if no resolution.
|
1418
|
-
|
1419
|
-
static struct sockaddr_in in4;
|
1420
|
-
#ifndef __CYGWIN__
|
1421
|
-
static struct sockaddr_in6 in6;
|
1422
|
-
#endif
|
1423
|
-
struct hostent *hp;
|
1424
|
-
|
1425
1544
|
if (!server || !*server)
|
1426
1545
|
server = "0.0.0.0";
|
1427
1546
|
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
*bind_size = sizeof(in4);
|
1434
|
-
in4.sin_family = AF_INET;
|
1435
|
-
in4.sin_port = htons (port);
|
1436
|
-
return (struct sockaddr*)&in4;
|
1437
|
-
}
|
1438
|
-
|
1439
|
-
#if defined(OS_UNIX) && !defined(__CYGWIN__)
|
1440
|
-
memset (&in6, 0, sizeof(in6));
|
1441
|
-
if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) {
|
1442
|
-
if (family)
|
1443
|
-
*family = AF_INET6;
|
1444
|
-
if (bind_size)
|
1445
|
-
*bind_size = sizeof(in6);
|
1446
|
-
in6.sin6_family = AF_INET6;
|
1447
|
-
in6.sin6_port = htons (port);
|
1448
|
-
return (struct sockaddr*)&in6;
|
1449
|
-
}
|
1450
|
-
#endif
|
1547
|
+
struct addrinfo *ai;
|
1548
|
+
struct addrinfo hints;
|
1549
|
+
memset (&hints, 0, sizeof(hints));
|
1550
|
+
hints.ai_family = AF_UNSPEC;
|
1551
|
+
hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
|
1451
1552
|
|
1452
|
-
|
1453
|
-
|
1454
|
-
// A possible approach is to make a getaddrinfo call with the supplied
|
1455
|
-
// server address, constraining the hints to ipv6 and seeing if we
|
1456
|
-
// get any addresses.
|
1457
|
-
// For the time being, Ipv6 addresses aren't supported on Windows.
|
1458
|
-
#endif
|
1553
|
+
char portstr[12];
|
1554
|
+
snprintf(portstr, sizeof(portstr), "%u", port);
|
1459
1555
|
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
in4.sin_family = AF_INET;
|
1468
|
-
in4.sin_port = htons (port);
|
1469
|
-
return (struct sockaddr*)&in4;
|
1556
|
+
if (getaddrinfo (server, portstr, &hints, &ai) == 0) {
|
1557
|
+
assert (ai->ai_addrlen <= *addr_len);
|
1558
|
+
memcpy (addr, ai->ai_addr, ai->ai_addrlen);
|
1559
|
+
*addr_len = ai->ai_addrlen;
|
1560
|
+
|
1561
|
+
freeaddrinfo(ai);
|
1562
|
+
return true;
|
1470
1563
|
}
|
1471
1564
|
|
1472
|
-
return
|
1565
|
+
return false;
|
1473
1566
|
}
|
1474
1567
|
|
1475
1568
|
|
@@ -1477,7 +1570,7 @@ struct sockaddr *name2address (const char *server, int port, int *family, int *b
|
|
1477
1570
|
EventMachine_t::CreateTcpServer
|
1478
1571
|
*******************************/
|
1479
1572
|
|
1480
|
-
const
|
1573
|
+
const uintptr_t EventMachine_t::CreateTcpServer (const char *server, int port)
|
1481
1574
|
{
|
1482
1575
|
/* Create a TCP-acceptor (server) socket and add it to the event machine.
|
1483
1576
|
* Return the binding of the new acceptor to the caller.
|
@@ -1486,16 +1579,12 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1486
1579
|
*/
|
1487
1580
|
|
1488
1581
|
|
1489
|
-
|
1490
|
-
|
1491
|
-
if (!bind_here)
|
1582
|
+
struct sockaddr_storage bind_here;
|
1583
|
+
size_t bind_here_len = sizeof bind_here;
|
1584
|
+
if (!name2address (server, port, (struct sockaddr *)&bind_here, &bind_here_len))
|
1492
1585
|
return 0;
|
1493
1586
|
|
1494
|
-
|
1495
|
-
|
1496
|
-
//struct sockaddr_in sin;
|
1497
|
-
|
1498
|
-
int sd_accept = socket (family, SOCK_STREAM, 0);
|
1587
|
+
SOCKET sd_accept = EmSocket (bind_here.ss_family, SOCK_STREAM, 0);
|
1499
1588
|
if (sd_accept == INVALID_SOCKET) {
|
1500
1589
|
goto fail;
|
1501
1590
|
}
|
@@ -1518,8 +1607,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1518
1607
|
}
|
1519
1608
|
|
1520
1609
|
|
1521
|
-
|
1522
|
-
if (bind (sd_accept, bind_here, bind_size)) {
|
1610
|
+
if (bind (sd_accept, (struct sockaddr *)&bind_here, bind_here_len)) {
|
1523
1611
|
//__warning ("binding failed");
|
1524
1612
|
goto fail;
|
1525
1613
|
}
|
@@ -1529,25 +1617,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1529
1617
|
goto fail;
|
1530
1618
|
}
|
1531
1619
|
|
1532
|
-
|
1533
|
-
// Set the acceptor non-blocking.
|
1534
|
-
// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
|
1535
|
-
if (!SetSocketNonblocking (sd_accept)) {
|
1536
|
-
//int val = fcntl (sd_accept, F_GETFL, 0);
|
1537
|
-
//if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
|
1538
|
-
goto fail;
|
1539
|
-
}
|
1540
|
-
}
|
1541
|
-
|
1542
|
-
{ // Looking good.
|
1543
|
-
AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
|
1544
|
-
if (!ad)
|
1545
|
-
throw std::runtime_error ("unable to allocate acceptor");
|
1546
|
-
Add (ad);
|
1547
|
-
output_binding = ad->GetBinding();
|
1548
|
-
}
|
1549
|
-
|
1550
|
-
return output_binding;
|
1620
|
+
return AttachSD(sd_accept);
|
1551
1621
|
|
1552
1622
|
fail:
|
1553
1623
|
if (sd_accept != INVALID_SOCKET)
|
@@ -1560,44 +1630,31 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1560
1630
|
EventMachine_t::OpenDatagramSocket
|
1561
1631
|
**********************************/
|
1562
1632
|
|
1563
|
-
const
|
1633
|
+
const uintptr_t EventMachine_t::OpenDatagramSocket (const char *address, int port)
|
1564
1634
|
{
|
1565
|
-
|
1635
|
+
uintptr_t output_binding = 0;
|
1566
1636
|
|
1567
|
-
|
1637
|
+
struct sockaddr_storage bind_here;
|
1638
|
+
size_t bind_here_len = sizeof bind_here;
|
1639
|
+
if (!name2address (address, port, (struct sockaddr *)&bind_here, &bind_here_len))
|
1640
|
+
return 0;
|
1641
|
+
|
1642
|
+
// from here on, early returns must close the socket!
|
1643
|
+
SOCKET sd = EmSocket (bind_here.ss_family, SOCK_DGRAM, 0);
|
1568
1644
|
if (sd == INVALID_SOCKET)
|
1569
1645
|
goto fail;
|
1570
|
-
// from here on, early returns must close the socket!
|
1571
|
-
|
1572
|
-
|
1573
|
-
struct sockaddr_in sin;
|
1574
|
-
memset (&sin, 0, sizeof(sin));
|
1575
|
-
sin.sin_family = AF_INET;
|
1576
|
-
sin.sin_port = htons (port);
|
1577
1646
|
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
hostent *hp = gethostbyname ((char*)address); // Windows requires the cast.
|
1583
|
-
if (hp == NULL)
|
1584
|
-
goto fail;
|
1585
|
-
sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
|
1586
|
-
}
|
1647
|
+
{ // set the SO_REUSEADDR on the socket before we bind, otherwise it won't work for a second one
|
1648
|
+
int oval = 1;
|
1649
|
+
if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0)
|
1650
|
+
goto fail;
|
1587
1651
|
}
|
1588
|
-
else
|
1589
|
-
sin.sin_addr.s_addr = htonl (INADDR_ANY);
|
1590
|
-
|
1591
1652
|
|
1592
1653
|
// Set the new socket nonblocking.
|
1593
|
-
|
1594
|
-
|
1595
|
-
//int val = fcntl (sd, F_GETFL, 0);
|
1596
|
-
//if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1)
|
1597
|
-
goto fail;
|
1598
|
-
}
|
1654
|
+
if (!SetSocketNonblocking (sd))
|
1655
|
+
goto fail;
|
1599
1656
|
|
1600
|
-
if (bind (sd, (struct sockaddr*)&
|
1657
|
+
if (bind (sd, (struct sockaddr *)&bind_here, bind_here_len) != 0)
|
1601
1658
|
goto fail;
|
1602
1659
|
|
1603
1660
|
{ // Looking good.
|
@@ -1635,10 +1692,10 @@ void EventMachine_t::Add (EventableDescriptor *ed)
|
|
1635
1692
|
EventMachine_t::ArmKqueueWriter
|
1636
1693
|
*******************************/
|
1637
1694
|
|
1695
|
+
#ifdef HAVE_KQUEUE
|
1638
1696
|
void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
|
1639
1697
|
{
|
1640
|
-
|
1641
|
-
if (bKqueue) {
|
1698
|
+
if (Poller == Poller_Kqueue) {
|
1642
1699
|
if (!ed)
|
1643
1700
|
throw std::runtime_error ("added bad descriptor");
|
1644
1701
|
struct kevent k;
|
@@ -1654,17 +1711,19 @@ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
|
|
1654
1711
|
throw std::runtime_error (buf);
|
1655
1712
|
}
|
1656
1713
|
}
|
1657
|
-
#endif
|
1658
1714
|
}
|
1715
|
+
#else
|
1716
|
+
void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed UNUSED) { }
|
1717
|
+
#endif
|
1659
1718
|
|
1660
1719
|
/*******************************
|
1661
1720
|
EventMachine_t::ArmKqueueReader
|
1662
1721
|
*******************************/
|
1663
1722
|
|
1723
|
+
#ifdef HAVE_KQUEUE
|
1664
1724
|
void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
|
1665
1725
|
{
|
1666
|
-
|
1667
|
-
if (bKqueue) {
|
1726
|
+
if (Poller == Poller_Kqueue) {
|
1668
1727
|
if (!ed)
|
1669
1728
|
throw std::runtime_error ("added bad descriptor");
|
1670
1729
|
struct kevent k;
|
@@ -1680,8 +1739,10 @@ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
|
|
1680
1739
|
throw std::runtime_error (buf);
|
1681
1740
|
}
|
1682
1741
|
}
|
1683
|
-
#endif
|
1684
1742
|
}
|
1743
|
+
#else
|
1744
|
+
void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed UNUSED) { }
|
1745
|
+
#endif
|
1685
1746
|
|
1686
1747
|
/**********************************
|
1687
1748
|
EventMachine_t::_AddNewDescriptors
|
@@ -1706,7 +1767,7 @@ void EventMachine_t::_AddNewDescriptors()
|
|
1706
1767
|
throw std::runtime_error ("adding bad descriptor");
|
1707
1768
|
|
1708
1769
|
#if HAVE_EPOLL
|
1709
|
-
if (
|
1770
|
+
if (Poller == Poller_Epoll) {
|
1710
1771
|
assert (epfd != -1);
|
1711
1772
|
int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent());
|
1712
1773
|
if (e) {
|
@@ -1719,7 +1780,7 @@ void EventMachine_t::_AddNewDescriptors()
|
|
1719
1780
|
|
1720
1781
|
#if HAVE_KQUEUE
|
1721
1782
|
/*
|
1722
|
-
if (
|
1783
|
+
if (Poller == Poller_Kqueue) {
|
1723
1784
|
// INCOMPLETE. Some descriptors don't want to be readable.
|
1724
1785
|
assert (kqfd != -1);
|
1725
1786
|
struct kevent k;
|
@@ -1765,7 +1826,7 @@ void EventMachine_t::_ModifyDescriptors()
|
|
1765
1826
|
*/
|
1766
1827
|
|
1767
1828
|
#ifdef HAVE_EPOLL
|
1768
|
-
if (
|
1829
|
+
if (Poller == Poller_Epoll) {
|
1769
1830
|
set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
|
1770
1831
|
while (i != ModifiedDescriptors.end()) {
|
1771
1832
|
assert (*i);
|
@@ -1775,6 +1836,18 @@ void EventMachine_t::_ModifyDescriptors()
|
|
1775
1836
|
}
|
1776
1837
|
#endif
|
1777
1838
|
|
1839
|
+
#ifdef HAVE_KQUEUE
|
1840
|
+
if (Poller == Poller_Kqueue) {
|
1841
|
+
set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
|
1842
|
+
while (i != ModifiedDescriptors.end()) {
|
1843
|
+
assert (*i);
|
1844
|
+
if ((*i)->GetKqueueArmWrite())
|
1845
|
+
ArmKqueueWriter (*i);
|
1846
|
+
++i;
|
1847
|
+
}
|
1848
|
+
}
|
1849
|
+
#endif
|
1850
|
+
|
1778
1851
|
ModifiedDescriptors.clear();
|
1779
1852
|
}
|
1780
1853
|
|
@@ -1803,7 +1876,7 @@ void EventMachine_t::Deregister (EventableDescriptor *ed)
|
|
1803
1876
|
// cut/paste from _CleanupSockets(). The error handling could be
|
1804
1877
|
// refactored out of there, but it is cut/paste all over the
|
1805
1878
|
// file already.
|
1806
|
-
if (
|
1879
|
+
if (Poller == Poller_Epoll) {
|
1807
1880
|
assert (epfd != -1);
|
1808
1881
|
assert (ed->GetSocket() != INVALID_SOCKET);
|
1809
1882
|
int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
|
@@ -1823,7 +1896,8 @@ void EventMachine_t::Deregister (EventableDescriptor *ed)
|
|
1823
1896
|
EventMachine_t::CreateUnixDomainServer
|
1824
1897
|
**************************************/
|
1825
1898
|
|
1826
|
-
|
1899
|
+
#ifdef OS_UNIX
|
1900
|
+
const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename)
|
1827
1901
|
{
|
1828
1902
|
/* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
|
1829
1903
|
* Return the binding of the new acceptor to the caller.
|
@@ -1832,17 +1906,9 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1832
1906
|
* THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
|
1833
1907
|
*/
|
1834
1908
|
|
1835
|
-
#ifdef OS_WIN32
|
1836
|
-
throw std::runtime_error ("unix-domain server unavailable on this platform");
|
1837
|
-
#endif
|
1838
|
-
|
1839
|
-
// The whole rest of this function is only compiled on Unix systems.
|
1840
|
-
#ifdef OS_UNIX
|
1841
|
-
unsigned long output_binding = 0;
|
1842
|
-
|
1843
1909
|
struct sockaddr_un s_sun;
|
1844
1910
|
|
1845
|
-
|
1911
|
+
SOCKET sd_accept = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
|
1846
1912
|
if (sd_accept == INVALID_SOCKET) {
|
1847
1913
|
goto fail;
|
1848
1914
|
}
|
@@ -1876,6 +1942,29 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1876
1942
|
goto fail;
|
1877
1943
|
}
|
1878
1944
|
|
1945
|
+
return AttachSD(sd_accept);
|
1946
|
+
|
1947
|
+
fail:
|
1948
|
+
if (sd_accept != INVALID_SOCKET)
|
1949
|
+
close (sd_accept);
|
1950
|
+
return 0;
|
1951
|
+
}
|
1952
|
+
#else
|
1953
|
+
const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename UNUSED)
|
1954
|
+
{
|
1955
|
+
throw std::runtime_error ("unix-domain server unavailable on this platform");
|
1956
|
+
}
|
1957
|
+
#endif
|
1958
|
+
|
1959
|
+
|
1960
|
+
/**************************************
|
1961
|
+
EventMachine_t::AttachSD
|
1962
|
+
**************************************/
|
1963
|
+
|
1964
|
+
const uintptr_t EventMachine_t::AttachSD (SOCKET sd_accept)
|
1965
|
+
{
|
1966
|
+
uintptr_t output_binding = 0;
|
1967
|
+
|
1879
1968
|
{
|
1880
1969
|
// Set the acceptor non-blocking.
|
1881
1970
|
// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
|
@@ -1900,64 +1989,16 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1900
1989
|
if (sd_accept != INVALID_SOCKET)
|
1901
1990
|
close (sd_accept);
|
1902
1991
|
return 0;
|
1903
|
-
#endif // OS_UNIX
|
1904
1992
|
}
|
1905
1993
|
|
1906
1994
|
|
1907
|
-
/*********************
|
1908
|
-
EventMachine_t::Popen
|
1909
|
-
*********************/
|
1910
|
-
#if OBSOLETE
|
1911
|
-
const char *EventMachine_t::Popen (const char *cmd, const char *mode)
|
1912
|
-
{
|
1913
|
-
#ifdef OS_WIN32
|
1914
|
-
throw std::runtime_error ("popen is currently unavailable on this platform");
|
1915
|
-
#endif
|
1916
|
-
|
1917
|
-
// The whole rest of this function is only compiled on Unix systems.
|
1918
|
-
// Eventually we need this functionality (or a full-duplex equivalent) on Windows.
|
1919
|
-
#ifdef OS_UNIX
|
1920
|
-
const char *output_binding = NULL;
|
1921
|
-
|
1922
|
-
FILE *fp = popen (cmd, mode);
|
1923
|
-
if (!fp)
|
1924
|
-
return NULL;
|
1925
|
-
|
1926
|
-
// From here, all early returns must pclose the stream.
|
1927
|
-
|
1928
|
-
// According to the pipe(2) manpage, descriptors returned from pipe have both
|
1929
|
-
// CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.
|
1930
|
-
if (!SetSocketNonblocking (fileno (fp))) {
|
1931
|
-
pclose (fp);
|
1932
|
-
return NULL;
|
1933
|
-
}
|
1934
|
-
|
1935
|
-
{ // Looking good.
|
1936
|
-
PipeDescriptor *pd = new PipeDescriptor (fp, this);
|
1937
|
-
if (!pd)
|
1938
|
-
throw std::runtime_error ("unable to allocate pipe");
|
1939
|
-
Add (pd);
|
1940
|
-
output_binding = pd->GetBinding();
|
1941
|
-
}
|
1942
|
-
|
1943
|
-
return output_binding;
|
1944
|
-
#endif
|
1945
|
-
}
|
1946
|
-
#endif // OBSOLETE
|
1947
|
-
|
1948
1995
|
/**************************
|
1949
1996
|
EventMachine_t::Socketpair
|
1950
1997
|
**************************/
|
1951
1998
|
|
1952
|
-
|
1999
|
+
#ifdef OS_UNIX
|
2000
|
+
const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings)
|
1953
2001
|
{
|
1954
|
-
#ifdef OS_WIN32
|
1955
|
-
throw std::runtime_error ("socketpair is currently unavailable on this platform");
|
1956
|
-
#endif
|
1957
|
-
|
1958
|
-
// The whole rest of this function is only compiled on Unix systems.
|
1959
|
-
// Eventually we need this functionality (or a full-duplex equivalent) on Windows.
|
1960
|
-
#ifdef OS_UNIX
|
1961
2002
|
// Make sure the incoming array of command strings is sane.
|
1962
2003
|
if (!cmd_strings)
|
1963
2004
|
return 0;
|
@@ -1967,7 +2008,7 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
|
|
1967
2008
|
if ((j==0) || (j==2048))
|
1968
2009
|
return 0;
|
1969
2010
|
|
1970
|
-
|
2011
|
+
uintptr_t output_binding = 0;
|
1971
2012
|
|
1972
2013
|
int sv[2];
|
1973
2014
|
if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
|
@@ -2005,15 +2046,21 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
|
|
2005
2046
|
throw std::runtime_error ("no fork");
|
2006
2047
|
|
2007
2048
|
return output_binding;
|
2008
|
-
#endif
|
2009
2049
|
}
|
2050
|
+
#else
|
2051
|
+
const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings UNUSED)
|
2052
|
+
{
|
2053
|
+
throw std::runtime_error ("socketpair is currently unavailable on this platform");
|
2054
|
+
}
|
2055
|
+
#endif
|
2056
|
+
|
2010
2057
|
|
2011
2058
|
|
2012
2059
|
/****************************
|
2013
2060
|
EventMachine_t::OpenKeyboard
|
2014
2061
|
****************************/
|
2015
2062
|
|
2016
|
-
const
|
2063
|
+
const uintptr_t EventMachine_t::OpenKeyboard()
|
2017
2064
|
{
|
2018
2065
|
KeyboardDescriptor *kd = new KeyboardDescriptor (this);
|
2019
2066
|
if (!kd)
|
@@ -2037,10 +2084,10 @@ int EventMachine_t::GetConnectionCount ()
|
|
2037
2084
|
EventMachine_t::WatchPid
|
2038
2085
|
************************/
|
2039
2086
|
|
2040
|
-
|
2087
|
+
#ifdef HAVE_KQUEUE
|
2088
|
+
const uintptr_t EventMachine_t::WatchPid (int pid)
|
2041
2089
|
{
|
2042
|
-
|
2043
|
-
if (!bKqueue)
|
2090
|
+
if (Poller != Poller_Kqueue)
|
2044
2091
|
throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support");
|
2045
2092
|
|
2046
2093
|
struct kevent event;
|
@@ -2055,17 +2102,17 @@ const unsigned long EventMachine_t::WatchPid (int pid)
|
|
2055
2102
|
sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
|
2056
2103
|
throw std::runtime_error(errbuf);
|
2057
2104
|
}
|
2058
|
-
#endif
|
2059
|
-
|
2060
|
-
#ifdef HAVE_KQUEUE
|
2061
2105
|
Bindable_t* b = new Bindable_t();
|
2062
2106
|
Pids.insert(make_pair (pid, b));
|
2063
2107
|
|
2064
2108
|
return b->GetBinding();
|
2065
|
-
|
2066
|
-
|
2109
|
+
}
|
2110
|
+
#else
|
2111
|
+
const uintptr_t EventMachine_t::WatchPid (int pid UNUSED)
|
2112
|
+
{
|
2067
2113
|
throw std::runtime_error("no pid watching support on this system");
|
2068
2114
|
}
|
2115
|
+
#endif
|
2069
2116
|
|
2070
2117
|
/**************************
|
2071
2118
|
EventMachine_t::UnwatchPid
|
@@ -2091,7 +2138,7 @@ void EventMachine_t::UnwatchPid (int pid)
|
|
2091
2138
|
delete b;
|
2092
2139
|
}
|
2093
2140
|
|
2094
|
-
void EventMachine_t::UnwatchPid (const
|
2141
|
+
void EventMachine_t::UnwatchPid (const uintptr_t sig)
|
2095
2142
|
{
|
2096
2143
|
for(map<int, Bindable_t*>::iterator i=Pids.begin(); i != Pids.end(); i++)
|
2097
2144
|
{
|
@@ -2109,7 +2156,7 @@ void EventMachine_t::UnwatchPid (const unsigned long sig)
|
|
2109
2156
|
EventMachine_t::WatchFile
|
2110
2157
|
*************************/
|
2111
2158
|
|
2112
|
-
const
|
2159
|
+
const uintptr_t EventMachine_t::WatchFile (const char *fpath)
|
2113
2160
|
{
|
2114
2161
|
struct stat sb;
|
2115
2162
|
int sres;
|
@@ -2140,7 +2187,7 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
|
|
2140
2187
|
#endif
|
2141
2188
|
|
2142
2189
|
#ifdef HAVE_KQUEUE
|
2143
|
-
if (
|
2190
|
+
if (Poller != Poller_Kqueue)
|
2144
2191
|
throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support");
|
2145
2192
|
|
2146
2193
|
// With kqueue we have to open the file first and use the resulting fd to register for events
|
@@ -2187,7 +2234,7 @@ void EventMachine_t::UnwatchFile (int wd)
|
|
2187
2234
|
delete b;
|
2188
2235
|
}
|
2189
2236
|
|
2190
|
-
void EventMachine_t::UnwatchFile (const
|
2237
|
+
void EventMachine_t::UnwatchFile (const uintptr_t sig)
|
2191
2238
|
{
|
2192
2239
|
for(map<int, Bindable_t*>::iterator i=Files.begin(); i != Files.end(); i++)
|
2193
2240
|
{
|
@@ -2213,9 +2260,9 @@ void EventMachine_t::_ReadInotifyEvents()
|
|
2213
2260
|
|
2214
2261
|
for (;;) {
|
2215
2262
|
int returned = read(inotify->GetSocket(), buffer, sizeof(buffer));
|
2216
|
-
assert(!(returned == 0 || returned == -1 && errno == EINVAL));
|
2263
|
+
assert(!(returned == 0 || (returned == -1 && errno == EINVAL)));
|
2217
2264
|
if (returned <= 0) {
|
2218
|
-
|
2265
|
+
break;
|
2219
2266
|
}
|
2220
2267
|
int current = 0;
|
2221
2268
|
while (current < returned) {
|
@@ -2330,4 +2377,3 @@ int EventMachine_t::SetHeartbeatInterval(float interval)
|
|
2330
2377
|
return 0;
|
2331
2378
|
}
|
2332
2379
|
//#endif // OS_UNIX
|
2333
|
-
|