eventmachine 0.12.0 → 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/cmain.cpp +27 -1
- data/ext/ed.cpp +17 -2
- data/ext/ed.h +9 -1
- data/ext/em.cpp +111 -2
- data/ext/em.h +4 -1
- data/ext/eventmachine.h +9 -2
- data/ext/rubymain.cpp +49 -1
- data/lib/eventmachine.rb +139 -15
- data/lib/eventmachine_version.rb +2 -2
- data/lib/jeventmachine.rb +30 -4
- data/lib/protocols/header_and_content.rb +8 -2
- data/lib/protocols/httpclient.rb +14 -3
- data/lib/protocols/linetext2.rb +20 -2
- data/lib/protocols/postgres.rb +261 -0
- data/lib/protocols/stomp.rb +4 -1
- data/tests/test_attach.rb +66 -0
- data/tests/test_basic.rb +38 -2
- data/tests/test_hc.rb +189 -141
- data/tests/test_httpclient.rb +22 -1
- data/tests/test_ltp2.rb +60 -1
- data/tests/test_next_tick.rb +45 -1
- data/tests/test_sasl.rb +2 -1
- data/tests/test_timers.rb +4 -2
- metadata +63 -61
data/ext/cmain.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: cmain.cpp
|
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
|
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
|
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
|
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
|
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
|
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
|
|
data/ext/eventmachine.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: eventmachine.h
|
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);
|
data/ext/rubymain.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: rubymain.cpp
|
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
|
|
data/lib/eventmachine.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: eventmachine.rb
|
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
|
-
@
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
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
|
|