eventmachine 0.12.0 → 0.12.2

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.
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: cmain.cpp 679 2008-01-19 01:40:06Z blackhedd $
3
+ $Id: cmain.cpp 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: cmain.cpp
6
6
  Date: 06Apr06
@@ -103,6 +103,32 @@ extern "C" const char *evma_connect_to_unix_server (const char *server)
103
103
  return EventMachine->ConnectToUnixServer (server);
104
104
  }
105
105
 
106
+ /**************
107
+ evma_attach_fd
108
+ **************/
109
+
110
+ extern "C" const char *evma_attach_fd (int file_descriptor, int notify_readable, int notify_writable)
111
+ {
112
+ if (!EventMachine)
113
+ throw std::runtime_error ("not initialized");
114
+ return EventMachine->AttachFD (file_descriptor, (notify_readable ? true : false), (notify_writable ? true : false));
115
+ }
116
+
117
+ /**************
118
+ evma_detach_fd
119
+ **************/
120
+
121
+ extern "C" int evma_detach_fd (const char *binding)
122
+ {
123
+ if (!EventMachine)
124
+ throw std::runtime_error ("not initialized");
125
+
126
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
127
+ if (ed)
128
+ return EventMachine->DetachFD (ed);
129
+ else
130
+ throw std::runtime_error ("invalid binding to detach");
131
+ }
106
132
 
107
133
  /**********************
108
134
  evma_create_tcp_server
data/ext/ed.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.cpp 687 2008-05-15 14:28:32Z francis $
3
+ $Id: ed.cpp 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: ed.cpp
6
6
  Date: 06Apr06
@@ -174,6 +174,8 @@ ConnectionDescriptor::ConnectionDescriptor
174
174
  ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
175
175
  EventableDescriptor (sd, em),
176
176
  bConnectPending (false),
177
+ bNotifyReadable (false),
178
+ bNotifyWritable (false),
177
179
  bReadAttemptedAfterClose (false),
178
180
  bWriteAttemptedAfterClose (false),
179
181
  OutboundDataSize (0),
@@ -368,7 +370,7 @@ bool ConnectionDescriptor::SelectForWrite()
368
370
  * have outgoing data to send.
369
371
  */
370
372
 
371
- if (bConnectPending)
373
+ if (bConnectPending || bNotifyWritable)
372
374
  return true;
373
375
  else {
374
376
  return (GetOutboundDataSize() > 0);
@@ -413,6 +415,12 @@ void ConnectionDescriptor::Read()
413
415
  return;
414
416
  }
415
417
 
418
+ if (bNotifyReadable) {
419
+ if (EventCallback)
420
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
421
+ return;
422
+ }
423
+
416
424
  LastIo = gCurrentLoopTime;
417
425
 
418
426
  int total_bytes_read = 0;
@@ -549,6 +557,13 @@ void ConnectionDescriptor::Write()
549
557
  //bCloseNow = true;
550
558
  }
551
559
  else {
560
+
561
+ if (bNotifyWritable) {
562
+ if (EventCallback)
563
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
564
+ return;
565
+ }
566
+
552
567
  _WriteOutboundData();
553
568
  }
554
569
  }
data/ext/ed.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.h 687 2008-05-15 14:28:32Z francis $
3
+ $Id: ed.h 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: ed.h
6
6
  Date: 06Apr06
@@ -40,6 +40,7 @@ class EventableDescriptor: public Bindable_t
40
40
  virtual ~EventableDescriptor();
41
41
 
42
42
  int GetSocket() {return MySocket;}
43
+ void SetSocketInvalid() { MySocket = INVALID_SOCKET; }
43
44
  void Close();
44
45
 
45
46
  virtual void Read() = 0;
@@ -140,6 +141,9 @@ class ConnectionDescriptor: public EventableDescriptor
140
141
 
141
142
  void SetConnectPending (bool f) { bConnectPending = f; }
142
143
 
144
+ void SetNotifyReadable (bool readable) { bNotifyReadable = readable; }
145
+ void SetNotifyWritable (bool writable) { bNotifyWritable = writable; }
146
+
143
147
  virtual void Read();
144
148
  virtual void Write();
145
149
  virtual void Heartbeat();
@@ -172,6 +176,10 @@ class ConnectionDescriptor: public EventableDescriptor
172
176
 
173
177
  protected:
