eventmachine 0.7.2 → 0.8.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/EPOLL ADDED
@@ -0,0 +1,142 @@
1
+ EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs.
2
+
3
+ Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels.
4
+ It features significantly greater performance than the standard select(2) mechanism, when used in
5
+ applications that require very large numbers of open I/O descriptors.
6
+
7
+ EventMachine has always used select(2) because its behavior is well standardized and broadly supported.
8
+ But select becomes unreasonably slow when a program has a
9
+ very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit
10
+ of 1024 descriptors per process, but heavily loaded processes will start to show performance
11
+ degradation even after only a few hundred descriptors are in use.
12
+
13
+ Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs
14
+ based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands
15
+ of connectors, with no significant impact on performance.
16
+
17
+ (Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its
18
+ variants.)
19
+
20
+
21
+
22
+ This note shows you how to use epoll in your programs.
23
+
24
+ === Compiling EventMachine to use epoll.
25
+
26
+ You don't have to do anything to get epoll support in EventMachine.
27
+ When you compile EventMachine on a platform that supports epoll, EM will
28
+ automatically generate a Makefile that includes epoll. (At this writing, this will only work
29
+ on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will
30
+ be omitted from the Makefile, and EM will work just as it always has.
31
+
32
+ === Using epoll in your programs.
33
+
34
+ First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement
35
+ will be removed in a future EventMachine version). Second, you need to prepare your program to use
36
+ more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably
37
+ want your process to drop the superuser privileges after you increase your process's descriptor limit.
38
+
39
+ === Using EventMachine#epoll
40
+
41
+ Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will
42
+ automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because
43
+
44
+ it compiles to a no-op on platforms that don't support epoll.
45
+
46
+ require 'rubygems'
47
+ require 'eventmachine'
48
+
49
+ EM.epoll
50
+ EM.run {
51
+ ...
52
+ }
53
+
54
+
55
+ EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing
56
+ programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op,
57
+ and run epoll by default on platforms that support it.
58
+
59
+ === Using EventMachine#set_descriptor_table_size
60
+
61
+ In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum
62
+ number of file and socket descriptors you may have open at any given time. The size of this table is
63
+ generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits.
64
+
65
+ If you want your EventMachine program to support more than 1024 total descriptors, you must use
66
+ EventMachine#set_descriptor_table_size, as follows:
67
+
68
+ require 'rubygems'
69
+ require 'eventmachine'
70
+
71
+ new_size = EM.set_descriptor_table_size( 60000 )
72
+ $>.puts "New descriptor-table size is #{new_size}"
73
+
74
+ EM.run {
75
+ ...
76
+ }
77
+
78
+ If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000.
79
+ Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current
80
+ size of the descriptor table.
81
+
82
+ Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used
83
+ by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the
84
+ number of descriptors that Ruby's own I/O functions can use.
85
+
86
+ #set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a
87
+ table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number.
88
+
89
+
90
+ === Using EventMachine#set_effective_user
91
+
92
+ In general, you must run your program with elevated or superuser privileges if you want to increase
93
+ your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the
94
+ sample program given above, that increases the descriptor limit to 60,000. You will probably find that
95
+ the table size will not be increased if you don't run your program as root or with elevated privileges.
96
+
97
+ But of course network servers, especially long-running ones, should not run with elevated privileges.
98
+ You will want to drop superuser privileges as soon as possible after initialization. To do this,
99
+ use EventMachine#set_effective_user:
100
+
101
+ require 'rubygems'
102
+ require 'eventmachine'
103
+
104
+ # (Here, program is running as superuser)
105
+
106
+ EM.set_descriptor_table_size( 60000 )
107
+ EM.set_effective_user( "nobody" )
108
+ # (Here, program is running as nobody)
109
+
110
+ EM.run {
111
+ ...
112
+ }
113
+
114
+ Of course, you will need to replace "nobody" in the example with the name of an unprivileged user
115
+ that is valid on your system. What if you want to drop privileges after opening a server socket
116
+ on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets:
117
+
118
+ require 'rubygems'
119
+ require 'eventmachine'
120
+
121
+ # (Here, program is running as superuser)
122
+
123
+ EM.set_descriptor_table_size( 60000 )
124
+
125
+ EM.run {
126
+ EM.start_server( "0.0.0.0", 80, MyHttpServer )
127
+ EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer )
128
+
129
+ EM.set_effective_user( "nobody" )
130
+ # (Here, program is running as nobody)
131
+
132
+ ...
133
+ }
134
+
135
+
136
+ Because EventMachine#set_effective_user is used to enforce security
137
+ requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user,
138
+ #set_effective_user will abort your program, rather than continue to run with elevated privileges.
139
+
140
+ EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows.
141
+
142
+
data/RELEASE_NOTES CHANGED
@@ -1,7 +1,20 @@
1
- $Id: RELEASE_NOTES 286 2006-11-28 03:18:18Z blackhedd $
1
+ $Id: RELEASE_NOTES 388 2007-06-25 02:06:05Z blackhedd $
2
2
 
