eventmachine 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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