174
178
  bool bConnectPending;
179
+
180
+ bool bNotifyReadable;
181
+ bool bNotifyWritable;
182
+
175
183
  bool bReadAttemptedAfterClose;
176
184
  bool bWriteAttemptedAfterClose;
177
185
 
data/ext/em.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.cpp 686 2008-05-14 21:21:10Z francis $
3
+ $Id: em.cpp 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: em.cpp
6
6
  Date: 06Apr06
@@ -635,12 +635,14 @@ SelectData_t::SelectData_t()
635
635
  _SelectDataSelect
636
636
  *****************/
637
637
 
638
+ #ifdef HAVE_TBR
638
639
  static VALUE _SelectDataSelect (void *v)
639
640
  {
640
641
  SelectData_t *sd = (SelectData_t*)v;
641
642
  sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), NULL, &(sd->tv));
642
643
  return Qnil;
643
644
  }
645
+ #endif
644
646
 
645
647
  /*********************
646
648
  SelectData_t::_Select
@@ -654,7 +656,7 @@ int SelectData_t::_Select()
654
656
  #endif
655
657
 
656
658
  #ifndef HAVE_TBR
657
- return rb_thread_select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
659
+ return EmSelect (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
658
660
  #endif
659
661
  }
660
662
 
@@ -1163,6 +1165,113 @@ const char *EventMachine_t::ConnectToUnixServer (const char *server)
1163
1165
  #endif
1164
1166
  }
1165
1167
 
1168
+ /************************
1169
+ EventMachine_t::AttachFD
1170
+ ************************/
1171
+
1172
+ const char *EventMachine_t::AttachFD (int fd, bool notify_readable, bool notify_writable)
1173
+ {
1174
+ #ifdef OS_UNIX
1175
+ if (fcntl(fd, F_GETFL, 0) < 0)
1176
+ throw std::runtime_error ("invalid file descriptor");
1177
+ #endif
1178
+
1179
+ #ifdef OS_WIN32
1180
+ // TODO: add better check for invalid file descriptors (see ioctlsocket or getsockopt)
1181
+ if (fd == INVALID_SOCKET)
1182
+ throw std::runtime_error ("invalid file descriptor");
1183
+ #endif
1184
+
1185
+ {// Check for duplicate descriptors
1186
+ for (size_t i = 0; i < Descriptors.size(); i++) {
1187
+ EventableDescriptor *ed = Descriptors[i];
1188
+ assert (ed);
1189
+ if (ed->GetSocket() == fd)
1190
+ throw std::runtime_error ("adding existing descriptor");
1191
+ }
1192
+
1193
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1194
+ EventableDescriptor *ed = NewDescriptors[i];
1195
+ assert (ed);
1196
+ if (ed->GetSocket() == fd)
1197
+ throw std::runtime_error ("adding existing new descriptor");
1198
+ }
1199
+ }
1200
+
1201
+ ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this);
1202
+ if (!cd)
1203
+ throw std::runtime_error ("no connection allocated");
1204
+
1205
+ cd->SetConnectPending (true);
1206
+ cd->SetNotifyReadable (notify_readable);
1207
+ cd->SetNotifyWritable (notify_writable);
1208
+
1209
+ Add (cd);
1210
+
1211
+ const char *out = NULL;
1212
+ out = cd->GetBinding().c_str();
1213
+ if (out == NULL)
1214
+ closesocket (fd);
1215
+ return out;
1216
+ }
1217
+
1218
+ /************************
1219
+ EventMachine_t::DetachFD
1220
+ ************************/
1221
+
1222
+ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1223
+ {
1224
+ if (!ed)
1225
+ throw std::runtime_error ("detaching bad descriptor");
1226
+
1227
+ #ifdef HAVE_EPOLL
1228
+ if (bEpoll) {
1229
+ if (ed->GetSocket() != INVALID_SOCKET) {
1230
+ assert (bEpoll); // wouldn't be in this method otherwise.
1231
+ assert (epfd != -1);
1232
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
1233
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
1234
+ if (e && (errno != ENOENT) && (errno != EBADF)) {
1235
+ char buf [200];
1236
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
1237
+ throw std::runtime_error (buf);
1238
+ }
1239
+ }
1240
+ }
1241
+ #endif
1242
+
1243
+ #ifdef HAVE_KQUEUE
1244
+ if (bKqueue) {
1245
+ struct kevent k;
1246
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_DELETE, 0, 0, ed);
1247
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1248
+ assert (t == 0);
1249
+ }
1250
+ #endif
1251
+
1252
+ { // remove descriptor from lists
1253
+ int i, j;
1254
+ int nSockets = Descriptors.size();
1255
+ for (i=0, j=0; i < nSockets; i++) {
1256
+ EventableDescriptor *ted = Descriptors[i];
1257
+ assert (ted);
1258
+ if (ted != ed)
1259
+ Descriptors [j++] = ted;
1260
+ }
1261
+ while ((size_t)j < Descriptors.size())
1262
+ Descriptors.pop_back();
1263
+
1264
+ ModifiedDescriptors.erase (ed);
1265
+ }
1266
+
1267
+ int fd = ed->GetSocket();
1268
+
1269
+ // We depend on ~EventableDescriptor not calling close() if the socket is invalid
1270
+ ed->SetSocketInvalid();
1271
+ delete ed;
1272
+
1273
+ return fd;
1274
+ }
1166
1275
 
