eventmachine 0.5.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/em.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.cpp 61 2006-05-17 04:58:31Z blackhedd $
3
+ $Id: em.cpp 267 2006-10-25 02:02:02Z blackhedd $
4
4
 
5
5
  File: ed.cpp
6
6
  Date: 06Apr06
@@ -35,6 +35,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35
35
  // This avoids the need for frequent expensive calls to time(NULL);
36
36
  time_t gCurrentLoopTime;
37
37
 
38
+ #ifdef OS_WIN32
39
+ unsigned gTickCountTickover;
40
+ unsigned gLastTickCount;
41
+ #endif
42
+
38
43
 
39
44
  /******************************
40
45
  EventMachine_t::EventMachine_t
@@ -42,9 +47,20 @@ EventMachine_t::EventMachine_t
42
47
 
43
48
  EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)):
44
49
  EventCallback (event_callback),
45
- NextHeartbeatTime (0)
50
+ NextHeartbeatTime (0),
51
+ LoopBreakerReader (-1),
52
+ LoopBreakerWriter (-1)
46
53
  {
54
+ // Default time-slice is just smaller than one hundred mills.
55
+ Quantum.tv_sec = 0;
56
+ Quantum.tv_usec = 90000;
57
+
47
58
  gTerminateSignalReceived = false;
59
+ // Make sure the current loop time is sane, in case we do any initializations of
60
+ // objects before we start running.
61
+ gCurrentLoopTime = time(NULL);
62
+
63
+ _InitializeLoopBreaker();
48
64
  }
49
65
 
50
66
 
@@ -60,6 +76,9 @@ EventMachine_t::~EventMachine_t()
60
76
  delete NewDescriptors[i];
61
77
  for (i = 0; i < Descriptors.size(); i++)
62
78
  delete Descriptors[i];
79
+
80
+ close (LoopBreakerReader);
81
+ close (LoopBreakerWriter);
63
82
  }
64
83
 
65
84
 
@@ -74,12 +93,103 @@ void EventMachine_t::ScheduleHalt()
74
93
  * This can be called by clients. Signal handlers will probably
75
94
  * set the global flag.
76
95
  * For now this means there can only be one EventMachine ever running at a time.
96
+ *
97
+ * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
98
+ * because it may be called from signal handlers invoked from code that we don't
99
+ * control. At this writing (20Sep06), EM does NOT install any signal handlers of
100
+ * its own.
101
+ *
102
+ * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
103
+ * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
77
104
  */
78
105
  gTerminateSignalReceived = true;
79
106
  }
80
107
 
81
108
 
82
109
 
110
+ /*******************************
111
+ EventMachine_t::SetTimerQuantum
112
+ *******************************/
113
+
114
+ void EventMachine_t::SetTimerQuantum (int interval)
115
+ {
116
+ /* We get a timer-quantum expressed in milliseconds.
117
+ * Don't set a quantum smaller than 5 or larger than 2500.
118
+ */
119
+
120
+ if ((interval < 5) || (interval > 2500))
121
+ throw std::runtime_error ("invalid timer-quantum");
122
+
123
+ Quantum.tv_sec = interval / 1000;
124
+ Quantum.tv_usec = (interval % 1000) * 1000;
125
+ }
126
+
127
+
128
+
129
+ /*********************************
130
+ EventMachine_t::SignalLoopBreaker
131
+ *********************************/
132
+
133
+ void EventMachine_t::SignalLoopBreaker()
134
+ {
135
+ #ifdef OS_UNIX
136
+ write (LoopBreakerWriter, "", 1);
137
+ #endif
138
+ #ifdef OS_WIN32
139
+ sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
140
+ #endif
141
+ }
142
+
143
+
144
+ /**************************************
145
+ EventMachine_t::_InitializeLoopBreaker
146
+ **************************************/
147
+
148
+ void EventMachine_t::_InitializeLoopBreaker()
149
+ {
150
+ /* A "loop-breaker" is a socket-descriptor that we can write to in order
151
+ * to break the main select loop. Primarily useful for things running on
152
+ * threads other than the main EM thread, so they can trigger processing
153
+ * of events that arise exogenously to the EM.
154
+ * Keep the loop-breaker pipe out of the main descriptor set, otherwise
155
+ * its events will get passed on to user code.
156
+ */
157
+
158
+ #ifdef OS_UNIX
159
+ int fd[2];
160
+ if (pipe (fd))
161
+ throw std::runtime_error ("no loop breaker");
162
+
163
+ LoopBreakerWriter = fd[1];
164
+ LoopBreakerReader = fd[0];
165
+ #endif
166
+
167
+ #ifdef OS_WIN32
168
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
169
+ if (sd == INVALID_SOCKET)
170
+ throw std::runtime_error ("no loop breaker socket");
171
+ SetSocketNonblocking (sd);
172
+
173
+ memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget));
174
+ LoopBreakerTarget.sin_family = AF_INET;
175
+ LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1");
176
+
177
+ srand ((int)time(NULL));
178
+ int i;
179
+ for (i=0; i < 100; i++) {
180
+ int r = (rand() % 10000) + 20000;
181
+ LoopBreakerTarget.sin_port = htons (r);
182
+ if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0)
183
+ break;
184
+ }
185
+
186
+ if (i == 100)
187
+ throw std::runtime_error ("no loop breaker");
188
+ LoopBreakerReader = sd;
189
+ #endif
190
+ }
191
+
192
+
83
193
  /*******************
84
194
  EventMachine_t::Run
85
195
  *******************/
