eventmachine 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -6
- data/CHANGELOG.md +20 -1
- data/README.md +3 -3
- data/eventmachine.gemspec +1 -0
- data/ext/binder.cpp +1 -1
- data/ext/cmain.cpp +11 -0
- data/ext/ed.cpp +17 -5
- data/ext/ed.h +5 -5
- data/ext/em.cpp +50 -31
- data/ext/em.h +11 -1
- data/ext/eventmachine.h +1 -0
- data/ext/extconf.rb +5 -3
- data/ext/fastfilereader/extconf.rb +1 -1
- data/ext/project.h +6 -1
- data/ext/rubymain.cpp +21 -0
- data/lib/em/iterator.rb +5 -44
- data/lib/em/protocols/smtpserver.rb +6 -2
- data/lib/em/resolver.rb +18 -1
- data/lib/em/tick_loop.rb +19 -19
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +11 -2
- data/rakelib/package.rake +7 -2
- data/tests/test_attach.rb +24 -0
- data/tests/test_connection_count.rb +21 -1
- data/tests/test_epoll.rb +15 -0
- data/tests/test_idle_connection.rb +6 -4
- data/tests/test_iterator.rb +97 -0
- data/tests/test_pause.rb +24 -0
- metadata +77 -79
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 1.0.
|
3
|
+
## 1.0.4 (December 19, 2014)
|
4
|
+
* add starttls_options to smtp server [#552]
|
5
|
+
* fix closesocket on windows [#497]
|
6
|
+
* fix build on ruby 2.2 [#503]
|
7
|
+
* fix build error on ruby 1.9 [#508]
|
8
|
+
* fix timer leak during dns resolution [#489]
|
9
|
+
* add concurrency validation to EM::Iterator [#468]
|
10
|
+
* add get_file_descriptor to get fd for a signature [#467]
|
11
|
+
* add EM.attach_server and EM.attach_socket_server [#465, #466]
|
12
|
+
* calling pause from receive_data takes effect immediately [#464]
|
13
|
+
* reactor_running? returns false after fork [#455]
|
14
|
+
* fix infinite loop on double close [edc4d0e6, #441, #445]
|
15
|
+
* fix compilation issue on llvm [#433]
|
16
|
+
* fix socket error codes on win32 [ff811a81]
|
17
|
+
* fix EM.stop latency when timers exist [8b613d05, #426]
|
18
|
+
* fix infinite loop when system time changes [1427a2c80, #428]
|
19
|
+
* fix crash when callin attach/detach in the same tick [#427]
|
20
|
+
* fix compilation issue on solaris [#416]
|
21
|
+
|
22
|
+
## 1.0.3 (March 8, 2013)
|
4
23
|
* EM.system was broken in 1.0.2 release [#413]
|
5
24
|
|
6
25
|
## 1.0.2 (March 8, 2013)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# About EventMachine
|
1
|
+
# About EventMachine [![Code Climate](https://codeclimate.com/github/eventmachine/eventmachine.png)](https://codeclimate.com/github/eventmachine/eventmachine)
|
2
2
|
|
3
3
|
|
4
4
|
## What is EventMachine ##
|
@@ -75,7 +75,7 @@ Here's a fully-functional echo server written with EventMachine:
|
|
75
75
|
|
76
76
|
def unbind
|
77
77
|
puts "-- someone disconnected from the echo server!"
|
78
|
-
|
78
|
+
end
|
79
79
|
end
|
80
80
|
|
81
81
|
# Note that this will block current thread.
|
@@ -86,7 +86,7 @@ Here's a fully-functional echo server written with EventMachine:
|
|
86
86
|
|
87
87
|
## EventMachine documentation ##
|
88
88
|
|
89
|
-
Currently we only have [reference documentation](http://eventmachine
|
89
|
+
Currently we only have [reference documentation](http://rdoc.info/github/eventmachine/eventmachine/frames) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
|
90
90
|
|
91
91
|
|
92
92
|
## Community and where to get help ##
|
data/eventmachine.gemspec
CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.version = EventMachine::VERSION
|
9
9
|
s.homepage = 'http://rubyeventmachine.com'
|
10
10
|
s.rubyforge_project = 'eventmachine'
|
11
|
+
s.licenses = ["Ruby", "GPL"]
|
11
12
|
|
12
13
|
s.authors = ["Francis Cianfrocca", "Aman Gupta"]
|
13
14
|
s.email = ["garbagecat10@gmail.com", "aman@tmm1.net"]
|
data/ext/binder.cpp
CHANGED
data/ext/cmain.cpp
CHANGED
@@ -259,6 +259,7 @@ evma_num_close_scheduled
|
|
259
259
|
|
260
260
|
extern "C" int evma_num_close_scheduled ()
|
261
261
|
{
|
262
|
+
ensure_eventmachine("evma_num_close_scheduled");
|
262
263
|
return EventMachine->NumCloseScheduled;
|
263
264
|
}
|
264
265
|
|
@@ -282,6 +283,16 @@ extern "C" const unsigned long evma_create_unix_domain_server (const char *filen
|
|
282
283
|
return EventMachine->CreateUnixDomainServer (filename);
|
283
284
|
}
|
284
285
|
|
286
|
+
/***********************
|
287
|
+
evma_attach_sd
|
288
|
+
************************/
|
289
|
+
|
290
|
+
extern "C" const unsigned long evma_attach_sd (int sd)
|
291
|
+
{
|
292
|
+
ensure_eventmachine("evma_attach_sd");
|
293
|
+
return EventMachine->AttachSD (sd);
|
294
|
+
}
|
295
|
+
|
285
296
|
/*************************
|
286
297
|
evma_open_datagram_socket
|
287
298
|
*************************/
|
data/ext/ed.cpp
CHANGED
@@ -217,6 +217,8 @@ EventableDescriptor::ScheduleClose
|
|
217
217
|
|
218
218
|
void EventableDescriptor::ScheduleClose (bool after_writing)
|
219
219
|
{
|
220
|
+
if (IsCloseScheduled())
|
221
|
+
return;
|
220
222
|
MyEventMachine->NumCloseScheduled++;
|
221
223
|
// KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
|
222
224
|
if (after_writing)
|
@@ -765,7 +767,11 @@ void ConnectionDescriptor::Read()
|
|
765
767
|
|
766
768
|
|
767
769
|
int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
|
770
|
+
#ifdef OS_WIN32
|
771
|
+
int e = WSAGetLastError();
|
772
|
+
#else
|
768
773
|
int e = errno;
|
774
|
+
#endif
|
769
775
|
//cerr << "<R:" << r << ">";
|
770
776
|
|
771
777
|
if (r > 0) {
|
@@ -779,6 +785,8 @@ void ConnectionDescriptor::Read()
|
|
779
785
|
// a security guard against buffer overflows.
|
780
786
|
readbuffer [r] = 0;
|
781
787
|
_DispatchInboundData (readbuffer, r);
|
788
|
+
if (bPaused)
|
789
|
+
break;
|
782
790
|
}
|
783
791
|
else if (r == 0) {
|
784
792
|
break;
|
@@ -981,11 +989,7 @@ void ConnectionDescriptor::_WriteOutboundData()
|
|
981
989
|
// Max of 16 outbound pages at a time
|
982
990
|
if (iovcnt > 16) iovcnt = 16;
|
983
991
|
|
984
|
-
|
985
|
-
struct iovec iov[16];
|
986
|
-
#else
|
987
|
-
struct iovec iov[ iovcnt ];
|
988
|
-
#endif
|
992
|
+
iovec iov[16];
|
989
993
|
|
990
994
|
for(int i = 0; i < iovcnt; i++){
|
991
995
|
OutboundPage *op = &(OutboundPages[i]);
|
@@ -1032,7 +1036,11 @@ void ConnectionDescriptor::_WriteOutboundData()
|
|
1032
1036
|
#endif
|
1033
1037
|
|
1034
1038
|
bool err = false;
|
1039
|
+
#ifdef OS_WIN32
|
1040
|
+
int e = WSAGetLastError();
|
1041
|
+
#else
|
1035
1042
|
int e = errno;
|
1043
|
+
#endif
|
1036
1044
|
if (bytes_written < 0) {
|
1037
1045
|
err = true;
|
1038
1046
|
bytes_written = 0;
|
@@ -1663,7 +1671,11 @@ void DatagramDescriptor::Write()
|
|
1663
1671
|
|
1664
1672
|
// The nasty cast to (char*) is needed because Windows is brain-dead.
|
1665
1673
|
int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
|
1674
|
+
#ifdef OS_WIN32
|
1675
|
+
int e = WSAGetLastError();
|
1676
|
+
#else
|
1666
1677
|
int e = errno;
|
1678
|
+
#endif
|
1667
1679
|
|
1668
1680
|
OutboundDataSize -= op->Length;
|
1669
1681
|
op->Free();
|
data/ext/ed.h
CHANGED
@@ -69,14 +69,14 @@ class EventableDescriptor: public Bindable_t
|
|
69
69
|
virtual bool GetSubprocessPid (pid_t*) {return false;}
|
70
70
|
|
71
71
|
virtual void StartTls() {}
|
72
|
-
virtual void SetTlsParms (const char
|
72
|
+
virtual void SetTlsParms (const char *, const char *, bool) {}
|
73
73
|
|
74
74
|
#ifdef WITH_SSL
|
75
75
|
virtual X509 *GetPeerCert() {return NULL;}
|
76
76
|
#endif
|
77
77
|
|
78
78
|
virtual uint64_t GetCommInactivityTimeout() {return 0;}
|
79
|
-
virtual int SetCommInactivityTimeout (uint64_t
|
79
|
+
virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
|
80
80
|
uint64_t GetPendingConnectTimeout();
|
81
81
|
int SetPendingConnectTimeout (uint64_t value);
|
82
82
|
uint64_t GetLastActivity() { return LastActivity; }
|
@@ -215,7 +215,7 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
215
215
|
protected:
|
216
216
|
struct OutboundPage {
|
217
217
|
OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
|
218
|
-
void Free() {if (Buffer) free ((
|
218
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
219
219
|
const char *Buffer;
|
220
220
|
int Length;
|
221
221
|
int Offset;
|
@@ -292,7 +292,7 @@ class DatagramDescriptor: public EventableDescriptor
|
|
292
292
|
protected:
|
293
293
|
struct OutboundPage {
|
294
294
|
OutboundPage (const char *b, int l, struct sockaddr_in f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
|
295
|
-
void Free() {if (Buffer) free ((
|
295
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
296
296
|
const char *Buffer;
|
297
297
|
int Length;
|
298
298
|
int Offset;
|
@@ -354,7 +354,7 @@ class PipeDescriptor: public EventableDescriptor
|
|
354
354
|
protected:
|
355
355
|
struct OutboundPage {
|
356
356
|
OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
|
357
|
-
void Free() {if (Buffer) free ((
|
357
|
+
void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
|
358
358
|
const char *Buffer;
|
359
359
|
int Length;
|
360
360
|
int Offset;
|
data/ext/em.cpp
CHANGED
@@ -382,15 +382,27 @@ EventMachine_t::_DispatchHeartbeats
|
|
382
382
|
|
383
383
|
void EventMachine_t::_DispatchHeartbeats()
|
384
384
|
{
|
385
|
+
// Store the first processed heartbeat descriptor and bail out if
|
386
|
+
// we see it again. This fixes an infinite loop in case the system time
|
387
|
+
// is changed out from underneath MyCurrentLoopTime.
|
388
|
+
const EventableDescriptor *head = NULL;
|
389
|
+
|
385
390
|
while (true) {
|
386
391
|
multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
|
387
392
|
if (i == Heartbeats.end())
|
388
393
|
break;
|
389
394
|
if (i->first > MyCurrentLoopTime)
|
390
395
|
break;
|
396
|
+
|
391
397
|
EventableDescriptor *ed = i->second;
|
398
|
+
if (ed == head)
|
399
|
+
break;
|
400
|
+
|
392
401
|
ed->Heartbeat();
|
393
402
|
QueueHeartbeat(ed);
|
403
|
+
|
404
|
+
if (head == NULL)
|
405
|
+
head = ed;
|
394
406
|
}
|
395
407
|
}
|
396
408
|
|
@@ -675,7 +687,7 @@ EventMachine_t::_TimeTilNextEvent
|
|
675
687
|
|
676
688
|
timeval EventMachine_t::_TimeTilNextEvent()
|
677
689
|
{
|
678
|
-
// 29jul11: Changed calculation base from MyCurrentLoopTime to the
|
690
|
+
// 29jul11: Changed calculation base from MyCurrentLoopTime to the
|
679
691
|
// real time. As MyCurrentLoopTime is set at the beginning of an
|
680
692
|
// iteration and this calculation is done at the end, evenmachine
|
681
693
|
// will potentially oversleep by the amount of time the iteration
|
@@ -697,10 +709,12 @@ timeval EventMachine_t::_TimeTilNextEvent()
|
|
697
709
|
if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
|
698
710
|
next_event = current_time;
|
699
711
|
}
|
700
|
-
|
712
|
+
|
701
713
|
timeval tv;
|
702
714
|
|
703
|
-
if (
|
715
|
+
if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
|
716
|
+
tv.tv_sec = tv.tv_usec = 0;
|
717
|
+
} else if (next_event == 0) {
|
704
718
|
tv = Quantum;
|
705
719
|
} else {
|
706
720
|
if (next_event > current_time) {
|
@@ -803,7 +817,7 @@ SelectData_t::SelectData_t()
|
|
803
817
|
_SelectDataSelect
|
804
818
|
*****************/
|
805
819
|
|
806
|
-
#
|
820
|
+
#if defined(HAVE_TBR) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
807
821
|
static VALUE _SelectDataSelect (void *v)
|
808
822
|
{
|
809
823
|
SelectData_t *sd = (SelectData_t*)v;
|
@@ -818,12 +832,13 @@ SelectData_t::_Select
|
|
818
832
|
|
819
833
|
int SelectData_t::_Select()
|
820
834
|
{
|
821
|
-
#
|
835
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
836
|
+
rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
|
837
|
+
return nSockets;
|
838
|
+
#elif defined(HAVE_TBR)
|
822
839
|
rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
|
823
840
|
return nSockets;
|
824
|
-
#
|
825
|
-
|
826
|
-
#ifndef HAVE_TBR
|
841
|
+
#else
|
827
842
|
return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
|
828
843
|
#endif
|
829
844
|
}
|
@@ -1399,6 +1414,14 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1399
1414
|
// Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
|
1400
1415
|
ModifiedDescriptors.erase (ed);
|
1401
1416
|
|
1417
|
+
// Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
|
1418
|
+
for (size_t i = 0; i < NewDescriptors.size(); i++) {
|
1419
|
+
if (ed == NewDescriptors[i]) {
|
1420
|
+
NewDescriptors.erase(NewDescriptors.begin() + i);
|
1421
|
+
break;
|
1422
|
+
}
|
1423
|
+
}
|
1424
|
+
|
1402
1425
|
// Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
|
1403
1426
|
// and also to prevent anyone from calling close() on the detached fd
|
1404
1427
|
ed->SetSocketInvalid();
|
@@ -1491,8 +1514,6 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1491
1514
|
if (!bind_here)
|
1492
1515
|
return 0;
|
1493
1516
|
|
1494
|
-
unsigned long output_binding = 0;
|
1495
|
-
|
1496
1517
|
//struct sockaddr_in sin;
|
1497
1518
|
|
1498
1519
|
int sd_accept = socket (family, SOCK_STREAM, 0);
|
@@ -1529,25 +1550,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1529
1550
|
goto fail;
|
1530
1551
|
}
|
1531
1552
|
|
1532
|
-
|
1533
|
-
// Set the acceptor non-blocking.
|
1534
|
-
// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
|
1535
|
-
if (!SetSocketNonblocking (sd_accept)) {
|
1536
|
-
//int val = fcntl (sd_accept, F_GETFL, 0);
|
1537
|
-
//if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
|
1538
|
-
goto fail;
|
1539
|
-
}
|
1540
|
-
}
|
1541
|
-
|
1542
|
-
{ // Looking good.
|
1543
|
-
AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
|
1544
|
-
if (!ad)
|
1545
|
-
throw std::runtime_error ("unable to allocate acceptor");
|
1546
|
-
Add (ad);
|
1547
|
-
output_binding = ad->GetBinding();
|
1548
|
-
}
|
1549
|
-
|
1550
|
-
return output_binding;
|
1553
|
+
return AttachSD(sd_accept);
|
1551
1554
|
|
1552
1555
|
fail:
|
1553
1556
|
if (sd_accept != INVALID_SOCKET)
|
@@ -1838,7 +1841,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1838
1841
|
|
1839
1842
|
// The whole rest of this function is only compiled on Unix systems.
|
1840
1843
|
#ifdef OS_UNIX
|
1841
|
-
unsigned long output_binding = 0;
|
1842
1844
|
|
1843
1845
|
struct sockaddr_un s_sun;
|
1844
1846
|
|
@@ -1876,6 +1878,24 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1876
1878
|
goto fail;
|
1877
1879
|
}
|
1878
1880
|
|
1881
|
+
return AttachSD(sd_accept);
|
1882
|
+
|
1883
|
+
fail:
|
1884
|
+
if (sd_accept != INVALID_SOCKET)
|
1885
|
+
close (sd_accept);
|
1886
|
+
return 0;
|
1887
|
+
#endif // OS_UNIX
|
1888
|
+
}
|
1889
|
+
|
1890
|
+
|
1891
|
+
/**************************************
|
1892
|
+
EventMachine_t::AttachSD
|
1893
|
+
**************************************/
|
1894
|
+
|
1895
|
+
const unsigned long EventMachine_t::AttachSD (int sd_accept)
|
1896
|
+
{
|
1897
|
+
unsigned long output_binding = 0;
|
1898
|
+
|
1879
1899
|
{
|
1880
1900
|
// Set the acceptor non-blocking.
|
1881
1901
|
// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
|
@@ -1900,7 +1920,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
|
|
1900
1920
|
if (sd_accept != INVALID_SOCKET)
|
1901
1921
|
close (sd_accept);
|
1902
1922
|
return 0;
|
1903
|
-
#endif // OS_UNIX
|
1904
1923
|
}
|
1905
1924
|
|
1906
1925
|
|
data/ext/em.h
CHANGED
@@ -22,7 +22,16 @@ See the file COPYING for complete licensing information.
|
|
22
22
|
|
23
23
|
#ifdef BUILD_FOR_RUBY
|
24
24
|
#include <ruby.h>
|
25
|
-
|
25
|
+
|
26
|
+
#ifdef HAVE_RB_THREAD_FD_SELECT
|
27
|
+
#define EmSelect rb_thread_fd_select
|
28
|
+
#else
|
29
|
+
#define EmSelect rb_thread_select
|
30
|
+
#endif
|
31
|
+
|
32
|
+
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
33
|
+
#include <ruby/thread.h>
|
34
|
+
#endif
|
26
35
|
|
27
36
|
#ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
|
28
37
|
#include <ruby/io.h>
|
@@ -88,6 +97,7 @@ class EventMachine_t
|
|
88
97
|
const unsigned long CreateTcpServer (const char *, int);
|
89
98
|
const unsigned long OpenDatagramSocket (const char *, int);
|
90
99
|
const unsigned long CreateUnixDomainServer (const char*);
|
100
|
+
const unsigned long AttachSD (int);
|
91
101
|
const unsigned long OpenKeyboard();
|
92
102
|
//const char *Popen (const char*, const char*);
|
93
103
|
const unsigned long Socketpair (char* const*);
|
data/ext/eventmachine.h
CHANGED
@@ -64,6 +64,7 @@ extern "C" {
|
|
64
64
|
void evma_stop_tcp_server (const unsigned long signature);
|
65
65
|
const unsigned long evma_create_tcp_server (const char *address, int port);
|
66
66
|
const unsigned long evma_create_unix_domain_server (const char *filename);
|
67
|
+
const unsigned long evma_attach_sd (int sd);
|
67
68
|
const unsigned long evma_open_datagram_socket (const char *server, int port);
|
68
69
|
const unsigned long evma_open_keyboard();
|
69
70
|
void evma_set_tls_parms (const unsigned long binding, const char *privatekey_filename, const char *certchain_filenane, int verify_peer);
|
data/ext/extconf.rb
CHANGED
@@ -40,7 +40,7 @@ def manual_ssl_config
|
|
40
40
|
end
|
41
41
|
|
42
42
|
if ENV['CROSS_COMPILING']
|
43
|
-
openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.
|
43
|
+
openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.1i")
|
44
44
|
openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/")
|
45
45
|
if File.exists?(openssl_dir)
|
46
46
|
FileUtils.mkdir_p Dir.pwd+"/openssl/"
|
@@ -67,9 +67,11 @@ end
|
|
67
67
|
add_define 'BUILD_FOR_RUBY'
|
68
68
|
add_define 'HAVE_RBTRAP' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
69
69
|
add_define "HAVE_TBR" if have_func('rb_thread_blocking_region')# and have_macro('RUBY_UBF_IO', 'ruby.h')
|
70
|
+
add_define "HAVE_RB_THREAD_CALL_WITHOUT_GVL" if have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
70
71
|
add_define "HAVE_INOTIFY" if inotify = have_func('inotify_init', 'sys/inotify.h')
|
71
72
|
add_define "HAVE_OLD_INOTIFY" if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h')
|
72
73
|
add_define 'HAVE_WRITEV' if have_func('writev', 'sys/uio.h')
|
74
|
+
add_define 'HAVE_RB_THREAD_FD_SELECT' if have_func('rb_thread_fd_select')
|
73
75
|
|
74
76
|
have_func('rb_wait_for_single_fd')
|
75
77
|
have_func('rb_enable_interrupt')
|
@@ -106,7 +108,7 @@ when /mswin32/, /mingw32/, /bccwin32/
|
|
106
108
|
check_libs(%w[kernel32 rpcrt4 gdi32], true)
|
107
109
|
|
108
110
|
if GNU_CHAIN
|
109
|
-
CONFIG['
|
111
|
+
CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
|
110
112
|
else
|
111
113
|
$defs.push "-EHs"
|
112
114
|
$defs.push "-GR"
|
@@ -170,7 +172,7 @@ TRY_LINK.sub!('$(CC)', '$(CXX)')
|
|
170
172
|
add_define 'HAVE_MAKE_PAIR' if try_link(<<SRC, '-lstdc++')
|
171
173
|
#include <utility>
|
172
174
|
using namespace std;
|
173
|
-
int main(){ pair<int,int> tuple = make_pair(1,2); }
|
175
|
+
int main(){ pair<const int,int> tuple = make_pair(1,2); }
|
174
176
|
SRC
|
175
177
|
TRY_LINK.sub!('$(CXX)', '$(CC)')
|
176
178
|
|
@@ -43,7 +43,7 @@ when /mswin32/, /mingw32/, /bccwin32/
|
|
43
43
|
check_libs(%w[kernel32 rpcrt4 gdi32], true)
|
44
44
|
|
45
45
|
if GNU_CHAIN
|
46
|
-
CONFIG['
|
46
|
+
CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
|
47
47
|
else
|
48
48
|
$defs.push "-EHs"
|
49
49
|
$defs.push "-GR"
|
data/ext/project.h
CHANGED
@@ -93,9 +93,14 @@ typedef int SOCKET;
|
|
93
93
|
#include <fcntl.h>
|
94
94
|
#include <assert.h>
|
95
95
|
|
96
|
+
#define close closesocket
|
97
|
+
|
96
98
|
typedef int socklen_t;
|
99
|
+
#ifndef _PID_T_
|
100
|
+
#define _PID_T_
|
97
101
|
typedef int pid_t;
|
98
|
-
#endif
|
102
|
+
#endif /* _PID_T_ */
|
103
|
+
#endif /* OS_WIN32 */
|
99
104
|
|
100
105
|
#if !defined(_MSC_VER) || _MSC_VER > 1500
|
101
106
|
#include <stdint.h>
|
data/ext/rubymain.cpp
CHANGED
@@ -273,6 +273,17 @@ static VALUE t_start_unix_server (VALUE self, VALUE filename)
|
|
273
273
|
return ULONG2NUM (f);
|
274
274
|
}
|
275
275
|
|
276
|
+
/********************
|
277
|
+
t_attach_sd
|
278
|
+
********************/
|
279
|
+
|
280
|
+
static VALUE t_attach_sd(VALUE self, VALUE sd)
|
281
|
+
{
|
282
|
+
const unsigned long f = evma_attach_sd(FIX2INT(sd));
|
283
|
+
if (!f)
|
284
|
+
rb_raise (rb_eRuntimeError, "%s", "no socket descriptor acceptor");
|
285
|
+
return ULONG2NUM (f);
|
286
|
+
}
|
276
287
|
|
277
288
|
|
278
289
|
/***********
|
@@ -566,6 +577,14 @@ static VALUE t_detach_fd (VALUE self, VALUE signature)
|
|
566
577
|
return INT2NUM(evma_detach_fd (NUM2ULONG (signature)));
|
567
578
|
}
|
568
579
|
|
580
|
+
/*********************
|
581
|
+
t_get_file_descriptor
|
582
|
+
*********************/
|
583
|
+
static VALUE t_get_file_descriptor (VALUE self, VALUE signature)
|
584
|
+
{
|
585
|
+
return INT2NUM(evma_get_file_descriptor (NUM2ULONG (signature)));
|
586
|
+
}
|
587
|
+
|
569
588
|
/**************
|
570
589
|
t_get_sock_opt
|
571
590
|
**************/
|
@@ -1204,6 +1223,7 @@ extern "C" void Init_rubyeventmachine()
|
|
1204
1223
|
rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2);
|
1205
1224
|
rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1);
|
1206
1225
|
rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
|
1226
|
+
rb_define_module_function (EmModule, "attach_sd", (VALUE(*)(...))t_attach_sd, 1);
|
1207
1227
|
rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 4);
|
1208
1228
|
rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
|
1209
1229
|
rb_define_module_function (EmModule, "get_peer_cert", (VALUE(*)(...))t_get_peer_cert, 1);
|
@@ -1217,6 +1237,7 @@ extern "C" void Init_rubyeventmachine()
|
|
1217
1237
|
|
1218
1238
|
rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2);
|
1219
1239
|
rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1);
|
1240
|
+
rb_define_module_function (EmModule, "get_file_descriptor", (VALUE (*)(...))t_get_file_descriptor, 1);
|
1220
1241
|
rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3);
|
1221
1242
|
rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4);
|
1222
1243
|
rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2);
|
data/lib/em/iterator.rb
CHANGED
@@ -50,6 +50,7 @@ module EventMachine
|
|
50
50
|
#
|
51
51
|
def initialize(list, concurrency = 1)
|
52
52
|
raise ArgumentError, 'argument must be an array' unless list.respond_to?(:to_a)
|
53
|
+
raise ArgumentError, 'concurrency must be bigger than zero' unless (concurrency > 0)
|
53
54
|
@list = list.to_a.dup
|
54
55
|
@concurrency = concurrency
|
55
56
|
|
@@ -224,47 +225,7 @@ module EventMachine
|
|
224
225
|
end
|
225
226
|
end
|
226
227
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
# TODO: real tests
|
232
|
-
# TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
|
233
|
-
# TODO: support iter.pause/resume/stop/break/continue?
|
234
|
-
# TODO: create some exceptions instead of using RuntimeError
|
235
|
-
# TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
|
236
|
-
|
237
|
-
EM.run{
|
238
|
-
EM::Iterator.new(1..50).each{ |num,iter| p num; iter.next }
|
239
|
-
EM::Iterator.new([1,2,3], 10).each{ |num,iter| p num; iter.next }
|
240
|
-
|
241
|
-
i = EM::Iterator.new(1..100, 5)
|
242
|
-
i.each(proc{|num,iter|
|
243
|
-
p num.to_s
|
244
|
-
iter.next
|
245
|
-
}, proc{
|
246
|
-
p :done
|
247
|
-
})
|
248
|
-
EM.add_timer(0.03){
|
249
|
-
i.concurrency = 1
|
250
|
-
}
|
251
|
-
EM.add_timer(0.04){
|
252
|
-
i.concurrency = 3
|
253
|
-
}
|
254
|
-
|
255
|
-
EM::Iterator.new(100..150).map(proc{ |num,iter|
|
256
|
-
EM.add_timer(0.01){ iter.return(num) }
|
257
|
-
}, proc{ |results|
|
258
|
-
p results
|
259
|
-
})
|
260
|
-
|
261
|
-
EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
|
262
|
-
EM.system(cmd){ |output,status|
|
263
|
-
hash[cmd] = status.exitstatus == 0 ? output.strip : nil
|
264
|
-
iter.return(hash)
|
265
|
-
}
|
266
|
-
}, proc{ |results|
|
267
|
-
p results
|
268
|
-
})
|
269
|
-
}
|
270
|
-
end
|
228
|
+
# TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
|
229
|
+
# TODO: support iter.pause/resume/stop/break/continue?
|
230
|
+
# TODO: create some exceptions instead of using RuntimeError
|
231
|
+
# TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
|
@@ -409,8 +409,12 @@ module EventMachine
|
|
409
409
|
#--
|
410
410
|
# STARTTLS may not be issued before EHLO, or unless the user has chosen
|
411
411
|
# to support it.
|
412
|
-
# TODO, must support user-supplied certificates.
|
413
412
|
#
|
413
|
+
# If :starttls_options is present and :starttls is set in the parms
|
414
|
+
# pass the options in :starttls_options to start_tls. Do this if you want to use
|
415
|
+
# your own certificate
|
416
|
+
# e.g. {:cert_chain_file => "/etc/ssl/cert.pem", :private_key_file => "/etc/ssl/private/cert.key"}
|
417
|
+
|
414
418
|
def process_starttls
|
415
419
|
if @@parms[:starttls]
|
416
420
|
if @state.include?(:starttls)
|
@@ -419,7 +423,7 @@ module EventMachine
|
|
419
423
|
send_data "503 EHLO required before STARTTLS\r\n"
|
420
424
|
else
|
421
425
|
send_data "220 Start TLS negotiation\r\n"
|
422
|
-
start_tls
|
426
|
+
start_tls(@@parms[:starttls_options] || {})
|
423
427
|
@state << :starttls
|
424
428
|
end
|
425
429
|
else
|
data/lib/em/resolver.rb
CHANGED
@@ -66,7 +66,15 @@ module EventMachine
|
|
66
66
|
|
67
67
|
def post_init
|
68
68
|
@requests = {}
|
69
|
-
|
69
|
+
end
|
70
|
+
|
71
|
+
def start_timer
|
72
|
+
@timer ||= EM.add_periodic_timer(0.1, &method(:tick))
|
73
|
+
end
|
74
|
+
|
75
|
+
def stop_timer
|
76
|
+
EM.cancel_timer(@timer)
|
77
|
+
@timer = nil
|
70
78
|
end
|
71
79
|
|
72
80
|
def unbind
|
@@ -84,6 +92,13 @@ module EventMachine
|
|
84
92
|
else
|
85
93
|
@requests[id] = req
|
86
94
|
end
|
95
|
+
|
96
|
+
start_timer
|
97
|
+
end
|
98
|
+
|
99
|
+
def deregister_request(id, req)
|
100
|
+
@requests.delete(id)
|
101
|
+
stop_timer if @requests.length == 0
|
87
102
|
end
|
88
103
|
|
89
104
|
def send_packet(pkt)
|
@@ -109,6 +124,7 @@ module EventMachine
|
|
109
124
|
req = @requests[msg.id]
|
110
125
|
if req
|
111
126
|
@requests.delete(msg.id)
|
127
|
+
stop_timer if @requests.length == 0
|
112
128
|
req.receive_answer(msg)
|
113
129
|
end
|
114
130
|
end
|
@@ -140,6 +156,7 @@ module EventMachine
|
|
140
156
|
if @tries < @max_tries
|
141
157
|
send
|
142
158
|
else
|
159
|
+
@socket.deregister_request(@id, self)
|
143
160
|
fail 'retries exceeded'
|
144
161
|
end
|
145
162
|
end
|
data/lib/em/tick_loop.rb
CHANGED
@@ -7,25 +7,25 @@ module EventMachine
|
|
7
7
|
# A TickLoop is useful when one needs to distribute amounts of work
|
8
8
|
# throughout ticks in order to maintain response times. It is also useful for
|
9
9
|
# simple repeated checks and metrics.
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
10
|
+
# @example
|
11
|
+
# # Here we run through an array one item per tick until it is empty,
|
12
|
+
# # printing each element.
|
13
|
+
# # When the array is empty, we return :stop from the callback, and the
|
14
|
+
# # loop will terminate.
|
15
|
+
# # When the loop terminates, the on_stop callbacks will be called.
|
16
|
+
# EM.run do
|
17
|
+
# array = (1..100).to_a
|
18
|
+
#
|
19
|
+
# tickloop = EM.tick_loop do
|
20
|
+
# if array.empty?
|
21
|
+
# :stop
|
22
|
+
# else
|
23
|
+
# puts array.shift
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# tickloop.on_stop { EM.stop }
|
28
|
+
# end
|
29
29
|
#
|
30
30
|
class TickLoop
|
31
31
|
|
data/lib/em/version.rb
CHANGED
data/lib/eventmachine.rb
CHANGED
@@ -156,7 +156,7 @@ module EventMachine
|
|
156
156
|
# will start without release_machine being called and will immediately throw
|
157
157
|
|
158
158
|
#
|
159
|
-
if reactor_running
|
159
|
+
if @reactor_running and @reactor_pid != Process.pid
|
160
160
|
# Reactor was started in a different parent, meaning we have forked.
|
161
161
|
# Clean up reactor state so a new reactor boots up in this child.
|
162
162
|
stop_event_loop
|
@@ -531,6 +531,15 @@ module EventMachine
|
|
531
531
|
s
|
532
532
|
end
|
533
533
|
|
534
|
+
# Attach to an existing socket's file descriptor. The socket may have been
|
535
|
+
# started with {EventMachine.start_server}.
|
536
|
+
def self.attach_server sock, handler=nil, *args, &block
|
537
|
+
klass = klass_from_handler(Connection, handler, *args)
|
538
|
+
sd = sock.respond_to?(:fileno) ? sock.fileno : sock
|
539
|
+
s = attach_sd(sd)
|
540
|
+
@acceptors[s] = [klass,args,block,sock]
|
541
|
+
s
|
542
|
+
end
|
534
543
|
|
535
544
|
# Stop a TCP server socket that was started with {EventMachine.start_server}.
|
536
545
|
# @see EventMachine.start_server
|
@@ -1181,7 +1190,7 @@ module EventMachine
|
|
1181
1190
|
#
|
1182
1191
|
# @return [Boolean] true if the EventMachine reactor loop is currently running
|
1183
1192
|
def self.reactor_running?
|
1184
|
-
|
1193
|
+
@reactor_running && Process.pid == @reactor_pid
|
1185
1194
|
end
|
1186
1195
|
|
1187
1196
|
|
data/rakelib/package.rake
CHANGED
@@ -31,8 +31,13 @@ else
|
|
31
31
|
def hack_cross_compilation(ext)
|
32
32
|
# inject 1.8/1.9 pure-ruby entry point
|
33
33
|
# HACK: add these dependencies to the task instead of using cross_compiling
|
34
|
-
ext.cross_platform.
|
35
|
-
|
34
|
+
if ext.cross_platform.is_a?(Array)
|
35
|
+
ext.cross_platform.each do |platform|
|
36
|
+
task = "native:#{GEMSPEC.name}:#{platform}"
|
37
|
+
if Rake::Task.task_defined?(task)
|
38
|
+
Rake::Task[task].prerequisites.unshift "lib/#{ext.name}.rb"
|
39
|
+
end
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
data/tests/test_attach.rb
CHANGED
@@ -4,6 +4,7 @@ require 'socket'
|
|
4
4
|
class TestAttach < Test::Unit::TestCase
|
5
5
|
class EchoServer < EM::Connection
|
6
6
|
def receive_data data
|
7
|
+
$received_data << data
|
7
8
|
send_data data
|
8
9
|
end
|
9
10
|
end
|
@@ -31,12 +32,14 @@ class TestAttach < Test::Unit::TestCase
|
|
31
32
|
def setup
|
32
33
|
@port = next_port
|
33
34
|
$read, $r, $w, $fd = nil
|
35
|
+
$received_data = ""
|
34
36
|
end
|
35
37
|
|
36
38
|
def teardown
|
37
39
|
[$r, $w].each do |io|
|
38
40
|
io.close rescue nil
|
39
41
|
end
|
42
|
+
$received_data = nil
|
40
43
|
end
|
41
44
|
|
42
45
|
def test_attach
|
@@ -63,6 +66,27 @@ class TestAttach < Test::Unit::TestCase
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
69
|
+
def test_attach_server
|
70
|
+
$before = TCPServer.new("127.0.0.1", @port)
|
71
|
+
sig = nil
|
72
|
+
EM.run {
|
73
|
+
sig = EM.attach_server $before, EchoServer
|
74
|
+
|
75
|
+
handler = Class.new(EM::Connection) do
|
76
|
+
def initialize
|
77
|
+
send_data "hello world"
|
78
|
+
close_connection_after_writing
|
79
|
+
EM.add_timer(0.1) { EM.stop }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
EM.connect("127.0.0.1", @port, handler)
|
83
|
+
}
|
84
|
+
|
85
|
+
assert_equal false, $before.closed?
|
86
|
+
assert_equal "hello world", $received_data
|
87
|
+
assert sig.is_a?(Integer)
|
88
|
+
end
|
89
|
+
|
66
90
|
def test_attach_pipe
|
67
91
|
EM.run{
|
68
92
|
$r, $w = IO.pipe
|
@@ -30,4 +30,24 @@ class TestConnectionCount < Test::Unit::TestCase
|
|
30
30
|
assert_equal(1, $server_conns)
|
31
31
|
assert_equal(4, $client_conns + $server_conns)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
|
+
module DoubleCloseClient
|
35
|
+
def unbind
|
36
|
+
close_connection
|
37
|
+
$num_close_scheduled_1 = EM.num_close_scheduled
|
38
|
+
EM.next_tick do
|
39
|
+
$num_close_scheduled_2 = EM.num_close_scheduled
|
40
|
+
EM.stop
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_num_close_scheduled
|
46
|
+
EM.run {
|
47
|
+
assert_equal(0, EM.num_close_scheduled)
|
48
|
+
EM.connect("127.0.0.1", 9999, DoubleCloseClient) # nothing listening on 9999
|
49
|
+
}
|
50
|
+
assert_equal(1, $num_close_scheduled_1)
|
51
|
+
assert_equal(0, $num_close_scheduled_2)
|
52
|
+
end
|
53
|
+
end
|
data/tests/test_epoll.rb
CHANGED
@@ -126,5 +126,20 @@ class TestEpoll < Test::Unit::TestCase
|
|
126
126
|
File.unlink(fn) if File.exist?(fn)
|
127
127
|
end
|
128
128
|
|
129
|
+
def test_attach_detach
|
130
|
+
EM.epoll
|
131
|
+
EM.run {
|
132
|
+
EM.add_timer(0.01) { EM.stop }
|
133
|
+
|
134
|
+
r, w = IO.pipe
|
135
|
+
|
136
|
+
# This tests a regression where detach in the same tick as attach crashes EM
|
137
|
+
EM.watch(r) do |connection|
|
138
|
+
connection.detach
|
139
|
+
end
|
140
|
+
}
|
141
|
+
|
142
|
+
assert true
|
143
|
+
end
|
129
144
|
end
|
130
145
|
|
@@ -9,15 +9,17 @@ class TestIdleConnection < Test::Unit::TestCase
|
|
9
9
|
$idle_time = conn.get_idle_time
|
10
10
|
conn.send_data "GET / HTTP/1.0\r\n\r\n"
|
11
11
|
EM.next_tick{
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
EM.next_tick{
|
13
|
+
$idle_time_after_send = conn.get_idle_time
|
14
|
+
conn.close_connection
|
15
|
+
EM.stop
|
16
|
+
}
|
15
17
|
}
|
16
18
|
}
|
17
19
|
}
|
18
20
|
|
19
21
|
assert_in_delta 3, $idle_time, 0.2
|
20
|
-
|
22
|
+
assert_in_delta 0, $idle_time_after_send, 0.1
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'em_test_helper'
|
2
|
+
|
3
|
+
class TestIterator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def get_time
|
6
|
+
EM.current_time.strftime('%H:%M:%S')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_default_concurrency
|
10
|
+
items = {}
|
11
|
+
list = 1..10
|
12
|
+
EM.run {
|
13
|
+
EM::Iterator.new(list).each( proc {|num,iter|
|
14
|
+
time = get_time
|
15
|
+
items[time] ||= []
|
16
|
+
items[time] << num
|
17
|
+
EM::Timer.new(1) {iter.next}
|
18
|
+
}, proc {EM.stop})
|
19
|
+
}
|
20
|
+
assert_equal(10, items.keys.size)
|
21
|
+
assert_equal((list).to_a, items.values.flatten)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_concurrency_bigger_than_list_size
|
25
|
+
items = {}
|
26
|
+
list = [1,2,3]
|
27
|
+
EM.run {
|
28
|
+
EM::Iterator.new(list,10).each(proc {|num,iter|
|
29
|
+
time = get_time
|
30
|
+
items[time] ||= []
|
31
|
+
items[time] << num
|
32
|
+
EM::Timer.new(1) {iter.next}
|
33
|
+
}, proc {EM.stop})
|
34
|
+
}
|
35
|
+
assert_equal(1, items.keys.size)
|
36
|
+
assert_equal((list).to_a, items.values.flatten)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def test_changing_concurrency_affects_active_iteration
|
41
|
+
items = {}
|
42
|
+
list = 1..25
|
43
|
+
EM.run {
|
44
|
+
i = EM::Iterator.new(list,5)
|
45
|
+
i.each(proc {|num,iter|
|
46
|
+
time = get_time
|
47
|
+
items[time] ||= []
|
48
|
+
items[time] << num
|
49
|
+
EM::Timer.new(1) {iter.next}
|
50
|
+
}, proc {EM.stop})
|
51
|
+
EM.add_timer(1){
|
52
|
+
i.concurrency = 1
|
53
|
+
}
|
54
|
+
EM.add_timer(3){
|
55
|
+
i.concurrency = 3
|
56
|
+
}
|
57
|
+
}
|
58
|
+
assert_equal(9, items.keys.size)
|
59
|
+
assert_equal((list).to_a, items.values.flatten)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_map
|
63
|
+
list = 100..150
|
64
|
+
EM.run {
|
65
|
+
EM::Iterator.new(list).map(proc{ |num,iter|
|
66
|
+
EM.add_timer(0.01){ iter.return(num) }
|
67
|
+
}, proc{ |results|
|
68
|
+
assert_equal((list).to_a.size, results.size)
|
69
|
+
EM.stop
|
70
|
+
})
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_inject
|
75
|
+
list = %w[ pwd uptime uname date ]
|
76
|
+
EM.run {
|
77
|
+
EM::Iterator.new(list, 2).inject({}, proc{ |hash,cmd,iter|
|
78
|
+
EM.system(cmd){ |output,status|
|
79
|
+
hash[cmd] = status.exitstatus == 0 ? output.strip : nil
|
80
|
+
iter.return(hash)
|
81
|
+
}
|
82
|
+
}, proc{ |results|
|
83
|
+
assert_equal(results.keys, list)
|
84
|
+
EM.stop
|
85
|
+
})
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_concurrency_is_0
|
90
|
+
EM.run {
|
91
|
+
assert_raise ArgumentError do
|
92
|
+
EM::Iterator.new(1..5,0)
|
93
|
+
end
|
94
|
+
EM.stop
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
data/tests/test_pause.rb
CHANGED
@@ -67,6 +67,30 @@ class TestPause < Test::Unit::TestCase
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
|
+
|
71
|
+
def test_pause_in_receive_data
|
72
|
+
incoming = []
|
73
|
+
|
74
|
+
test_server = Module.new do
|
75
|
+
define_method(:receive_data) do |data|
|
76
|
+
incoming << data
|
77
|
+
pause
|
78
|
+
EM.add_timer(0.5){ close_connection }
|
79
|
+
end
|
80
|
+
define_method(:unbind) do
|
81
|
+
EM.stop
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
EM.run do
|
86
|
+
EM.start_server "127.0.0.1", @port, test_server
|
87
|
+
cli = EM.connect "127.0.0.1", @port
|
88
|
+
cli.send_data 'a'*(17*1024)
|
89
|
+
end
|
90
|
+
|
91
|
+
assert_equal 1, incoming.size
|
92
|
+
assert_equal 16*1024, incoming[0].bytesize
|
93
|
+
end
|
70
94
|
else
|
71
95
|
warn "EM.pause_connection not implemented, skipping tests in #{__FILE__}"
|
72
96
|
|
metadata
CHANGED
@@ -1,90 +1,93 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: eventmachine
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.4
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 3
|
10
|
-
version: 1.0.3
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Francis Cianfrocca
|
14
9
|
- Aman Gupta
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2014-12-19 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
22
16
|
name: rake-compiler
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
25
18
|
none: false
|
26
|
-
requirements:
|
19
|
+
requirements:
|
27
20
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 57
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
- 8
|
33
|
-
- 3
|
21
|
+
- !ruby/object:Gem::Version
|
34
22
|
version: 0.8.3
|
35
23
|
type: :development
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: yard
|
39
24
|
prerelease: false
|
40
|
-
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 0.8.3
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: yard
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
41
34
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
hash: 31
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
- 8
|
49
|
-
- 5
|
50
|
-
- 2
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
51
38
|
version: 0.8.5.2
|
52
39
|
type: :development
|
53
|
-
version_requirements: *id002
|
54
|
-
- !ruby/object:Gem::Dependency
|
55
|
-
name: bluecloth
|
56
40
|
prerelease: false
|
57
|
-
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.8.5.2
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bluecloth
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
58
50
|
none: false
|
59
|
-
requirements:
|
60
|
-
- -
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
segments:
|
64
|
-
- 0
|
65
|
-
version: "0"
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
66
55
|
type: :development
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
description: ! 'EventMachine implements a fast, single-threaded engine for arbitrary
|
64
|
+
network
|
65
|
+
|
66
|
+
communications. It''s extremely easy to use in Ruby. EventMachine wraps all
|
67
|
+
|
71
68
|
interactions with IP sockets, allowing programs to concentrate on the
|
69
|
+
|
72
70
|
implementation of network protocols. It can be used to create both network
|
71
|
+
|
73
72
|
servers and clients. To create a server or client, a Ruby program only needs
|
73
|
+
|
74
74
|
to specify the IP address and port, and provide a Module that implements the
|
75
|
+
|
75
76
|
communications protocol. Implementations of several standard network protocols
|
77
|
+
|
76
78
|
are provided with the package, primarily to serve as examples. The real goal
|
79
|
+
|
77
80
|
of EventMachine is to enable programs to easily interface with other programs
|
78
|
-
|
79
|
-
|
81
|
+
|
82
|
+
using TCP/IP, especially if custom protocols are required.'
|
83
|
+
email:
|
80
84
|
- garbagecat10@gmail.com
|
81
85
|
- aman@tmm1.net
|
82
86
|
executables: []
|
83
|
-
|
84
|
-
extensions:
|
87
|
+
extensions:
|
85
88
|
- ext/extconf.rb
|
86
89
|
- ext/fastfilereader/extconf.rb
|
87
|
-
extra_rdoc_files:
|
90
|
+
extra_rdoc_files:
|
88
91
|
- README.md
|
89
92
|
- docs/DocumentationGuidesIndex.md
|
90
93
|
- docs/GettingStarted.md
|
@@ -100,7 +103,7 @@ extra_rdoc_files:
|
|
100
103
|
- docs/old/SMTP
|
101
104
|
- docs/old/SPAWNED_PROCESSES
|
102
105
|
- docs/old/TODO
|
103
|
-
files:
|
106
|
+
files:
|
104
107
|
- .gitignore
|
105
108
|
- .travis.yml
|
106
109
|
- .yardopts
|
@@ -232,6 +235,7 @@ files:
|
|
232
235
|
- tests/test_httpclient2.rb
|
233
236
|
- tests/test_idle_connection.rb
|
234
237
|
- tests/test_inactivity_timeout.rb
|
238
|
+
- tests/test_iterator.rb
|
235
239
|
- tests/test_kb.rb
|
236
240
|
- tests/test_line_protocol.rb
|
237
241
|
- tests/test_ltp.rb
|
@@ -267,10 +271,11 @@ files:
|
|
267
271
|
- tests/test_ud.rb
|
268
272
|
- tests/test_unbind_reason.rb
|
269
273
|
homepage: http://rubyeventmachine.com
|
270
|
-
licenses:
|
271
|
-
|
274
|
+
licenses:
|
275
|
+
- Ruby
|
276
|
+
- GPL
|
272
277
|
post_install_message:
|
273
|
-
rdoc_options:
|
278
|
+
rdoc_options:
|
274
279
|
- --title
|
275
280
|
- EventMachine
|
276
281
|
- --main
|
@@ -279,32 +284,25 @@ rdoc_options:
|
|
279
284
|
- lib/em/version
|
280
285
|
- -x
|
281
286
|
- lib/jeventmachine
|
282
|
-
require_paths:
|
287
|
+
require_paths:
|
283
288
|
- lib
|
284
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
289
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
285
290
|
none: false
|
286
|
-
requirements:
|
287
|
-
- -
|
288
|
-
- !ruby/object:Gem::Version
|
289
|
-
|
290
|
-
|
291
|
-
- 0
|
292
|
-
version: "0"
|
293
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
291
|
+
requirements:
|
292
|
+
- - ! '>='
|
293
|
+
- !ruby/object:Gem::Version
|
294
|
+
version: '0'
|
295
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
294
296
|
none: false
|
295
|
-
requirements:
|
296
|
-
- -
|
297
|
-
- !ruby/object:Gem::Version
|
298
|
-
|
299
|
-
segments:
|
300
|
-
- 0
|
301
|
-
version: "0"
|
297
|
+
requirements:
|
298
|
+
- - ! '>='
|
299
|
+
- !ruby/object:Gem::Version
|
300
|
+
version: '0'
|
302
301
|
requirements: []
|
303
|
-
|
304
302
|
rubyforge_project: eventmachine
|
305
|
-
rubygems_version: 1.8.
|
303
|
+
rubygems_version: 1.8.23
|
306
304
|
signing_key:
|
307
305
|
specification_version: 3
|
308
306
|
summary: Ruby/EventMachine library
|
309
307
|
test_files: []
|
310
|
-
|
308
|
+
has_rdoc:
|