3
3
  RUBY/EventMachine RELEASE NOTES
4
4
 
5
+ --------------------------------------------------
6
+ Version: 0.9.0, released xxXXX07
7
+ Added Erlang-like distributed-computing features
8
+
9
+ --------------------------------------------------
10
+ Version: 0.8.0, released 23Jun07
11
+ Added an epoll implementation for Linux 2.6 kernels.
12
+ Added evented #popen.
13
+
14
+ --------------------------------------------------
15
+ Version: 0.7.3, released 22May07
16
+ Added a large variety of small features. See the ChangeLog.
17
+
5
18
  --------------------------------------------------
6
19
  Version: 0.7.1, released xxNov06
7
20
  Added protocol handlers for line-oriented protocols.
data/ext/cmain.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: cmain.cpp 318 2007-05-22 22:06:24Z blackhedd $
3
+ $Id: cmain.cpp 377 2007-06-13 01:05:56Z blackhedd $
4
4
 
5
5
  File: cmain.cpp
6
6
  Date: 06Apr06
@@ -21,6 +21,7 @@ See the file COPYING for complete licensing information.
21
21
 
22
22
 
23
23
  static EventMachine_t *EventMachine;
24
+ static int bUseEpoll = 0;
24
25
 
25
26
 
26
27
  /***********************
@@ -35,6 +36,8 @@ extern "C" void evma_initialize_library (void(*cb)(const char*, int, const char*
35
36
  if (EventMachine)
36
37
  throw std::runtime_error ("already initialized");
37
38
  EventMachine = new EventMachine_t (cb);
39
+ if (bUseEpoll)
40
+ EventMachine->_UseEpoll();
38
41
  }
39
42
 
40
43
 
@@ -210,6 +213,22 @@ extern "C" int evma_get_peername (const char *binding, struct sockaddr *sa)
210
213
  return 0;
211
214
  }
212
215
 
216
+ /***********************
217
+ evma_get_subprocess_pid
218
+ ***********************/
219
+
220
+ extern "C" int evma_get_subprocess_pid (const char *binding, pid_t *pid)
221
+ {
222
+ if (!EventMachine)
223
+ throw std::runtime_error ("not initialized");
224
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
225
+ if (ed) {
226
+ return ed->GetSubprocessPid (pid) ? 1 : 0;
227
+ }
228
+ else
229
+ return 0;
230
+ }
231
+
213
232
 
214
233
  /*********************
215
234
  evma_signal_loopbreak
@@ -290,3 +309,53 @@ extern "C" void evma_setuid_string (const char *username)
290
309
  EventMachine_t::SetuidString (username);
291
310
  }
292
311
 
312
+
313
+ /**********
314
+ evma_popen
315
+ **********/
316
+
317
+ extern "C" const char *evma_popen (char * const*cmd_strings)
318
+ {
319
+ if (!EventMachine)
320
+ throw std::runtime_error ("not initialized");
321
+ return EventMachine->Socketpair (cmd_strings);
322
+ }
323
+
324
+
325
+ /***************************
326
+ evma_get_outbound_data_size
327
+ ***************************/
328
+
329
+ extern "C" int evma_get_outbound_data_size (const char *binding)
330
+ {
331
+ if (!EventMachine)
332
+ throw std::runtime_error ("not initialized");
333
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
334
+ return ed ? ed->GetOutboundDataSize() : 0;
335
+ }
336
+
337
+
338
+ /***********
339
+ evma__epoll
340
+ ***********/
341
+
342
+ extern "C" void evma__epoll()
343
+ {
344
+ bUseEpoll = 1;
345
+ }
346
+
347
+
348
+ /**********************
349
+ evma_set_rlimit_nofile
350
+ **********************/
351
+
352
+ extern "C" int evma_set_rlimit_nofile (int nofiles)
353
+ {
354
+ return EventMachine_t::SetRlimitNofile (nofiles);
355
+ }
356
+
357
+
358
+
359
+
360
+
361
+
data/ext/ed.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.cpp 318 2007-05-22 22:06:24Z blackhedd $
3
+ $Id: ed.cpp 400 2007-07-11 12:10:33Z blackhedd $
4
4
 