@@ -122,18 +232,28 @@ bool EventMachine_t::_RunOnce()
122
232
  // Return T/F to indicate whether we should continue.
123
233
  // This is based on a select loop. Alternately provide epoll
124
234
  // if we know we're running on a 2.6 kernel.
235
+ // epoll will be effective if we provide it as an alternative,
236
+ // however it has the same problem interoperating with Ruby
237
+ // threads that selct does.
125
238
 
126
239
  //cerr << "X";
240
+
241
+ /* This protection is now obsolete, because we will ALWAYS
242
+ * have at least one descriptor (the loop-breaker) to read.
243
+ */
244
+ /*
127
245
  if (Descriptors.size() == 0) {
128
246
  #ifdef OS_UNIX
129
247
  timeval tv = {0, 200 * 1000};
130
248
  EmSelect (0, NULL, NULL, NULL, &tv);
249
+ return true;
131
250
  #endif
132
251
  #ifdef OS_WIN32
133
252
  Sleep (200);
134
- #endif
135
253
  return true;
254
+ #endif
136
255
  }
256
+ */
137
257
 
138
258
  fd_set fdreads, fdwrites;
139
259
  FD_ZERO (&fdreads);
@@ -141,6 +261,15 @@ bool EventMachine_t::_RunOnce()
141
261
 
142
262
  int maxsocket = 0;
143
263
 
264
+ // Always read the loop-breaker reader.
265
+ // Changed 23Aug06, provisionally implemented for Windows with a UDP socket
266
+ // running on localhost with a randomly-chosen port. (*Puke*)
267
+ // Windows has a version of the Unix pipe() library function, but it doesn't
268
+ // give you back descriptors that are selectable.
269
+ FD_SET (LoopBreakerReader, &fdreads);
270
+ if (maxsocket < LoopBreakerReader)
271
+ maxsocket = LoopBreakerReader;
272
+
144
273
  // prepare the sockets for reading and writing
145
274
  size_t i;
