eventmachine 0.12.0 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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