5
5
  File: ed.cpp
6
6
  Date: 06Apr06
@@ -43,13 +43,15 @@ bool SetSocketNonblocking (SOCKET sd)
43
43
  EventableDescriptor::EventableDescriptor
44
44
  ****************************************/
45
45
 
46
- EventableDescriptor::EventableDescriptor (int sd):
46
+ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
47
+ bCloseNow (false),
48
+ bCloseAfterWriting (false),
49
+ MySocket (sd),
47
50
  EventCallback (NULL),
48
51
  LastRead (0),
49
52
  LastWritten (0),
50
- MySocket (sd),
51
- bCloseNow (false),
52
- bCloseAfterWriting (false)
53
+ bCallbackUnbind (true),
54
+ MyEventMachine (em)
53
55
  {
54
56
  /* There are three ways to close a socket, all of which should
55
57
  * automatically signal to the event machine that this object
@@ -74,7 +76,13 @@ EventableDescriptor::EventableDescriptor (int sd):
74
76
 
75
77
  if (sd == INVALID_SOCKET)
76
78
  throw std::runtime_error ("bad eventable descriptor");
79
+ if (MyEventMachine == NULL)
80
+ throw std::runtime_error ("bad em in eventable descriptor");
77
81
  CreatedAt = gCurrentLoopTime;
82
+
83
+ #ifdef HAVE_EPOLL
84
+ EpollEvent.data.ptr = this;
85
+ #endif
78
86
  }
79
87
 
80
88
 
@@ -84,8 +92,8 @@ EventableDescriptor::~EventableDescriptor
84
92
 
85
93
  EventableDescriptor::~EventableDescriptor()
86
94
  {
87
- if (EventCallback)
88
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_UNBOUND, NULL, 0);
95
+ if (EventCallback && bCallbackUnbind)
96
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, 0);
89
97
  Close();
90
98
  }
91
99
 
@@ -140,6 +148,7 @@ EventableDescriptor::ScheduleClose
140
148
 
141
149
  void EventableDescriptor::ScheduleClose (bool after_writing)
142
150
  {
151
+ // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
143
152
  if (after_writing)
144
153
  bCloseAfterWriting = true;
145
154
  else
@@ -147,12 +156,23 @@ void EventableDescriptor::ScheduleClose (bool after_writing)
147
156
  }
148
157
 
149
158
 
159
+ /*************************************
160
+ EventableDescriptor::IsCloseScheduled
161
+ *************************************/
162
+
163
+ bool EventableDescriptor::IsCloseScheduled()
164
+ {
165
+ // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.
166
+ return (bCloseNow || bCloseAfterWriting);
167
+ }
168
+
169
+
150
170
  /******************************************
151
171
  ConnectionDescriptor::ConnectionDescriptor
152
172
  ******************************************/
153
173
 
154
- ConnectionDescriptor::ConnectionDescriptor (int sd):
155
- EventableDescriptor (sd),
174
+ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
175
+ EventableDescriptor (sd, em),
156
176
  bConnectPending (false),
157
177
  bReadAttemptedAfterClose (false),
158
178
  OutboundDataSize (0),
@@ -163,6 +183,9 @@ ConnectionDescriptor::ConnectionDescriptor (int sd):
163
183
  LastIo (gCurrentLoopTime),
164
184
  InactivityTimeout (0)
165
185
  {
186
+ #ifdef HAVE_EPOLL
187
+ EpollEvent.events = EPOLLOUT;
188
+ #endif
166
189
  }
167
190
 
168
191
 
@@ -190,12 +213,19 @@ STATIC: ConnectionDescriptor::SendDataToConnection
190
213
  int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length)
191
214
  {
192
215
  // TODO: This is something of a hack, or at least it's a static method of the wrong class.
216
+ // TODO: Poor polymorphism here. We should be calling one virtual method
217
+ // instead of hacking out the runtime information of the target object.
193
218
  ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
194
219
  if (cd)
195
220
  return cd->SendOutboundData (data, data_length);
196
221
  DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
197
222
  if (ds)
198
223
  return ds->SendOutboundData (data, data_length);
224
+ #ifdef OS_UNIX
225
+ PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
226
+ if (ps)
227
+ return ps->SendOutboundData (data, data_length);
228
+ #endif
199
229
  return -1;
200
230
  }