1167
1276
  /************
1168
1277
  name2address
data/ext/em.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.h 668 2008-01-04 23:00:34Z blackhedd $
3
+ $Id: em.h 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: em.h
6
6
  Date: 06Apr06
@@ -69,6 +69,8 @@ class EventMachine_t
69
69
  const char *InstallOneshotTimer (int);
70
70
  const char *ConnectToServer (const char *, int);
71
71
  const char *ConnectToUnixServer (const char *);
72
+ const char *AttachFD (int, bool, bool);
73
+
72
74
  const char *CreateTcpServer (const char *, int);
73
75
  const char *OpenDatagramSocket (const char *, int);
74
76
  const char *CreateUnixDomainServer (const char*);
@@ -79,6 +81,7 @@ class EventMachine_t
79
81
 
80
82
  void Add (EventableDescriptor*);
81
83
  void Modify (EventableDescriptor*);
84
+ int DetachFD (EventableDescriptor*);
82
85
  void ArmKqueueWriter (EventableDescriptor*);
83
86
  void ArmKqueueReader (EventableDescriptor*);
84
87
 
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: eventmachine.h 679 2008-01-19 01:40:06Z blackhedd $
3
+ $Id: eventmachine.h 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: eventmachine.h
6
6
  Date: 15Apr06
@@ -30,7 +30,10 @@ extern "C" {
30
30
  EM_CONNECTION_UNBOUND = 102,
31
31
  EM_CONNECTION_ACCEPTED = 103,
32
32
  EM_CONNECTION_COMPLETED = 104,
33
- EM_LOOPBREAK_SIGNAL = 105
33
+ EM_LOOPBREAK_SIGNAL = 105,
34
+ EM_CONNECTION_NOTIFY_READABLE = 106,
35
+ EM_CONNECTION_NOTIFY_WRITABLE = 107
36
+
34
37
  };
35
38
 
36
39
  void evma_initialize_library (void(*)(const char*, int, const char*, int));
@@ -39,6 +42,10 @@ extern "C" {
39
42
  const char *evma_install_oneshot_timer (int seconds);
40
43
  const char *evma_connect_to_server (const char *server, int port);
41
44
  const char *evma_connect_to_unix_server (const char *server);
45
+
46
+ const char *evma_attach_fd (int file_descriptor, int read_mode, int write_mode);
47
+ int evma_detach_fd (const char *binding);
48
+
42
49
  void evma_stop_tcp_server (const char *signature);
43
50
  const char *evma_create_tcp_server (const char *address, int port);
44
51
  const char *evma_create_unix_domain_server (const char *filename);
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: rubymain.cpp 679 2008-01-19 01:40:06Z blackhedd $
3
+ $Id: rubymain.cpp 785 2008-09-15 09:46:23Z francis $
4
4
 
5
5
  File: rubymain.cpp
6
6
  Date: 06Apr06
@@ -39,6 +39,8 @@ static VALUE Intern_delete;
39
39
  static VALUE Intern_call;
40
40
  static VALUE Intern_receive_data;
41
41
 
42
+ static VALUE Intern_notify_readable;
43
+ static VALUE Intern_notify_writable;
42
44
 
43
45
  /****************
44
46
  t_event_callback
@@ -53,6 +55,20 @@ static void event_callback (const char *a1, int a2, const char *a3, int a4)
53
55
  rb_raise (rb_eRuntimeError, "no connection");
54
56
  rb_funcall (q, Intern_receive_data, 1, rb_str_new (a3, a4));
55
57
  }
58
+ else if (a2 == EM_CONNECTION_NOTIFY_READABLE) {
59
+ VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
60
+ VALUE q = rb_hash_aref (t, rb_str_new2(a1));
61
+ if (q == Qnil)
62
+ rb_raise (rb_eRuntimeError, "no connection");
63
+ rb_funcall (q, Intern_notify_readable, 0);
64
+ }
65
+ else if (a2 == EM_CONNECTION_NOTIFY_WRITABLE) {
66
+ VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
67
+ VALUE q = rb_hash_aref (t, rb_str_new2(a1));
68
+ if (q == Qnil)
69
+ rb_raise (rb_eRuntimeError, "no connection");
70
+ rb_funcall (q, Intern_notify_writable, 0);
71
+ }
56
72
  else if (a2 == EM_LOOPBREAK_SIGNAL) {
57
73
  rb_funcall (EmModule, Intern_run_deferred_callbacks, 0);
58
74
  }
@@ -320,6 +336,27 @@ static VALUE t_connect_unix_server (VALUE self, VALUE serversocket)
320
336
  return rb_str_new2 (f);
321
337
  }
322
338
 
339
+ /***********
340
+ t_attach_fd
341
+ ***********/
342
+
343
+ static VALUE t_attach_fd (VALUE self, VALUE file_descriptor, VALUE read_mode, VALUE write_mode)
344
+ {
345
+ const char *f = evma_attach_fd (NUM2INT(file_descriptor), (read_mode == Qtrue) ? 1 : 0, (write_mode == Qtrue) ? 1 : 0);
346
+ if (!f || !*f)
347
+ rb_raise (rb_eRuntimeError, "no connection");
348
+ return rb_str_new2 (f);
349
+ }
350
+
351
+ /***********
352
+ t_detach_fd
353
+ ***********/
354
+
355
+ static VALUE t_detach_fd (VALUE self, VALUE signature)
356
+ {
357
+ return INT2NUM(evma_detach_fd (StringValuePtr(signature)));
358
+ }
359
+
323
360
  /*****************
324
361
  t_open_udp_socket
325
362
  *****************/