146
275
  for (i = 0; i < Descriptors.size(); i++) {
@@ -160,9 +289,13 @@ bool EventMachine_t::_RunOnce()
160
289
 
161
290
 
162
291
  { // read and write the sockets
163
- timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
292
+ //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
293
+ timeval tv = Quantum;
164
294
  int s = EmSelect (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
165
295
  if (s > 0) {
296
+ if (FD_ISSET (LoopBreakerReader, &fdreads))
297
+ _ReadLoopBreaker();
298
+
166
299
  for (i=0; i < Descriptors.size(); i++) {
167
300
  EventableDescriptor *ed = Descriptors[i];
168
301
  assert (ed);
@@ -178,7 +311,7 @@ bool EventMachine_t::_RunOnce()
178
311
  else if (s < 0) {
179
312
  // select can fail on error in a handful of ways.
180
313
  // If this happens, then wait for a little while to avoid busy-looping.
181
- // If the error was EINTR, we probaby caught SIGCHLD or something,
314
+ // If the error was EINTR, we probably caught SIGCHLD or something,
182
315
  // so keep the wait short.
183
316
  timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
184
317
  EmSelect (0, NULL, NULL, NULL, &tv);
@@ -219,6 +352,23 @@ bool EventMachine_t::_RunOnce()
219
352
  }
220
353
 
221
354
 
355
+ /********************************
356
+ EventMachine_t::_ReadLoopBreaker
357
+ ********************************/
358
+
359
+ void EventMachine_t::_ReadLoopBreaker()
360
+ {
361
+ /* The loop breaker has selected readable.
362
+ * Read it ONCE (it may block if we try to read it twice)
363
+ * and send a loop-break event back to user code.
364
+ */
365
+ char buffer [1024];
366
+ read (LoopBreakerReader, buffer, sizeof(buffer));
367
+ if (EventCallback)
368
+ (*EventCallback)("", EventMachine_t::LOOPBREAK_SIGNAL, "", 0);
369
+ }
370
+
371
+
222
372
  /**************************
223
373
  EventMachine_t::_RunTimers
224
374
  **************************/
@@ -232,11 +382,25 @@ bool EventMachine_t::_RunTimers()
232
382
  // Just keep inspecting and processing the list head until we hit
233
383
  // one that hasn't expired yet.
234
384
 
385
+ #ifdef OS_UNIX
386
+ struct timeval tv;
387
+ gettimeofday (&tv, NULL);
388
+ Int64 now = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
389
+ #endif
390
+
391
+ #ifdef OS_WIN32
392
+ unsigned tick = GetTickCount();
393
+ if (tick < gLastTickCount)
394
+ gTickCountTickover += 1;
395
+ gLastTickCount = tick;
396
+ Int64 now = ((Int64)gTickCountTickover << 32) + (Int64)tick;
397
+ #endif
398
+
235
399
  while (true) {
236
- multimap<time_t,Timer_t>::iterator i = Timers.begin();
400
+ multimap<Int64,Timer_t>::iterator i = Timers.begin();
237
401
  if (i == Timers.end())
238
402
  break;
239
- if (i->first > gCurrentLoopTime)
403
+ if (i->first > now)
240
404
  break;
241
405
  if (EventCallback)
242
406
  (*EventCallback) ("", TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
@@ -251,17 +415,33 @@ bool EventMachine_t::_RunTimers()
251
415
  EventMachine_t::InstallOneshotTimer
252
416
  ***********************************/
253
417
 
254
- const char *EventMachine_t::InstallOneshotTimer (int seconds)
418
+ const char *EventMachine_t::InstallOneshotTimer (int milliseconds)
255
419
  {
256
420
  if (Timers.size() > MaxOutstandingTimers)
257
421
  return false;
258
422
  // Don't use the global loop-time variable here, because we might
259
423
  // get called before the main event machine is running.
260
424
 
425
+ #ifdef OS_UNIX
426
+ struct timeval tv;
427
+ gettimeofday (&tv, NULL);
428
+ Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
429
+ fire_at += ((Int64)milliseconds) * 1000LL;
430
+ #endif
431
+
432
+ #ifdef OS_WIN32
433
+ unsigned tick = GetTickCount();
434
+ if (tick < gLastTickCount)
435
+ gTickCountTickover += 1;
436
+ gLastTickCount = tick;
437
+
438
+ Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick;
439
+ fire_at += (Int64)milliseconds;
440
+ #endif
441
+
261
442
  Timer_t t;
262
- multimap<time_t,Timer_t>::iterator i =
263
- Timers.insert (make_pair (time(NULL) + seconds, t));
264
- //return t.GetBinding().c_str();
443
+ multimap<Int64,Timer_t>::iterator i =
444
+ Timers.insert (make_pair (fire_at, t));
265
445
  return i->second.GetBindingChars();
266
446
  }
267
447
 
@@ -304,8 +484,14 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
304
484
  HostAddr = inet_addr (server);
305
485
  if (HostAddr == INADDR_NONE) {
306
486
  hostent *hp = gethostbyname ((char*)server); // Windows requires (char*)
307
- if (!hp)
487
+ if (!hp) {
488
+ // TODO: This gives the caller a fatal error. Not good.
489
+ // They can respond by catching RuntimeError (blecch).
490
+ // Possibly we need to fire an unbind event and provide
491
+ // a status code so user code can detect the cause of the
492
+ // failure.
308
493
  return NULL;
494
+ }
309
495
  HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
310
496
  }
311
497
 
@@ -333,7 +519,27 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
333
519
  // never to give when the socket is nonblocking,
334
520
  // even if the connection is intramachine or to
335
521
  // localhost.
336
- throw std::runtime_error ("unimplemented");
522
+
523
+ /* Changed this branch 08Aug06. Evidently some kernels
524
+ * (FreeBSD for example) will actually return success from
525
+ * a nonblocking connect. This is a pretty simple case,
526
+ * just set up the new connection and clear the pending flag.
527
+ * Thanks to Chris Ochs for helping track this down.
528
+ * This branch never gets taken on Linux or (oddly) OSX.
529
+ * The original behavior was to throw an unimplemented,
530
+ * which the user saw as a fatal exception. Very unfriendly.
531
+ *
532
+ * Tweaked 10Aug06. Even though the connect disposition is
533
+ * known, we still set the connect-pending flag. That way
534
+ * some needed initialization will happen in the ConnectionDescriptor.
535
+ * (To wit, the ConnectionCompleted event gets sent to the client.)
536
+ */
537
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
538
+ if (!cd)
539
+ throw std::runtime_error ("no connection allocated");
540
+ cd->SetConnectPending (true);
541
+ Add (cd);
542
+ out = cd->GetBinding().c_str();
337
543
  }
338
544
  else if (errno == EINPROGRESS) {
339
545
  // Errno will generally always be EINPROGRESS, but on Linux
@@ -354,7 +560,24 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
354
560
  out = cd->GetBinding().c_str();
355
561
  }
356
562
  else {
357
- // This could be connection refused or something such thing.
563
+ /* This could be connection refused or some such thing.
564
+ * We will come here on Linux if a localhost connection fails.
565
+ * Changed 16Jul06: Originally this branch was a no-op, and
566
+ * we'd drop down to the end of the method, close the socket,
567
+ * and return NULL, which would cause the caller to GET A
568
+ * FATAL EXCEPTION. Now we keep the socket around but schedule an
569
+ * immediate close on it, so the caller will get a close-event
570
+ * scheduled on it. This was only an issue for localhost connections
571
+ * to non-listening ports. We may eventually need to revise this
572
+ * revised behavior, in case it causes problems like making it hard
573
+ * for people to know that a failure occurred.
574
+ */
575
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
576
+ if (!cd)
577
+ throw std::runtime_error ("no connection allocated");
578
+ cd->ScheduleClose (false);
579
+ Add (cd);
580
+ out = cd->GetBinding().c_str();
358
581
  }
359
582
  }
360
583
  else {
@@ -574,6 +797,10 @@ void EventMachine_t::_AddNewDescriptors()
574
797
  * Any descriptors that are added as a result of processing timers
575
798
  * or acceptors should go on a temporary queue and then added
576
799
  * while we're not traversing the main list.
800
+ * Also, it (rarely) happens that a newly-created descriptor
801
+ * is immediately scheduled to close. It might be a good
802
+ * idea not to bother scheduling these for I/O but if
803
+ * we do that, we might bypass some important processing.
577
804
  */
578
805
 
579
806
  for (size_t i = 0; i < NewDescriptors.size(); i++) {
@@ -586,5 +813,115 @@ void EventMachine_t::_AddNewDescriptors()
586
813
  }
587
814
 
588
815
 
816
+ /***********************************
817
+ EventMachine_t::_OpenFileForWriting
818
+ ***********************************/
819
+
820
+ const char *EventMachine_t::_OpenFileForWriting (const char *filename)
821
+ {
822
+ /*
823
+ * Return the binding-text of the newly-opened file,
824
+ * or NULL if there was a problem.
825
+ */
826
+
827
+ if (!filename || !*filename)
828
+ return NULL;
829
+
830
+ int fd = open (filename, O_CREAT|O_TRUNC|O_WRONLY|O_NONBLOCK, 0644);
831
+
832
+ FileStreamDescriptor *fsd = new FileStreamDescriptor (fd);
833
+ if (!fsd)
834
+ throw std::runtime_error ("no file-stream allocated");
835
+ Add (fsd);
836
+ return fsd->GetBinding().c_str();
837
+
838
+ }
839
+
840
+
841
+ /**************************************
842
+ EventMachine_t::CreateUnixDomainServer
843
+ **************************************/
844
+
845
+ const char *EventMachine_t::CreateUnixDomainServer (const char *filename)
846
+ {
847
+ /* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
848
+ * Return the binding of the new acceptor to the caller.
849
+ * This binding will be referenced when the new acceptor sends events
850
+ * to indicate accepted connections.
851
+ * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
852
+ */
853
+
854
+ #ifdef OS_WIN32
855
+ throw std::runtime_error ("unix-domain server unavailable on this platform");
856
+ #endif
857
+
858
+ // The whole rest of this function is only compiled on Unix systems.
859
+ #ifdef OS_UNIX
860
+ const char *output_binding = NULL;
861
+
862
+ struct sockaddr_un sun;
863
+
864
+ int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0);
865
+ if (sd_accept == INVALID_SOCKET) {
866
+ goto fail;
867
+ }
868
+
869
+ if (!filename || !*filename)
870
+ goto fail;
871
+ unlink (filename);
872
+
873
+ bzero (&sun, sizeof(sun));
874
+ sun.sun_family = AF_LOCAL;
875
+ strncpy (sun.sun_path, filename, sizeof(sun.sun_path)-1);
876
+
877
+ // don't bother with reuseaddr for a local socket.
878
+
879
+ { // set CLOEXEC. Only makes sense on Unix
880
+ #ifdef OS_UNIX
881
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
882
+ assert (cloexec >= 0);
883
+ cloexec |= FD_CLOEXEC;
884
+ fcntl (sd_accept, F_SETFD, cloexec);
885
+ #endif
886
+ }
887
+
888
+ if (bind (sd_accept, (struct sockaddr*)&sun, sizeof(sun))) {
889
+ //__warning ("binding failed");
890
+ goto fail;
891
+ }
892
+
893
+ if (listen (sd_accept, 100)) {
894
+ //__warning ("listen failed");
895
+ goto fail;
896
+ }
897
+
898
+ {
899
+ // Set the acceptor non-blocking.
900
+ // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
901
+ if (!SetSocketNonblocking (sd_accept)) {
902
+ //int val = fcntl (sd_accept, F_GETFL, 0);
903
+ //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
904
+ goto fail;
905
+ }
906
+ }
907
+
908
+ { // Looking good.
909
+ AcceptorDescriptor *ad = new AcceptorDescriptor (this, sd_accept);
910
+ if (!ad)
911
+ throw std::runtime_error ("unable to allocate acceptor");
912
+ Add (ad);
913
+ output_binding = ad->GetBinding().c_str();
914
+ }
915
+
916
+ return output_binding;
917
+
918
+ fail:
919
+ if (sd_accept != INVALID_SOCKET)
920
+ closesocket (sd_accept);
921
+ return NULL;
922
+ #endif // OS_UNIX
923
+ }
924
+
925
+
589
926
  //#endif // OS_UNIX
590
927
 
data/ext/em.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.h 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: em.h 264 2006-10-05 16:33:22Z blackhedd $
4
4
 
5
5
  File: ed.h
6
6
  Date: 06Apr06
@@ -44,6 +44,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
44
44
  #define EmSelect select
45
45
  #endif
46
46
 
47
+
48
+ #ifdef OS_UNIX
49
+ typedef long long Int64;
50
+ #endif
51
+ #ifdef OS_WIN32
52
+ typedef __int64 Int64;
53
+ #endif
54
+
47
55
  extern time_t gCurrentLoopTime;
48
56
 
49
57
  class EventableDescriptor;
@@ -60,20 +68,27 @@ class EventMachine_t
60
68
  virtual ~EventMachine_t();
61
69
 
62
70
  void Run();
63
- void ScheduleHalt();
71
+ void ScheduleHalt();
72
+ void SignalLoopBreaker();
64
73
  const char *InstallOneshotTimer (int);
65
74
  const char *ConnectToServer (const char *, int);
66
75
  const char *CreateTcpServer (const char *, int);
67
76
  const char *OpenDatagramSocket (const char *, int);
77
+ const char *CreateUnixDomainServer (const char*);
78
+ const char *_OpenFileForWriting (const char*);
68
79
 
69
- void Add (EventableDescriptor*);
80
+ void Add (EventableDescriptor*);
70
81
 
71
- public:
82
+ void SetTimerQuantum (int);
83
+
84
+ public:
72
85
  enum { // Event names
73
86
  TIMER_FIRED = 100,
74
- CONNECTION_READ = 101,
75
- CONNECTION_UNBOUND = 102,
76
- CONNECTION_ACCEPTED = 103
87
+ CONNECTION_READ = 101,
88
+ CONNECTION_UNBOUND = 102,
89
+ CONNECTION_ACCEPTED = 103,
90
+ CONNECTION_COMPLETED = 104,
91
+ LOOPBREAK_SIGNAL = 105
77
92
  };
78
93
 
79
94
 
@@ -81,6 +96,8 @@ class EventMachine_t
81
96
  bool _RunOnce();
82
97
  bool _RunTimers();
83
98
  void _AddNewDescriptors();
99
+ void _InitializeLoopBreaker();
100
+ void _ReadLoopBreaker();
84
101
 
85
102
  private:
86
103
  enum {
@@ -92,11 +109,19 @@ class EventMachine_t
92
109
  class Timer_t: public Bindable_t {
93
110
  };
94
111
 
95
- multimap<time_t, Timer_t> Timers;
112
+ multimap<Int64, Timer_t> Timers;
96
113
  vector<EventableDescriptor*> Descriptors;
97
114
  vector<EventableDescriptor*> NewDescriptors;
98
115
 
99
116
  time_t NextHeartbeatTime;
117
+
118
+ int LoopBreakerReader;
119
+ int LoopBreakerWriter;
120
+ #ifdef OS_WIN32
121
+ struct sockaddr_in LoopBreakerTarget;
122
+ #endif
123
+
124
+ timeval Quantum;
100
125
  };
101
126
 
102
127
 
data/ext/emwin.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: emwin.h 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: emwin.h 209 2006-07-16 23:32:16Z blackhedd $
4
4
 
5
5
  File: edwin.h
6
6
  Date: 05May06
@@ -62,7 +62,9 @@ class EventMachine_t
62
62
  TIMER_FIRED = 100,
63
63
  CONNECTION_READ = 101,
64
64
  CONNECTION_UNBOUND = 102,
65
- CONNECTION_ACCEPTED = 103
65
+ CONNECTION_ACCEPTED = 103,
66
+ CONNECTION_COMPLETED = 104,
67
+ LOOPBREAK_SIGNAL = 105
66
68
  };
67
69
 
68
70
  private:
data/ext/eventmachine.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: eventmachine.h 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: eventmachine.h 265 2006-10-05 19:07:45Z blackhedd $
4
4
 
5
5
  File: eventmachine.h
6
6
  Date: 15Apr06
@@ -37,13 +37,21 @@ extern "C" {
37
37
  const char *evma_install_oneshot_timer (int seconds);
38
38
  const char *evma_connect_to_server (const char *server, int port);
39
39
  const char *evma_create_tcp_server (const char *address, int port);
40
+ const char *evma_create_unix_domain_server (const char *filename);
40
41
  const char *evma_open_datagram_socket (const char *server, int port);
41
42
  void evma_start_tls (const char *binding);
43
+ int evma_get_peername (const char *binding, struct sockaddr*);
42
44
  int evma_send_data_to_connection (const char *binding, const char *data, int data_length);
43
45
  int evma_send_datagram (const char *binding, const char *data, int data_length, const char *address, int port);
46
+ int evma_get_comm_inactivity_timeout (const char *binding, /*out*/int *value);
47
+ int evma_set_comm_inactivity_timeout (const char *binding, /*in,out*/int *value);
44
48
  void evma_close_connection (const char *binding, int after_writing);
49
+ void evma_signal_loopbreak();
50
+ void evma_set_timer_quantum (int);
45
51
  void evma_stop_machine();
46
52
 
53
+ const char *evma__write_file (const char *filename);
54
+
47
55
  #if __cplusplus
48
56
  }
49
57
  #endif