201
231
 
@@ -257,7 +287,8 @@ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
257
287
  // and not the whole process), and no coalescing of small pages.
258
288
  // (Well, not so bad, small pages are coalesced in ::Write)
259
289
 
260
- if (bCloseNow || bCloseAfterWriting)
290
+ if (IsCloseScheduled())
291
+ //if (bCloseNow || bCloseAfterWriting)
261
292
  return 0;
262
293
 
263
294
  if (!data && (length > 0))
@@ -269,6 +300,11 @@ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
269
300
  buffer [length] = 0;
270
301
  OutboundPages.push_back (OutboundPage (buffer, length));
271
302
  OutboundDataSize += length;
303
+ #ifdef HAVE_EPOLL
304
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
305
+ assert (MyEventMachine);
306
+ MyEventMachine->Modify (this);
307
+ #endif
272
308
  return length;
273
309
  }
274
310
 
@@ -399,7 +435,8 @@ void ConnectionDescriptor::Read()
399
435
  if (total_bytes_read == 0) {
400
436
  // If we read no data on a socket that selected readable,
401
437
  // it generally means the other end closed the connection gracefully.
402
- bCloseNow = true;
438
+ ScheduleClose (false);
439
+ //bCloseNow = true;
403
440
  }
404
441
 
405
442
  }
@@ -421,20 +458,20 @@ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
421
458
  while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
422
459
  B [s] = 0;
423
460
  if (EventCallback)
424
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, B, s);
461
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, B, s);
425
462
  }
426
463
  // INCOMPLETE, s may indicate an SSL error that would force the connection down.
427
464
  _DispatchCiphertext();
428
465
  }
429
466
  else {
430
467
  if (EventCallback)
431
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, buffer, size);
468
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size);
432
469
  }
433
470
  #endif
434
471
 
435
472
  #ifdef WITHOUT_SSL
436
473
  if (EventCallback)
437
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, buffer, size);
474
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size);
438
475
  #endif
439
476
  }
440
477
 
@@ -465,18 +502,23 @@ void ConnectionDescriptor::Write()
465
502
  socklen_t len;
466
503
  len = sizeof(error);
467
504
  #ifdef OS_UNIX
468
- int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, &error, &len);
505
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
469
506
  #endif
470
507
  #ifdef OS_WIN32
471
- int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
508
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
472
509
  #endif
473
510
  if ((o == 0) && (error == 0)) {
474
511
  if (EventCallback)
475
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_COMPLETED, "", 0);
512
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_COMPLETED, "", 0);
476
513
  bConnectPending = false;
514
+ #ifdef HAVE_EPOLL
515
+ // The callback may have scheduled outbound data.
516
+ EpollEvent.events = EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0);
517
+ #endif
477
518
  }
478
519
  else
479
- bCloseNow = true;
520
+ ScheduleClose (false);
521
+ //bCloseNow = true;
480
522
  }
481
523
  else {
482
524
  _WriteOutboundData();
@@ -540,6 +582,12 @@ void ConnectionDescriptor::_WriteOutboundData()
540
582
  buffer [len] = 0;
541
583
  OutboundPages.push_front (OutboundPage (buffer, len));
542
584
  }
585
+
586
+ #ifdef HAVE_EPOLL
587
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
588
+ assert (MyEventMachine);
589
+ MyEventMachine->Modify (this);
590
+ #endif
543
591
  }
544
592
  else {
545
593
  #ifdef OS_UNIX
@@ -653,30 +701,71 @@ void ConnectionDescriptor::Heartbeat()
653
701
 
654
702
  if (bConnectPending) {
655
703
  if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
656
- bCloseNow = true;
704
+ ScheduleClose (false);
705
+ //bCloseNow = true;
657
706
  }
658
707
  else {
659
708
  if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
660
- bCloseNow = true;
709
+ ScheduleClose (false);
710
+ //bCloseNow = true;
661
711
  }
662
712
  }
663
713
 
664
714
 