@@ -565,6 +602,9 @@ extern "C" void Init_rubyeventmachine()
565
602
  Intern_call = rb_intern ("call");
566
603
  Intern_receive_data = rb_intern ("receive_data");
567
604
 
605
+ Intern_notify_readable = rb_intern ("notify_readable");
606
+ Intern_notify_writable = rb_intern ("notify_writable");
607
+
568
608
  // INCOMPLETE, we need to define class Connections inside module EventMachine
569
609
  // run_machine and run_machine_without_threads are now identical.
570
610
  // Must deprecate the without_threads variant.
@@ -590,6 +630,10 @@ extern "C" void Init_rubyeventmachine()
590
630
  rb_define_module_function (EmModule, "report_connection_error_status", (VALUE(*)(...))t_report_connection_error_status, 1);
591
631
  rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2);
592
632
  rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1);
633
+
634
+ rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 3);
635
+ rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1);
636
+
593
637
  rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2);
594
638
  rb_define_module_function (EmModule, "read_keyboard", (VALUE(*)(...))t_read_keyboard, 0);
595
639
  rb_define_module_function (EmModule, "release_machine", (VALUE(*)(...))t_release_machine, 0);
@@ -626,5 +670,9 @@ extern "C" void Init_rubyeventmachine()
626
670
  rb_define_const (EmModule, "ConnectionAccepted", INT2NUM(103));
627
671
  rb_define_const (EmModule, "ConnectionCompleted", INT2NUM(104));
628
672
  rb_define_const (EmModule, "LoopbreakSignalled", INT2NUM(105));
673
+
674
+ rb_define_const (EmModule, "ConnectionNotifyReadable", INT2NUM(106));
675
+ rb_define_const (EmModule, "ConnectionNotifyWritable", INT2NUM(107));
676
+
629
677
  }
630
678
 
@@ -1,4 +1,4 @@
1
- # $Id: eventmachine.rb 688 2008-05-15 23:44:39Z francis $
1
+ # $Id: eventmachine.rb 785 2008-09-15 09:46:23Z francis $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -213,18 +213,32 @@ module EventMachine
213
213
  # will start without release_machine being called and will immediately throw
