eventmachine 1.0.3 → 1.0.4
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/.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 [](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:
|