715
+ /****************************************
716
+ LoopbreakDescriptor::LoopbreakDescriptor
717
+ ****************************************/
718
+
719
+ LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em):
720
+ EventableDescriptor (sd, parent_em)
721
+ {
722
+ /* This is really bad and ugly. Change someday if possible.
723
+ * We have to know about an event-machine (probably the one that owns us),
724
+ * so we can pass newly-created connections to it.
725
+ */
726
+
727
+ bCallbackUnbind = false;
728
+
729
+ #ifdef HAVE_EPOLL
730
+ EpollEvent.events = EPOLLIN;
731
+ #endif
732
+ }
733
+
734
+
735
+
736
+
737
+ /*************************
738
+ LoopbreakDescriptor::Read
739
+ *************************/
740
+
741
+ void LoopbreakDescriptor::Read()
742
+ {
743
+ // TODO, refactor, this code is probably in the wrong place.
744
+ assert (MyEventMachine);
745
+ MyEventMachine->_ReadLoopBreaker();
746
+ }
747
+
748
+
749
+ /**************************
750
+ LoopbreakDescriptor::Write
751
+ **************************/
752
+
753
+ void LoopbreakDescriptor::Write()
754
+ {
755
+ // Why are we here?
756
+ throw std::runtime_error ("bad code path in loopbreak");
757
+ }
758
+
665
759
  /**************************************
666
760
  AcceptorDescriptor::AcceptorDescriptor
667
761
  **************************************/
668
762
 
669
- AcceptorDescriptor::AcceptorDescriptor (EventMachine_t *parent_em, int sd):
670
- EventableDescriptor (sd),
671
- MyEventMachine (parent_em)
763
+ AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em):
764
+ EventableDescriptor (sd, parent_em)
672
765
  {
673
- /* This is really bad and ugly. Change someday if possible.
674
- * We have to know about an event-machine (probably the one that owns us),
675
- * so we can pass newly-created connections to it.
676
- */
677
-
678
- if (!MyEventMachine)
679
- throw std::runtime_error ("bad event-machine passed to acceptor");
766
+ #ifdef HAVE_EPOLL
767
+ EpollEvent.events = EPOLLIN;
768
+ #endif
680
769
  }
681
770
 
682
771
 
@@ -739,13 +828,16 @@ void AcceptorDescriptor::Read()
739
828
  setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
740
829
 
741
830
 
742
- ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
831
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
743
832
  if (!cd)
744
833
  throw std::runtime_error ("no newly accepted connection");
745
834
  cd->SetServerMode();
746
835
  if (EventCallback) {
747
- (*EventCallback) (GetBinding().c_str(), EventMachine_t::CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
836
+ (*EventCallback) (GetBinding().c_str(), EM_CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
748
837
  }
838
+ #ifdef HAVE_EPOLL
839
+ cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
840
+ #endif
749
841
  assert (MyEventMachine);
750
842
  MyEventMachine->Add (cd);
751
843
  }
@@ -780,13 +872,17 @@ void AcceptorDescriptor::Heartbeat()
780
872
  DatagramDescriptor::DatagramDescriptor
781
873
  **************************************/
782
874
 
783
- DatagramDescriptor::DatagramDescriptor (int sd):
784
- EventableDescriptor (sd),
875
+ DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
876
+ EventableDescriptor (sd, parent_em),
785
877
  OutboundDataSize (0),
786
878
  LastIo (gCurrentLoopTime),
787
879
  InactivityTimeout (0)
788
880
  {
789
881
  memset (&ReturnAddress, 0, sizeof(ReturnAddress));
882
+
883
+ #ifdef HAVE_EPOLL
884
+ EpollEvent.events = EPOLLIN;
885
+ #endif
790
886
  }
791
887
 
792
888
 
@@ -810,8 +906,9 @@ void DatagramDescriptor::Heartbeat()
810
906
  {
811
907
  // Close it if its inactivity timer has expired.
812
908
 
813
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
814
- bCloseNow = true;
909
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
910
+ ScheduleClose (false);
911
+ //bCloseNow = true;
815
912
  }
816
913
 
817
914
 
@@ -869,7 +966,7 @@ void DatagramDescriptor::Read()
869
966
  memcpy (&ReturnAddress, &sin, slen);
870
967
 
871
968
  if (EventCallback)
872
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, readbuffer, r);
969
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);
873
970
 
874
971
  }
875
972
  else {
@@ -932,6 +1029,12 @@ void DatagramDescriptor::Write()
932
1029
  }
933
1030
  }
934
1031
  }