214
214
  # a C++ runtime error.
215
215
  #
216
- def EventMachine::run &block
217
- @conns = {}
218
- @acceptors = {}
219
- @timers = {}
220
- begin
221
- @reactor_running = true
222
- initialize_event_machine
223
- block and add_timer 0, block
224
- run_machine
225
- ensure
226
- release_machine
227
- @reactor_running = false
216
+ def EventMachine::run blk=nil, tail=nil, &block
217
+ @tails ||= []
218
+ tail and @tails.unshift(tail)
219
+
220
+ if reactor_running?
221
+ (b = blk || block) and b.call # next_tick(b)
222
+ else
223
+ @conns = {}
224
+ @acceptors = {}
225
+ @timers = {}
226
+ @wrapped_exception = nil
227
+ begin
228
+ @reactor_running = true
229
+ initialize_event_machine
230
+ (b = blk || block) and add_timer(0, b)
231
+ run_machine
232
+ ensure
233
+ release_machine
234
+ @reactor_running = false
235
+ end
236
+
237
+ until @tails.empty?
238
+ @tails.pop.call
239
+ end
240
+
241
+ raise @wrapped_exception if @wrapped_exception
228
242
  end
229
243
  end
230
244
 
@@ -242,6 +256,23 @@ module EventMachine
242
256
  run(&pr)
243
257
  end
244
258
 
259
+ # fork_reactor forks a new process and calls EM#run inside of it, passing your block.
260
+ #--
261
+ # This implementation is subject to change, especially if we clean up the relationship
262
+ # of EM#run to @reactor_running.
263
+ # Original patch by Aman Gupta.
264
+ #
265
+ def EventMachine::fork_reactor &block
266
+ Kernel.fork do
267
+ if self.reactor_running?
268
+ self.stop_event_loop
269
+ self.release_machine
270
+ self.instance_variable_set( '@reactor_running', false )
271
+ end
272
+ self.run block
273
+ end
274
+ end
275
+
245
276
 
246
277
  # +deprecated+
247
278
  #--
@@ -527,6 +558,7 @@ module EventMachine
527
558
 
528
559
  s = start_unix_server filename
529
560
  @acceptors[s] = [klass,args,block]
561
+ s
530
562
  end
531
563
 
532
564
  # EventMachine#connect initiates a TCP connection to a remote
@@ -646,6 +678,71 @@ module EventMachine
646
678
  c
647
679
  end
648
680
 
681
+ # EventMachine::attach registers a given file descriptor or IO object with the eventloop
682
+ #
683
+ # If the handler provided has the functions notify_readable or notify_writable defined,
684
+ # EventMachine will not read or write from the socket, and instead fire the corresponding
685
+ # callback on the handler.
686
+ #
687
+ # To detach the file descriptor, use EventMachine::Connection#detach
688
+ #
689
+ # === Usage Example
690
+ #
691
+ # module SimpleHttpClient
692
+ # def initialize sock
693
+ # @sock = sock
694
+ # end
695
+ #
696
+ # def notify_readable
697
+ # header = @sock.readline
698
+ #
699
+ # if header == "\r\n"
700
+ # # detach returns the file descriptor number (fd == @sock.fileno)
701
+ # fd = detach
702
+ # end
703
+ # rescue EOFError
704
+ # detach
705
+ # end
706
+ #
707
+ # def unbind
708
+ # EM.next_tick do
709
+ # # socket is detached from the eventloop, but still open
710
+ # data = @sock.read
711
+ # end
712
+ # end
713
+ # end
714
+ #
715
+ # EM.run{
716
+ # $sock = TCPSocket.new('site.com', 80)
717
+ # $sock.write("GET / HTTP/1.0\r\n\r\n")
718
+ # EM.attach $sock, SimpleHttpClient, $sock
719
+ # }
720
+ #
721
+ #--
722
+ # Thanks to Riham Aldakkak (eSpace Technologies) for the initial patch
723
+ def EventMachine::attach io, handler=nil, *args
724
+ klass = if (handler and handler.is_a?(Class))
725
+ handler
726
+ else
727
+ Class.new( Connection ) {handler and include handler}
728
+ end
729
+
730
+ arity = klass.instance_method(:initialize).arity
731
+ expected = arity >= 0 ? arity : -(arity + 1)
732
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
733
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
734
+ end
735
+
736
+ readmode = klass.public_instance_methods.any?{|m| m.to_sym == :notify_readable }
737
+ writemode = klass.public_instance_methods.any?{|m| m.to_sym == :notify_writable }
738
+
739
+ s = attach_fd io.respond_to?(:fileno) ? io.fileno : io, readmode, writemode
740
+
741
+ c = klass.new s, *args
742
+ @conns[s] = c
743
+ block_given? and yield c
744
+ c
745
+ end
649
746
 
