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.
- 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
|
|