1032
+
1033
+ #ifdef HAVE_EPOLL
1034
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
1035
+ assert (MyEventMachine);
1036
+ MyEventMachine->Modify (this);
1037
+ #endif
935
1038
  }
936
1039
 
937
1040
 
@@ -954,7 +1057,8 @@ int DatagramDescriptor::SendOutboundData (const char *data, int length)
954
1057
  // This is an exact clone of ConnectionDescriptor::SendOutboundData.
955
1058
  // That means it needs to move to a common ancestor.
956
1059
 
957
- if (bCloseNow || bCloseAfterWriting)
1060
+ if (IsCloseScheduled())
1061
+ //if (bCloseNow || bCloseAfterWriting)
958
1062
  return 0;
959
1063
 
960
1064
  if (!data && (length > 0))
@@ -966,6 +1070,11 @@ int DatagramDescriptor::SendOutboundData (const char *data, int length)
966
1070
  buffer [length] = 0;
967
1071
  OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress));
968
1072
  OutboundDataSize += length;
1073
+ #ifdef HAVE_EPOLL
1074
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1075
+ assert (MyEventMachine);
1076
+ MyEventMachine->Modify (this);
1077
+ #endif
969
1078
  return length;
970
1079
  }
971
1080
 
@@ -980,7 +1089,8 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
980
1089
  // That means it needs to move to a common ancestor.
981
1090
  // TODO: Refactor this so there's no overlap with SendOutboundData.
982
1091
 
983
- if (bCloseNow || bCloseAfterWriting)
1092
+ if (IsCloseScheduled())
1093
+ //if (bCloseNow || bCloseAfterWriting)
984
1094
  return 0;
985
1095
 
986
1096
  if (!address || !*address || !port)
@@ -1014,6 +1124,11 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
1014
1124
  buffer [length] = 0;
1015
1125
  OutboundPages.push_back (OutboundPage (buffer, length, pin));
1016
1126
  OutboundDataSize += length;
1127
+ #ifdef HAVE_EPOLL
1128
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1129
+ assert (MyEventMachine);
1130
+ MyEventMachine->Modify (this);
1131
+ #endif
1017
1132
  return length;
1018
1133
  }
1019
1134
 
@@ -1055,14 +1170,14 @@ ConnectionDescriptor::GetCommInactivityTimeout
1055
1170
 
1056
1171
  int ConnectionDescriptor::GetCommInactivityTimeout (int *value)
1057
1172
  {
1058
- if (value) {
1059
- *value = InactivityTimeout;
1060
- return 1;
1061
- }
1062
- else {
1063
- // TODO, extended logging, got bad parameter.
1064
- return 0;
1065
- }
1173
+ if (value) {
1174
+ *value = InactivityTimeout;
1175
+ return 1;
1176
+ }
1177
+ else {
1178
+ // TODO, extended logging, got bad parameter.
1179
+ return 0;
1180
+ }
1066
1181
  }
1067
1182
 
1068
1183
 
@@ -1072,25 +1187,25 @@ ConnectionDescriptor::SetCommInactivityTimeout
1072
1187
 
1073
1188
  int ConnectionDescriptor::SetCommInactivityTimeout (int *value)
1074
1189
  {
1075
- int out = 0;
1076
-
1077
- if (value) {
1078
- if ((*value==0) || (*value >= 2)) {
1079
- // Replace the value and send the old one back to the caller.
1080
- int v = *value;
1081
- *value = InactivityTimeout;
1082
- InactivityTimeout = v;
1083
- out = 1;
1084
- }
1085
- else {
1086
- // TODO, extended logging, got bad value.
1087
- }
1088
- }
1089
- else {
1090
- // TODO, extended logging, got bad parameter.
1091
- }
1190
+ int out = 0;
1191
+
1192
+ if (value) {
1193
+ if ((*value==0) || (*value >= 2)) {
1194
+ // Replace the value and send the old one back to the caller.
1195
+ int v = *value;
1196
+ *value = InactivityTimeout;
1197
+ InactivityTimeout = v;
1198
+ out = 1;
1199
+ }
1200
+ else {
1201
+ // TODO, extended logging, got bad value.
1202
+ }
1203
+ }
1204
+ else {
1205
+ // TODO, extended logging, got bad parameter.
1206
+ }
1092
1207
 
1093
- return out;
1208
+ return out;
1094
1209
  }
1095
1210
 
1096
1211
  /*******************************