650
747
  #--
651
748
  # EXPERIMENTAL. DO NOT RELY ON THIS METHOD TO BE HERE IN THIS FORM, OR AT ALL.
@@ -1057,12 +1154,26 @@ module EventMachine
1057
1154
  # No one was using it, and it degraded performance significantly.
1058
1155
  # It's in original_event_callback, which is dead code.
1059
1156
  #
1157
+ # Changed 25Jul08: Added a partial solution to the problem of exceptions
1158
+ # raised in user-written event-handlers. If such exceptions are not caught,
1159
+ # we must cause the reactor to stop, and then re-raise the exception.
1160
+ # Otherwise, the reactor doesn't stop and it's left on the call stack.
1161
+ # This is partial because we only added it to #unbind, where it's critical
1162
+ # (to keep unbind handlers from being re-entered when a stopping reactor
1163
+ # runs down open connections). It should go on the other calls to user
1164
+ # code, but the performance impact may be too large.
1165
+ #
1060
1166
  if opcode == ConnectionData
1061
1167
  c = @conns[conn_binding] or raise ConnectionNotBound
1062
1168
  c.receive_data data
1063
1169
  elsif opcode == ConnectionUnbound
1064
1170
  if c = @conns.delete( conn_binding )
1065
- c.unbind
1171
+ begin
1172
+ c.unbind
1173
+ rescue
1174
+ @wrapped_exception = $!
1175
+ stop
1176
+ end
1066
1177
  elsif c = @acceptors.delete( conn_binding )
1067
1178
  # no-op
1068
1179
  else
@@ -1083,6 +1194,12 @@ module EventMachine
1083
1194
  c.connection_completed
1084
1195
  elsif opcode == LoopbreakSignalled
1085
1196
  run_deferred_callbacks
1197
+ elsif opcode == ConnectionNotifyReadable
1198
+ c = @conns[conn_binding] or raise ConnectionNotBound
1199
+ c.notify_readable
1200
+ elsif opcode == ConnectionNotifyWritable
1201
+ c = @conns[conn_binding] or raise ConnectionNotBound
1202
+ c.notify_writable
1086
1203
  end
1087
1204
  end
1088
1205
 
@@ -1325,6 +1442,12 @@ class Connection
1325
1442
  EventMachine::close_connection @signature, after_writing
1326
1443
  end
1327
1444
 
1445
+ # EventMachine::Connection#detach will remove the given connection from the event loop.
1446
+ # The connection's socket remains open and its file descriptor number is returned
1447
+ def detach
1448
+ EventMachine::detach_fd @signature
1449
+ end
1450
+
1328
1451
  # EventMachine::Connection#close_connection_after_writing is a variant of close_connection.
1329
1452
  # All of the descriptive comments given for close_connection also apply to
1330
1453
  # close_connection_after_writing, <i>with one exception:</i> If the connection has
@@ -1609,13 +1732,14 @@ EM::P = EventMachine::Protocols
1609
1732
  require 'protocols/tcptest'
1610
1733
  require 'protocols/httpclient'
1611
1734
  require 'protocols/line_and_text'
1612
- require 'protocols/header_and_content'
1613
1735
  require 'protocols/linetext2'
1736
+ require 'protocols/header_and_content'
1614
1737
  require 'protocols/httpcli2'
1615
1738
  require 'protocols/stomp'
1616
1739
  require 'protocols/smtpclient'
1617
1740
  require 'protocols/smtpserver'
1618
1741
  require 'protocols/saslauth'
1742
+ #require 'protocols/postgres' UNCOMMENT THIS LINE WHEN THE POSTGRES CODE IS READY FOR PRIME TIME.
1619
1743
 
1620
1744
  require 'em/processes'
1621
1745