eventmachine 1.0.0.beta.4-x86-mswin32-60 → 1.0.0.rc.1-x86-mswin32-60
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/Rakefile +11 -10
- data/eventmachine.gemspec +1 -1
- data/ext/cmain.cpp +38 -0
- data/ext/ed.cpp +18 -1
- data/ext/ed.h +5 -0
- data/ext/em.cpp +30 -7
- data/ext/em.h +3 -2
- data/ext/eventmachine.h +4 -0
- data/ext/extconf.rb +11 -2
- data/ext/fastfilereader/extconf.rb +10 -1
- data/ext/project.h +2 -1
- data/ext/rubymain.cpp +56 -6
- data/ext/ssl.cpp +4 -1
- data/java/src/com/rubyeventmachine/EmReactor.java +4 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +1 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +6 -0
- data/lib/em/connection.rb +11 -0
- data/lib/em/pool.rb +7 -2
- data/lib/em/protocols/smtpclient.rb +28 -28
- data/lib/em/threaded_resource.rb +1 -1
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +57 -11
- data/lib/jeventmachine.rb +5 -0
- data/{tasks → rakelib}/cpp.rake_example +0 -0
- data/{tasks → rakelib}/package.rake +0 -0
- data/{tasks → rakelib}/test.rake +0 -0
- data/tests/test_basic.rb +67 -0
- data/tests/test_idle_connection.rb +23 -0
- data/tests/test_pool.rb +67 -1
- data/tests/test_proxy_connection.rb +13 -1
- data/tests/test_unbind_reason.rb +19 -2
- metadata +9 -22
data/Rakefile
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
import *Dir['tasks/*.rake']
|
1
|
+
require 'rubygems'
|
2
|
+
GEMSPEC = Gem::Specification.load('eventmachine.gemspec')
|
4
3
|
|
5
|
-
GEMSPEC = eval(File.read(File.expand_path('../eventmachine.gemspec', __FILE__)))
|
6
|
-
|
7
|
-
require 'yard'
|
8
4
|
require 'rake/clean'
|
9
5
|
task :clobber => :clean
|
10
6
|
|
@@ -12,8 +8,13 @@ desc "Build eventmachine, then run tests."
|
|
12
8
|
task :default => [:compile, :test]
|
13
9
|
|
14
10
|
desc 'Generate documentation'
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
begin
|
12
|
+
require 'yard'
|
13
|
+
YARD::Rake::YardocTask.new do |t|
|
14
|
+
t.files = ['lib/**/*.rb', '-', 'docs/*.md']
|
15
|
+
t.options = ['--main', 'README.md', '--no-private']
|
16
|
+
t.options = ['--exclude', 'lib/jeventmachine', '--exclude', 'lib/pr_eventmachine']
|
17
|
+
end
|
18
|
+
rescue LoadError
|
19
|
+
task :yard do puts "Please install yard first!"; end
|
19
20
|
end
|
data/eventmachine.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
|
16
16
|
s.add_development_dependency 'rake-compiler', '0.7.9'
|
17
17
|
s.add_development_dependency 'yard', ">= 0.7.2"
|
18
|
-
s.add_development_dependency 'bluecloth'
|
18
|
+
#s.add_development_dependency 'bluecloth'
|
19
19
|
|
20
20
|
s.summary = 'Ruby/EventMachine library'
|
21
21
|
s.description = "EventMachine implements a fast, single-threaded engine for arbitrary network
|
data/ext/cmain.cpp
CHANGED
@@ -253,6 +253,15 @@ extern "C" int evma_is_paused (const unsigned long binding)
|
|
253
253
|
return 0;
|
254
254
|
}
|
255
255
|
|
256
|
+
/************************
|
257
|
+
evma_num_close_scheduled
|
258
|
+
************************/
|
259
|
+
|
260
|
+
extern "C" int evma_num_close_scheduled ()
|
261
|
+
{
|
262
|
+
return EventMachine->NumCloseScheduled;
|
263
|
+
}
|
264
|
+
|
256
265
|
/**********************
|
257
266
|
evma_create_tcp_server
|
258
267
|
**********************/
|
@@ -804,6 +813,35 @@ extern "C" void evma_stop_proxy (const unsigned long from)
|
|
804
813
|
ed->StopProxy();
|
805
814
|
}
|
806
815
|
|
816
|
+
/******************
|
817
|
+
evma_proxied_bytes
|
818
|
+
*******************/
|
819
|
+
|
820
|
+
extern "C" unsigned long evma_proxied_bytes (const unsigned long from)
|
821
|
+
{
|
822
|
+
ensure_eventmachine("evma_proxied_bytes");
|
823
|
+
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
|
824
|
+
if (ed)
|
825
|
+
return ed->GetProxiedBytes();
|
826
|
+
else
|
827
|
+
return 0;
|
828
|
+
}
|
829
|
+
|
830
|
+
|
831
|
+
/***************************
|
832
|
+
evma_get_last_activity_time
|
833
|
+
****************************/
|
834
|
+
|
835
|
+
extern "C" uint64_t evma_get_last_activity_time(const unsigned long from)
|
836
|
+
{
|
837
|
+
ensure_eventmachine("evma_get_last_activity_time");
|
838
|
+
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
|
839
|
+
if (ed)
|
840
|
+
return ed->GetLastActivity();
|
841
|
+
else
|
842
|
+
return 0;
|
843
|
+
}
|
844
|
+
|
807
845
|
|
808
846
|
/***************************
|
809
847
|
evma_get_heartbeat_interval
|
data/ext/ed.cpp
CHANGED
@@ -54,12 +54,14 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
|
|
54
54
|
bCloseNow (false),
|
55
55
|
bCloseAfterWriting (false),
|
56
56
|
MySocket (sd),
|
57
|
+
bAttached (false),
|
57
58
|
bWatchOnly (false),
|
58
59
|
EventCallback (NULL),
|
59
60
|
bCallbackUnbind (true),
|
60
61
|
UnbindReasonCode (0),
|
61
62
|
ProxyTarget(NULL),
|
62
63
|
ProxiedFrom(NULL),
|
64
|
+
ProxiedBytes(0),
|
63
65
|
MaxOutboundBufSize(0),
|
64
66
|
MyEventMachine (em),
|
65
67
|
PendingConnectTimeout(20000000),
|
@@ -115,6 +117,7 @@ EventableDescriptor::~EventableDescriptor()
|
|
115
117
|
(*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
|
116
118
|
ProxiedFrom->StopProxy();
|
117
119
|
}
|
120
|
+
MyEventMachine->NumCloseScheduled--;
|
118
121
|
StopProxy();
|
119
122
|
Close();
|
120
123
|
}
|
@@ -179,7 +182,7 @@ void EventableDescriptor::Close()
|
|
179
182
|
MyEventMachine->Deregister (this);
|
180
183
|
|
181
184
|
// Do not close STDIN, STDOUT, STDERR
|
182
|
-
if (MySocket > 2 && !
|
185
|
+
if (MySocket > 2 && !bAttached) {
|
183
186
|
shutdown (MySocket, 1);
|
184
187
|
close (MySocket);
|
185
188
|
}
|
@@ -214,6 +217,7 @@ EventableDescriptor::ScheduleClose
|
|
214
217
|
|
215
218
|
void EventableDescriptor::ScheduleClose (bool after_writing)
|
216
219
|
{
|
220
|
+
MyEventMachine->NumCloseScheduled++;
|
217
221
|
// KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
|
218
222
|
if (after_writing)
|
219
223
|
bCloseAfterWriting = true;
|
@@ -244,6 +248,7 @@ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long
|
|
244
248
|
StopProxy();
|
245
249
|
ProxyTarget = ed;
|
246
250
|
BytesToProxy = length;
|
251
|
+
ProxiedBytes = 0;
|
247
252
|
ed->SetProxiedFrom(this, bufsize);
|
248
253
|
return;
|
249
254
|
}
|
@@ -290,6 +295,7 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
|
|
290
295
|
if (BytesToProxy > 0) {
|
291
296
|
unsigned long proxied = min(BytesToProxy, (unsigned long) size);
|
292
297
|
ProxyTarget->SendOutboundData(buf, proxied);
|
298
|
+
ProxiedBytes += (unsigned long) proxied;
|
293
299
|
BytesToProxy -= proxied;
|
294
300
|
if (BytesToProxy == 0) {
|
295
301
|
StopProxy();
|
@@ -300,6 +306,7 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
|
|
300
306
|
}
|
301
307
|
} else {
|
302
308
|
ProxyTarget->SendOutboundData(buf, size);
|
309
|
+
ProxiedBytes += (unsigned long) size;
|
303
310
|
}
|
304
311
|
} else {
|
305
312
|
(*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
|
@@ -457,6 +464,16 @@ void ConnectionDescriptor::SetConnectPending(bool f)
|
|
457
464
|
}
|
458
465
|
|
459
466
|
|
467
|
+
/**********************************
|
468
|
+
ConnectionDescriptor::SetAttached
|
469
|
+
***********************************/
|
470
|
+
|
471
|
+
void ConnectionDescriptor::SetAttached(bool state)
|
472
|
+
{
|
473
|
+
bAttached = state;
|
474
|
+
}
|
475
|
+
|
476
|
+
|
460
477
|
/**********************************
|
461
478
|
ConnectionDescriptor::SetWatchOnly
|
462
479
|
***********************************/
|
data/ext/ed.h
CHANGED
@@ -79,6 +79,7 @@ class EventableDescriptor: public Bindable_t
|
|
79
79
|
virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
|
80
80
|
uint64_t GetPendingConnectTimeout();
|
81
81
|
int SetPendingConnectTimeout (uint64_t value);
|
82
|
+
uint64_t GetLastActivity() { return LastActivity; }
|
82
83
|
|
83
84
|
#ifdef HAVE_EPOLL
|
84
85
|
struct epoll_event *GetEpollEvent() { return &EpollEvent; }
|
@@ -86,6 +87,7 @@ class EventableDescriptor: public Bindable_t
|
|
86
87
|
|
87
88
|
virtual void StartProxy(const unsigned long, const unsigned long, const unsigned long);
|
88
89
|
virtual void StopProxy();
|
90
|
+
virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; };
|
89
91
|
virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
|
90
92
|
virtual int SendOutboundData(const char*,int){ return -1; }
|
91
93
|
virtual bool IsPaused(){ return bPaused; }
|
@@ -103,6 +105,7 @@ class EventableDescriptor: public Bindable_t
|
|
103
105
|
|
104
106
|
protected:
|
105
107
|
int MySocket;
|
108
|
+
bool bAttached;
|
106
109
|
bool bWatchOnly;
|
107
110
|
|
108
111
|
EMCallback EventCallback;
|
@@ -115,6 +118,7 @@ class EventableDescriptor: public Bindable_t
|
|
115
118
|
unsigned long BytesToProxy;
|
116
119
|
EventableDescriptor *ProxyTarget;
|
117
120
|
EventableDescriptor *ProxiedFrom;
|
121
|
+
unsigned long ProxiedBytes;
|
118
122
|
|
119
123
|
unsigned long MaxOutboundBufSize;
|
120
124
|
|
@@ -169,6 +173,7 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
169
173
|
|
170
174
|
void SetNotifyReadable (bool);
|
171
175
|
void SetNotifyWritable (bool);
|
176
|
+
void SetAttached (bool);
|
172
177
|
void SetWatchOnly (bool);
|
173
178
|
|
174
179
|
bool Pause();
|
data/ext/em.cpp
CHANGED
@@ -73,6 +73,7 @@ EventMachine_t::EventMachine_t (EMCallback event_callback):
|
|
73
73
|
NextHeartbeatTime (0),
|
74
74
|
LoopBreakerReader (-1),
|
75
75
|
LoopBreakerWriter (-1),
|
76
|
+
NumCloseScheduled (0),
|
76
77
|
bTerminateSignalReceived (false),
|
77
78
|
bEpoll (false),
|
78
79
|
epfd (-1),
|
@@ -197,10 +198,9 @@ EventMachine_t::SetTimerQuantum
|
|
197
198
|
void EventMachine_t::SetTimerQuantum (int interval)
|
198
199
|
{
|
199
200
|
/* We get a timer-quantum expressed in milliseconds.
|
200
|
-
* Don't set a quantum smaller than 5 or larger than 2500.
|
201
201
|
*/
|
202
202
|
|
203
|
-
if ((interval < 5) || (interval >
|
203
|
+
if ((interval < 5) || (interval > 5*60*1000))
|
204
204
|
throw std::runtime_error ("invalid timer-quantum");
|
205
205
|
|
206
206
|
Quantum.tv_sec = interval / 1000;
|
@@ -673,7 +673,13 @@ EventMachine_t::_TimeTilNextEvent
|
|
673
673
|
|
674
674
|
timeval EventMachine_t::_TimeTilNextEvent()
|
675
675
|
{
|
676
|
+
// 29jul11: Changed calculation base from MyCurrentLoopTime to the
|
677
|
+
// real time. As MyCurrentLoopTime is set at the beginning of an
|
678
|
+
// iteration and this calculation is done at the end, evenmachine
|
679
|
+
// will potentially oversleep by the amount of time the iteration
|
680
|
+
// took to execute.
|
676
681
|
uint64_t next_event = 0;
|
682
|
+
uint64_t current_time = GetRealTime();
|
677
683
|
|
678
684
|
if (!Heartbeats.empty()) {
|
679
685
|
multimap<uint64_t,EventableDescriptor*>::iterator heartbeats = Heartbeats.begin();
|
@@ -687,16 +693,16 @@ timeval EventMachine_t::_TimeTilNextEvent()
|
|
687
693
|
}
|
688
694
|
|
689
695
|
if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
|
690
|
-
next_event =
|
696
|
+
next_event = current_time;
|
691
697
|
}
|
692
|
-
|
698
|
+
|
693
699
|
timeval tv;
|
694
700
|
|
695
|
-
if (next_event == 0) {
|
701
|
+
if (next_event == 0 || NumCloseScheduled > 0) {
|
696
702
|
tv = Quantum;
|
697
703
|
} else {
|
698
|
-
if (next_event >
|
699
|
-
uint64_t duration = next_event -
|
704
|
+
if (next_event > current_time) {
|
705
|
+
uint64_t duration = next_event - current_time;
|
700
706
|
tv.tv_sec = duration / 1000000;
|
701
707
|
tv.tv_usec = duration % 1000000;
|
702
708
|
} else {
|
@@ -1356,6 +1362,7 @@ const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
|
|
1356
1362
|
if (!cd)
|
1357
1363
|
throw std::runtime_error ("no connection allocated");
|
1358
1364
|
|
1365
|
+
cd->SetAttached(true);
|
1359
1366
|
cd->SetWatchOnly(watch_mode);
|
1360
1367
|
cd->SetConnectPending (false);
|
1361
1368
|
|
@@ -1395,7 +1402,11 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
|
|
1395
1402
|
if (bKqueue) {
|
1396
1403
|
// remove any read/write events for this fd
|
1397
1404
|
struct kevent k;
|
1405
|
+
#ifdef __NetBSD__
|
1406
|
+
EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t)ed);
|
1407
|
+
#else
|
1398
1408
|
EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, ed);
|
1409
|
+
#endif
|
1399
1410
|
int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
|
1400
1411
|
if (t < 0 && (errno != ENOENT) && (errno != EBADF)) {
|
1401
1412
|
char buf [200];
|
@@ -1651,7 +1662,11 @@ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
|
|
1651
1662
|
if (!ed)
|
1652
1663
|
throw std::runtime_error ("added bad descriptor");
|
1653
1664
|
struct kevent k;
|
1665
|
+
#ifdef __NetBSD__
|
1666
|
+
EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, (intptr_t)ed);
|
1667
|
+
#else
|
1654
1668
|
EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed);
|
1669
|
+
#endif
|
1655
1670
|
int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
|
1656
1671
|
if (t < 0) {
|
1657
1672
|
char buf [200];
|
@@ -1673,7 +1688,11 @@ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
|
|
1673
1688
|
if (!ed)
|
1674
1689
|
throw std::runtime_error ("added bad descriptor");
|
1675
1690
|
struct kevent k;
|
1691
|
+
#ifdef __NetBSD__
|
1692
|
+
EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
|
1693
|
+
#else
|
1676
1694
|
EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
|
1695
|
+
#endif
|
1677
1696
|
int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
|
1678
1697
|
if (t < 0) {
|
1679
1698
|
char buf [200];
|
@@ -1724,7 +1743,11 @@ void EventMachine_t::_AddNewDescriptors()
|
|
1724
1743
|
// INCOMPLETE. Some descriptors don't want to be readable.
|
1725
1744
|
assert (kqfd != -1);
|
1726
1745
|
struct kevent k;
|
1746
|
+
#ifdef __NetBSD__
|
1747
|
+
EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
|
1748
|
+
#else
|
1727
1749
|
EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
|
1750
|
+
#endif
|
1728
1751
|
int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
|
1729
1752
|
assert (t == 0);
|
1730
1753
|
}
|
data/ext/em.h
CHANGED
@@ -44,10 +44,10 @@ See the file COPYING for complete licensing information.
|
|
44
44
|
#define RUBY_UBF_IO RB_UBF_DFL
|
45
45
|
#endif
|
46
46
|
#ifndef RSTRING_PTR
|
47
|
-
#define RSTRING_PTR(str)
|
47
|
+
#define RSTRING_PTR(str) RSTRING(str)->ptr
|
48
48
|
#endif
|
49
49
|
#ifndef RSTRING_LEN
|
50
|
-
#define RSTRING_LEN(str)
|
50
|
+
#define RSTRING_LEN(str) RSTRING(str)->len
|
51
51
|
#endif
|
52
52
|
#ifndef RSTRING_LENINT
|
53
53
|
#define RSTRING_LENINT(str) RSTRING_LEN(str)
|
@@ -161,6 +161,7 @@ class EventMachine_t
|
|
161
161
|
public:
|
162
162
|
void _ReadLoopBreaker();
|
163
163
|
void _ReadInotifyEvents();
|
164
|
+
int NumCloseScheduled;
|
164
165
|
|
165
166
|
private:
|
166
167
|
enum {
|
data/ext/eventmachine.h
CHANGED
@@ -59,6 +59,8 @@ extern "C" {
|
|
59
59
|
int evma_is_paused(const unsigned long binding);
|
60
60
|
int evma_resume(const unsigned long binding);
|
61
61
|
|
62
|
+
int evma_num_close_scheduled();
|
63
|
+
|
62
64
|
void evma_stop_tcp_server (const unsigned long signature);
|
63
65
|
const unsigned long evma_create_tcp_server (const char *address, int port);
|
64
66
|
const unsigned long evma_create_unix_domain_server (const char *filename);
|
@@ -84,6 +86,7 @@ extern "C" {
|
|
84
86
|
float evma_get_pending_connect_timeout (const unsigned long binding);
|
85
87
|
int evma_set_pending_connect_timeout (const unsigned long binding, float value);
|
86
88
|
int evma_get_outbound_data_size (const unsigned long binding);
|
89
|
+
uint64_t evma_get_last_activity_time (const unsigned long);
|
87
90
|
int evma_send_file_data_to_connection (const unsigned long binding, const char *filename);
|
88
91
|
|
89
92
|
void evma_close_connection (const unsigned long binding, int after_writing);
|
@@ -107,6 +110,7 @@ extern "C" {
|
|
107
110
|
|
108
111
|
void evma_start_proxy(const unsigned long, const unsigned long, const unsigned long, const unsigned long);
|
109
112
|
void evma_stop_proxy(const unsigned long);
|
113
|
+
unsigned long evma_proxied_bytes(const unsigned long);
|
110
114
|
|
111
115
|
int evma_set_rlimit_nofile (int n_files);
|
112
116
|
|
data/ext/extconf.rb
CHANGED
@@ -92,7 +92,7 @@ end
|
|
92
92
|
case RUBY_PLATFORM
|
93
93
|
when /mswin32/, /mingw32/, /bccwin32/
|
94
94
|
check_heads(%w[windows.h winsock.h], true)
|
95
|
-
check_libs(%w[kernel32 rpcrt4 gdi32], true)
|
95
|
+
check_libs(%w[kernel32 rpcrt4 gdi32], true)
|
96
96
|
|
97
97
|
if GNU_CHAIN
|
98
98
|
CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
|
@@ -139,6 +139,15 @@ when /linux/
|
|
139
139
|
when /aix/
|
140
140
|
CONFIG['LDSHARED'] = "$(CXX) -shared -Wl,-G -Wl,-brtl"
|
141
141
|
|
142
|
+
when /cygwin/
|
143
|
+
# For rubies built with Cygwin, CXX may be set to CC, which is just
|
144
|
+
# a wrapper for gcc.
|
145
|
+
# This will compile, but it will not link to the C++ std library.
|
146
|
+
# Explicitly set CXX to use g++.
|
147
|
+
CONFIG['CXX'] = "g++"
|
148
|
+
# on Unix we need a g++ link, not gcc.
|
149
|
+
CONFIG['LDSHARED'] = "$(CXX) -shared"
|
150
|
+
|
142
151
|
else
|
143
152
|
# on Unix we need a g++ link, not gcc.
|
144
153
|
CONFIG['LDSHARED'] = "$(CXX) -shared"
|
@@ -154,4 +163,4 @@ add_define 'HAVE_MAKE_PAIR' if try_link(<<SRC, '-lstdc++')
|
|
154
163
|
SRC
|
155
164
|
TRY_LINK.sub!('$(CXX)', '$(CC)')
|
156
165
|
|
157
|
-
create_makefile "rubyeventmachine"
|
166
|
+
create_makefile "rubyeventmachine"
|
@@ -77,9 +77,18 @@ when /aix/
|
|
77
77
|
# on Unix we need a g++ link, not gcc.
|
78
78
|
CONFIG['LDSHARED'] = "$(CXX) -shared -Wl,-G"
|
79
79
|
|
80
|
+
when /cygwin/
|
81
|
+
# For rubies built with Cygwin, CXX may be set to CC, which is just
|
82
|
+
# a wrapper for gcc.
|
83
|
+
# This will compile, but it will not link to the C++ std library.
|
84
|
+
# Explicitly set CXX to use g++.
|
85
|
+
CONFIG['CXX'] = "g++"
|
86
|
+
# on Unix we need a g++ link, not gcc.
|
87
|
+
CONFIG['LDSHARED'] = "$(CXX) -shared"
|
88
|
+
|
80
89
|
else
|
81
90
|
# on Unix we need a g++ link, not gcc.
|
82
91
|
CONFIG['LDSHARED'] = "$(CXX) -shared"
|
83
92
|
end
|
84
93
|
|
85
|
-
create_makefile "fastfilereaderext"
|
94
|
+
create_makefile "fastfilereaderext"
|
data/ext/project.h
CHANGED
@@ -82,7 +82,8 @@ typedef int SOCKET;
|
|
82
82
|
|
83
83
|
#ifdef OS_WIN32
|
84
84
|
// 21Sep09: windows limits select() to 64 sockets by default, we increase it to 1024 here (before including winsock2.h)
|
85
|
-
|
85
|
+
// 18Jun12: fd_setsize must be changed in the ruby binary (not in this extension). redefining it also causes segvs, see eventmachine/eventmachine#333
|
86
|
+
//#define FD_SETSIZE 1024
|
86
87
|
|
87
88
|
#define WIN32_LEAN_AND_MEAN
|
88
89
|
#include <windows.h>
|
data/ext/rubymain.cpp
CHANGED
@@ -507,7 +507,7 @@ static VALUE t_connect_server (VALUE self, VALUE server, VALUE port)
|
|
507
507
|
rb_raise (EM_eConnectionError, "no connection");
|
508
508
|
return ULONG2NUM (f);
|
509
509
|
} catch (std::runtime_error e) {
|
510
|
-
rb_raise (EM_eConnectionError, e.what());
|
510
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
511
511
|
}
|
512
512
|
return Qnil;
|
513
513
|
}
|
@@ -528,7 +528,7 @@ static VALUE t_bind_connect_server (VALUE self, VALUE bind_addr, VALUE bind_port
|
|
528
528
|
rb_raise (EM_eConnectionError, "no connection");
|
529
529
|
return ULONG2NUM (f);
|
530
530
|
} catch (std::runtime_error e) {
|
531
|
-
rb_raise (EM_eConnectionError, e.what());
|
531
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
532
532
|
}
|
533
533
|
return Qnil;
|
534
534
|
}
|
@@ -686,6 +686,15 @@ static VALUE t_paused_p (VALUE self, VALUE signature)
|
|
686
686
|
return evma_is_paused(NUM2ULONG (signature)) ? Qtrue : Qfalse;
|
687
687
|
}
|
688
688
|
|
689
|
+
/*********************
|
690
|
+
t_num_close_scheduled
|
691
|
+
*********************/
|
692
|
+
|
693
|
+
static VALUE t_num_close_scheduled (VALUE self)
|
694
|
+
{
|
695
|
+
return INT2FIX(evma_num_close_scheduled());
|
696
|
+
}
|
697
|
+
|
689
698
|
/*****************
|
690
699
|
t_open_udp_socket
|
691
700
|
*****************/
|
@@ -839,7 +848,7 @@ static VALUE t_watch_filename (VALUE self, VALUE fname)
|
|
839
848
|
try {
|
840
849
|
return ULONG2NUM(evma_watch_filename(StringValuePtr(fname)));
|
841
850
|
} catch (std::runtime_error e) {
|
842
|
-
rb_raise (EM_eUnsupported, e.what());
|
851
|
+
rb_raise (EM_eUnsupported, "%s", e.what());
|
843
852
|
}
|
844
853
|
return Qnil;
|
845
854
|
}
|
@@ -865,7 +874,7 @@ static VALUE t_watch_pid (VALUE self, VALUE pid)
|
|
865
874
|
try {
|
866
875
|
return ULONG2NUM(evma_watch_pid(NUM2INT(pid)));
|
867
876
|
} catch (std::runtime_error e) {
|
868
|
-
rb_raise (EM_eUnsupported, e.what());
|
877
|
+
rb_raise (EM_eUnsupported, "%s", e.what());
|
869
878
|
}
|
870
879
|
return Qnil;
|
871
880
|
}
|
@@ -1065,7 +1074,7 @@ static VALUE t_start_proxy (VALUE self, VALUE from, VALUE to, VALUE bufsize, VAL
|
|
1065
1074
|
try {
|
1066
1075
|
evma_start_proxy(NUM2ULONG (from), NUM2ULONG (to), NUM2ULONG(bufsize), NUM2ULONG(length));
|
1067
1076
|
} catch (std::runtime_error e) {
|
1068
|
-
rb_raise (EM_eConnectionError, e.what());
|
1077
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
1069
1078
|
}
|
1070
1079
|
return Qnil;
|
1071
1080
|
}
|
@@ -1080,11 +1089,49 @@ static VALUE t_stop_proxy (VALUE self, VALUE from)
|
|
1080
1089
|
try{
|
1081
1090
|
evma_stop_proxy(NUM2ULONG (from));
|
1082
1091
|
} catch (std::runtime_error e) {
|
1083
|
-
rb_raise (EM_eConnectionError, e.what());
|
1092
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
1084
1093
|
}
|
1085
1094
|
return Qnil;
|
1086
1095
|
}
|
1087
1096
|
|
1097
|
+
/***************
|
1098
|
+
t_proxied_bytes
|
1099
|
+
****************/
|
1100
|
+
|
1101
|
+
static VALUE t_proxied_bytes (VALUE self, VALUE from)
|
1102
|
+
{
|
1103
|
+
try{
|
1104
|
+
return ULONG2NUM(evma_proxied_bytes(NUM2ULONG (from)));
|
1105
|
+
} catch (std::runtime_error e) {
|
1106
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
1107
|
+
}
|
1108
|
+
return Qnil;
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
/***************
|
1112
|
+
t_get_idle_time
|
1113
|
+
****************/
|
1114
|
+
|
1115
|
+
static VALUE t_get_idle_time (VALUE self, VALUE from)
|
1116
|
+
{
|
1117
|
+
try{
|
1118
|
+
uint64_t current_time = evma_get_current_loop_time();
|
1119
|
+
uint64_t time = evma_get_last_activity_time(NUM2ULONG (from));
|
1120
|
+
if (current_time != 0 && time != 0) {
|
1121
|
+
if (time >= current_time)
|
1122
|
+
return ULONG2NUM(0);
|
1123
|
+
else {
|
1124
|
+
uint64_t diff = current_time - time;
|
1125
|
+
float seconds = diff / (1000.0*1000.0);
|
1126
|
+
return rb_float_new(seconds);
|
1127
|
+
}
|
1128
|
+
return Qnil;
|
1129
|
+
}
|
1130
|
+
} catch (std::runtime_error e) {
|
1131
|
+
rb_raise (EM_eConnectionError, "%s", e.what());
|
1132
|
+
}
|
1133
|
+
return Qnil;
|
1134
|
+
}
|
1088
1135
|
|
1089
1136
|
/************************
|
1090
1137
|
t_get_heartbeat_interval
|
@@ -1180,9 +1227,11 @@ extern "C" void Init_rubyeventmachine()
|
|
1180
1227
|
rb_define_module_function (EmModule, "pause_connection", (VALUE (*)(...))t_pause, 1);
|
1181
1228
|
rb_define_module_function (EmModule, "resume_connection", (VALUE (*)(...))t_resume, 1);
|
1182
1229
|
rb_define_module_function (EmModule, "connection_paused?", (VALUE (*)(...))t_paused_p, 1);
|
1230
|
+
rb_define_module_function (EmModule, "num_close_scheduled", (VALUE (*)(...))t_num_close_scheduled, 0);
|
1183
1231
|
|
1184
1232
|
rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 4);
|
1185
1233
|
rb_define_module_function (EmModule, "stop_proxy", (VALUE (*)(...))t_stop_proxy, 1);
|
1234
|
+
rb_define_module_function (EmModule, "get_proxied_bytes", (VALUE (*)(...))t_proxied_bytes, 1);
|
1186
1235
|
|
1187
1236
|
rb_define_module_function (EmModule, "watch_filename", (VALUE (*)(...))t_watch_filename, 1);
|
1188
1237
|
rb_define_module_function (EmModule, "unwatch_filename", (VALUE (*)(...))t_unwatch_filename, 1);
|
@@ -1206,6 +1255,7 @@ extern "C" void Init_rubyeventmachine()
|
|
1206
1255
|
rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2);
|
1207
1256
|
rb_define_module_function (EmModule, "get_heartbeat_interval", (VALUE(*)(...))t_get_heartbeat_interval, 0);
|
1208
1257
|
rb_define_module_function (EmModule, "set_heartbeat_interval", (VALUE(*)(...))t_set_heartbeat_interval, 1);
|
1258
|
+
rb_define_module_function (EmModule, "get_idle_time", (VALUE(*)(...))t_get_idle_time, 1);
|
1209
1259
|
|
1210
1260
|
rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1);
|
1211
1261
|
rb_define_module_function (EmModule, "get_sockname", (VALUE(*)(...))t_get_sockname, 1);
|
data/ext/ssl.cpp
CHANGED
@@ -137,7 +137,7 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
|
|
137
137
|
bLibraryInitialized = true;
|
138
138
|
SSL_library_init();
|
139
139
|
OpenSSL_add_ssl_algorithms();
|
140
|
-
|
140
|
+
OpenSSL_add_all_algorithms();
|
141
141
|
SSL_load_error_strings();
|
142
142
|
ERR_load_crypto_strings();
|
143
143
|
|
@@ -151,6 +151,9 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
|
|
151
151
|
|
152
152
|
SSL_CTX_set_options (pCtx, SSL_OP_ALL);
|
153
153
|
//SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3));
|
154
|
+
#ifdef SSL_MODE_RELEASE_BUFFERS
|
155
|
+
SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS);
|
156
|
+
#endif
|
154
157
|
|
155
158
|
if (is_server) {
|
156
159
|
// The SSL_CTX calls here do NOT allocate memory.
|
@@ -524,6 +524,10 @@ public class EmReactor {
|
|
524
524
|
return Connections.get(sig).getPeerName();
|
525
525
|
}
|
526
526
|
|
527
|
+
public Object[] getSockName (long sig) {
|
528
|
+
return Connections.get(sig).getSockName();
|
529
|
+
}
|
530
|
+
|
527
531
|
public long attachChannel (SocketChannel sc, boolean watch_mode) {
|
528
532
|
long b = createBinding();
|
529
533
|
|
@@ -183,6 +183,12 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
public Object[] getSockName () {
|
187
|
+
DatagramSocket socket = channel.socket();
|
188
|
+
return new Object[]{ socket.getLocalPort(),
|
189
|
+
socket.getLocalAddress().getHostAddress() };
|
190
|
+
}
|
191
|
+
|
186
192
|
public boolean isWatchOnly() { return false; }
|
187
193
|
public boolean isNotifyReadable() { return false; }
|
188
194
|
public boolean isNotifyWritable() { return false; }
|
@@ -302,6 +302,12 @@ public class EventableSocketChannel implements EventableChannel {
|
|
302
302
|
return new Object[]{ sock.getPort(), sock.getInetAddress().getHostAddress() };
|
303
303
|
}
|
304
304
|
|
305
|
+
public Object[] getSockName () {
|
306
|
+
Socket sock = channel.socket();
|
307
|
+
return new Object[]{ sock.getLocalPort(),
|
308
|
+
sock.getLocalAddress().getHostAddress() };
|
309
|
+
}
|
310
|
+
|
305
311
|
public void setWatchOnly() {
|
306
312
|
bWatchOnly = true;
|
307
313
|
updateEvents();
|
data/lib/em/connection.rb
CHANGED
@@ -238,6 +238,12 @@ module EventMachine
|
|
238
238
|
EventMachine::disable_proxy(self)
|
239
239
|
end
|
240
240
|
|
241
|
+
# The number of bytes proxied to another connection. Reset to zero when
|
242
|
+
# EventMachine::Connection#proxy_incoming_to is called, and incremented whenever data is proxied.
|
243
|
+
def get_proxied_bytes
|
244
|
+
EventMachine::get_proxied_bytes(@signature)
|
245
|
+
end
|
246
|
+
|
241
247
|
# EventMachine::Connection#close_connection is called only by user code, and never
|
242
248
|
# by the event loop. You may call this method against a connection object in any
|
243
249
|
# callback handler, whether or not the callback was made against the connection
|
@@ -570,6 +576,11 @@ module EventMachine
|
|
570
576
|
EventMachine::get_subprocess_status @signature
|
571
577
|
end
|
572
578
|
|
579
|
+
# The number of seconds since the last send/receive activity on this connection.
|
580
|
+
def get_idle_time
|
581
|
+
EventMachine::get_idle_time @signature
|
582
|
+
end
|
583
|
+
|
573
584
|
# comm_inactivity_timeout returns the current value (float in seconds) of the inactivity-timeout
|
574
585
|
# property of network-connection and datagram-socket objects. A nonzero value
|
575
586
|
# indicates that the connection or socket will automatically be closed if no read or write
|
data/lib/em/pool.rb
CHANGED
@@ -122,7 +122,10 @@ module EventMachine
|
|
122
122
|
|
123
123
|
def failure resource
|
124
124
|
if @on_error
|
125
|
+
@contents.delete resource
|
125
126
|
@on_error.call resource
|
127
|
+
# Prevent users from calling a leak.
|
128
|
+
@removed.delete resource
|
126
129
|
else
|
127
130
|
requeue resource
|
128
131
|
end
|
@@ -140,7 +143,9 @@ module EventMachine
|
|
140
143
|
else
|
141
144
|
raise ArgumentError, "deferrable expected from work"
|
142
145
|
end
|
146
|
+
rescue Exception
|
147
|
+
failure resource
|
148
|
+
raise
|
143
149
|
end
|
144
|
-
|
145
150
|
end
|
146
|
-
end
|
151
|
+
end
|
@@ -31,38 +31,38 @@ module EventMachine
|
|
31
31
|
# Simple SMTP client
|
32
32
|
#
|
33
33
|
# @example
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
34
|
+
# email = EM::Protocols::SmtpClient.send(
|
35
|
+
# :domain=>"example.com",
|
36
|
+
# :host=>'localhost',
|
37
|
+
# :port=>25, # optional, defaults 25
|
38
|
+
# :starttls=>true, # use ssl
|
39
|
+
# :from=>"sender@example.com",
|
40
|
+
# :to=> ["to_1@example.com", "to_2@example.com"],
|
41
|
+
# :header=> {"Subject" => "This is a subject line"},
|
42
|
+
# :body=> "This is the body of the email"
|
43
|
+
# )
|
44
|
+
# email.callback{
|
45
|
+
# puts 'Email sent!'
|
46
|
+
# }
|
47
|
+
# email.errback{ |e|
|
48
|
+
# puts 'Email failed!'
|
49
|
+
# }
|
50
50
|
#
|
51
51
|
# Sending generated emails (using mailfactory)
|
52
52
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
53
|
+
# mail = MailFactory.new
|
54
|
+
# mail.to = 'someone@site.co'
|
55
|
+
# mail.from = 'me@site.com'
|
56
|
+
# mail.subject = 'hi!'
|
57
|
+
# mail.text = 'hello world'
|
58
|
+
# mail.html = '<h1>hello world</h1>'
|
59
59
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
60
|
+
# email = EM::P::SmtpClient.send(
|
61
|
+
# :domain=>'site.com',
|
62
|
+
# :from=>mail.from,
|
63
|
+
# :to=>mail.to,
|
64
|
+
# :content=>"#{mail.to_s}\r\n.\r\n"
|
65
|
+
# )
|
66
66
|
#
|
67
67
|
class SmtpClient < Connection
|
68
68
|
include EventMachine::Deferrable
|
data/lib/em/threaded_resource.rb
CHANGED
@@ -29,7 +29,7 @@ module EventMachine
|
|
29
29
|
#
|
30
30
|
# # If we don't care about the result:
|
31
31
|
# pool.perform do |dispatcher|
|
32
|
-
# # The following
|
32
|
+
# # The following block executes inside a dedicated thread, and should not
|
33
33
|
# # access EventMachine things:
|
34
34
|
# dispatcher.dispatch do |cassandra|
|
35
35
|
# cassandra.insert(:Things, '10', 'stuff' => 'things')
|
data/lib/em/version.rb
CHANGED
data/lib/eventmachine.rb
CHANGED
@@ -82,7 +82,8 @@ module EventMachine
|
|
82
82
|
@reactor_running = false
|
83
83
|
@next_tick_queue = []
|
84
84
|
@tails = []
|
85
|
-
@threadpool = nil
|
85
|
+
@threadpool = @threadqueue = @resultqueue = nil
|
86
|
+
@all_threads_spawned = false
|
86
87
|
|
87
88
|
# System errnos
|
88
89
|
# @private
|
@@ -155,7 +156,13 @@ module EventMachine
|
|
155
156
|
# will start without release_machine being called and will immediately throw
|
156
157
|
|
157
158
|
#
|
158
|
-
|
159
|
+
if reactor_running? and @reactor_pid != Process.pid
|
160
|
+
# Reactor was started in a different parent, meaning we have forked.
|
161
|
+
# Clean up reactor state so a new reactor boots up in this child.
|
162
|
+
stop_event_loop
|
163
|
+
release_machine
|
164
|
+
@reactor_running = false
|
165
|
+
end
|
159
166
|
|
160
167
|
tail and @tails.unshift(tail)
|
161
168
|
|
@@ -169,6 +176,7 @@ module EventMachine
|
|
169
176
|
@next_tick_queue ||= []
|
170
177
|
@tails ||= []
|
171
178
|
begin
|
179
|
+
@reactor_pid = Process.pid
|
172
180
|
@reactor_running = true
|
173
181
|
initialize_event_machine
|
174
182
|
(b = blk || block) and add_timer(0, b)
|
@@ -201,6 +209,7 @@ module EventMachine
|
|
201
209
|
@threadqueue = nil
|
202
210
|
@resultqueue = nil
|
203
211
|
@threadpool = nil
|
212
|
+
@all_threads_spawned = false
|
204
213
|
end
|
205
214
|
|
206
215
|
@next_tick_queue = []
|
@@ -252,7 +261,7 @@ module EventMachine
|
|
252
261
|
if self.reactor_running?
|
253
262
|
self.stop_event_loop
|
254
263
|
self.release_machine
|
255
|
-
|
264
|
+
@reactor_running = false
|
256
265
|
end
|
257
266
|
self.run block
|
258
267
|
end
|
@@ -425,7 +434,8 @@ module EventMachine
|
|
425
434
|
# that you must define. When the network server that is started by
|
426
435
|
# start_server accepts a new connection, it instantiates a new
|
427
436
|
# object of an anonymous class that is inherited from {EventMachine::Connection},
|
428
|
-
# *into which your handler module have been included*.
|
437
|
+
# *into which your handler module have been included*. Arguments passed into start_server
|
438
|
+
# after the class name are passed into the constructor during the instantiation.
|
429
439
|
#
|
430
440
|
# Your handler module may override any of the methods in {EventMachine::Connection},
|
431
441
|
# such as {EventMachine::Connection#receive_data}, in order to implement the specific behavior
|
@@ -736,6 +746,7 @@ module EventMachine
|
|
736
746
|
c = klass.new s, *args
|
737
747
|
|
738
748
|
c.instance_variable_set(:@io, io)
|
749
|
+
c.instance_variable_set(:@watch_mode, watch_mode)
|
739
750
|
c.instance_variable_set(:@fd, fd)
|
740
751
|
|
741
752
|
@conns[s] = c
|
@@ -761,7 +772,11 @@ module EventMachine
|
|
761
772
|
#raise "still connected" if @conns.has_key?(handler.signature)
|
762
773
|
return handler if @conns.has_key?(handler.signature)
|
763
774
|
|
764
|
-
s =
|
775
|
+
s = if port
|
776
|
+
connect_server server, port
|
777
|
+
else
|
778
|
+
connect_unix_server server
|
779
|
+
end
|
765
780
|
handler.signature = s
|
766
781
|
@conns[s] = handler
|
767
782
|
block_given? and yield handler
|
@@ -936,10 +951,21 @@ module EventMachine
|
|
936
951
|
cback.call result if cback
|
937
952
|
end
|
938
953
|
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
954
|
+
# Capture the size at the start of this tick...
|
955
|
+
size = @next_tick_mutex.synchronize { @next_tick_queue.size }
|
956
|
+
size.times do |i|
|
957
|
+
callback = @next_tick_mutex.synchronize { @next_tick_queue.shift }
|
958
|
+
begin
|
959
|
+
callback.call
|
960
|
+
ensure
|
961
|
+
# This is a little nasty. The problem is, if an exception occurs during
|
962
|
+
# the callback, then we need to send a signal to the reactor to actually
|
963
|
+
# do some work during the next_tick. The only mechanism we have from the
|
964
|
+
# ruby side is next_tick itself, although ideally, we'd just drop a byte
|
965
|
+
# on the loopback descriptor.
|
966
|
+
EM.next_tick {} if $!
|
967
|
+
end
|
968
|
+
end
|
943
969
|
end
|
944
970
|
|
945
971
|
|
@@ -991,7 +1017,6 @@ module EventMachine
|
|
991
1017
|
# has no constructor.
|
992
1018
|
|
993
1019
|
unless @threadpool
|
994
|
-
require 'thread'
|
995
1020
|
@threadpool = []
|
996
1021
|
@threadqueue = ::Queue.new
|
997
1022
|
@resultqueue = ::Queue.new
|
@@ -1016,6 +1041,19 @@ module EventMachine
|
|
1016
1041
|
end
|
1017
1042
|
@threadpool << thread
|
1018
1043
|
end
|
1044
|
+
@all_threads_spawned = true
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
##
|
1048
|
+
# Returns +true+ if all deferred actions are done executing and their
|
1049
|
+
# callbacks have been fired.
|
1050
|
+
#
|
1051
|
+
def self.defers_finished?
|
1052
|
+
return false if @threadpool and !@all_threads_spawned
|
1053
|
+
return false if @threadqueue and not @threadqueue.empty?
|
1054
|
+
return false if @resultqueue and not @resultqueue.empty?
|
1055
|
+
return false if @threadpool and @threadqueue.num_waiting != @threadpool.size
|
1056
|
+
return true
|
1019
1057
|
end
|
1020
1058
|
|
1021
1059
|
class << self
|
@@ -1391,11 +1429,19 @@ module EventMachine
|
|
1391
1429
|
if opcode == ConnectionUnbound
|
1392
1430
|
if c = @conns.delete( conn_binding )
|
1393
1431
|
begin
|
1394
|
-
if c.original_method(:unbind).arity
|
1432
|
+
if c.original_method(:unbind).arity != 0
|
1395
1433
|
c.unbind(data == 0 ? nil : EventMachine::ERRNOS[data])
|
1396
1434
|
else
|
1397
1435
|
c.unbind
|
1398
1436
|
end
|
1437
|
+
# If this is an attached (but not watched) connection, close the underlying io object.
|
1438
|
+
if c.instance_variable_defined?(:@io) and !c.instance_variable_get(:@watch_mode)
|
1439
|
+
io = c.instance_variable_get(:@io)
|
1440
|
+
begin
|
1441
|
+
io.close
|
1442
|
+
rescue Errno::EBADF, IOError
|
1443
|
+
end
|
1444
|
+
end
|
1399
1445
|
rescue
|
1400
1446
|
@wrapped_exception = $!
|
1401
1447
|
stop
|
data/lib/jeventmachine.rb
CHANGED
@@ -203,6 +203,11 @@ module EventMachine
|
|
203
203
|
Socket.pack_sockaddr_in(*peer)
|
204
204
|
end
|
205
205
|
end
|
206
|
+
def self.get_sockname sig
|
207
|
+
if sockName = @em.getSockName(sig)
|
208
|
+
Socket.pack_sockaddr_in(*sockName)
|
209
|
+
end
|
210
|
+
end
|
206
211
|
# @private
|
207
212
|
def self.attach_fd fileno, watch_mode
|
208
213
|
# 3Aug09: We could pass in the actual SocketChannel, but then it would be modified (set as non-blocking), and
|
File without changes
|
File without changes
|
data/{tasks → rakelib}/test.rake
RENAMED
File without changes
|
data/tests/test_basic.rb
CHANGED
@@ -224,4 +224,71 @@ class TestBasic < Test::Unit::TestCase
|
|
224
224
|
end
|
225
225
|
end
|
226
226
|
end
|
227
|
+
|
228
|
+
def test_schedule_close
|
229
|
+
localhost, port = '127.0.0.1', 9000
|
230
|
+
timer_ran = false
|
231
|
+
num_close_scheduled = nil
|
232
|
+
EM.run do
|
233
|
+
assert_equal 0, EM.num_close_scheduled
|
234
|
+
EM.add_timer(1) { timer_ran = true; EM.stop }
|
235
|
+
EM.start_server localhost, port do |s|
|
236
|
+
s.close_connection
|
237
|
+
num_close_scheduled = EM.num_close_scheduled
|
238
|
+
end
|
239
|
+
EM.connect localhost, port do |c|
|
240
|
+
def c.unbind
|
241
|
+
EM.stop
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
assert !timer_ran
|
246
|
+
assert_equal 1, num_close_scheduled
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_fork_safe
|
250
|
+
return unless cpid = fork { exit! } rescue false
|
251
|
+
|
252
|
+
read, write = IO.pipe
|
253
|
+
EM.run do
|
254
|
+
cpid = fork do
|
255
|
+
write.puts "forked"
|
256
|
+
EM.run do
|
257
|
+
EM.next_tick do
|
258
|
+
write.puts "EM ran"
|
259
|
+
exit!
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
EM.stop
|
264
|
+
end
|
265
|
+
Process.waitall
|
266
|
+
assert_equal "forked\n", read.readline
|
267
|
+
assert_equal "EM ran\n", read.readline
|
268
|
+
ensure
|
269
|
+
read.close rescue nil
|
270
|
+
write.close rescue nil
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_error_handler_idempotent # issue 185
|
274
|
+
errors = []
|
275
|
+
ticks = []
|
276
|
+
EM.error_handler do |e|
|
277
|
+
errors << e
|
278
|
+
end
|
279
|
+
|
280
|
+
EM.run do
|
281
|
+
EM.next_tick do
|
282
|
+
ticks << :first
|
283
|
+
raise
|
284
|
+
end
|
285
|
+
EM.next_tick do
|
286
|
+
ticks << :second
|
287
|
+
end
|
288
|
+
EM.add_timer(0.001) { EM.stop }
|
289
|
+
end
|
290
|
+
|
291
|
+
assert_equal 1, errors.size
|
292
|
+
assert_equal [:first, :second], ticks
|
293
|
+
end
|
227
294
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'em_test_helper'
|
2
|
+
|
3
|
+
class TestIdleConnection < Test::Unit::TestCase
|
4
|
+
if EM.respond_to?(:get_idle_time)
|
5
|
+
def test_idle_time
|
6
|
+
EM.run{
|
7
|
+
conn = EM.connect 'www.google.com', 80
|
8
|
+
EM.add_timer(3){
|
9
|
+
$idle_time = conn.get_idle_time
|
10
|
+
conn.send_data "GET / HTTP/1.0\r\n\r\n"
|
11
|
+
EM.next_tick{
|
12
|
+
$idle_time_after_send = conn.get_idle_time
|
13
|
+
conn.close_connection
|
14
|
+
EM.stop
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
assert_in_delta 3, $idle_time, 0.2
|
20
|
+
assert_equal 0, $idle_time_after_send
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/tests/test_pool.rb
CHANGED
@@ -115,6 +115,41 @@ class TestPool < Test::Unit::TestCase
|
|
115
115
|
assert_equal [:res], pool.contents
|
116
116
|
end
|
117
117
|
|
118
|
+
def test_contents_when_perform_errors_and_on_error_is_not_set
|
119
|
+
pool.add :res
|
120
|
+
assert_equal [:res], pool.contents
|
121
|
+
|
122
|
+
pool.perform do |r|
|
123
|
+
d = EM::DefaultDeferrable.new
|
124
|
+
d.fail
|
125
|
+
d
|
126
|
+
end
|
127
|
+
|
128
|
+
EM.run { EM.next_tick { EM.stop } }
|
129
|
+
|
130
|
+
assert_equal [:res], pool.contents
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_contents_when_perform_errors_and_on_error_is_set
|
134
|
+
pool.add :res
|
135
|
+
res = nil
|
136
|
+
pool.on_error do |r|
|
137
|
+
res = r
|
138
|
+
end
|
139
|
+
assert_equal [:res], pool.contents
|
140
|
+
|
141
|
+
pool.perform do |r|
|
142
|
+
d = EM::DefaultDeferrable.new
|
143
|
+
d.fail 'foo'
|
144
|
+
d
|
145
|
+
end
|
146
|
+
|
147
|
+
EM.run { EM.next_tick { EM.stop } }
|
148
|
+
|
149
|
+
assert_equal :res, res
|
150
|
+
assert_equal [], pool.contents
|
151
|
+
end
|
152
|
+
|
118
153
|
def test_num_waiting
|
119
154
|
pool.add :res
|
120
155
|
assert_equal 0, pool.num_waiting
|
@@ -125,4 +160,35 @@ class TestPool < Test::Unit::TestCase
|
|
125
160
|
assert_equal 10, pool.num_waiting
|
126
161
|
end
|
127
162
|
|
128
|
-
|
163
|
+
def test_exceptions_in_the_work_block_bubble_up_raise_and_fail_the_resource
|
164
|
+
pool.add :res
|
165
|
+
|
166
|
+
res = nil
|
167
|
+
pool.on_error { |r| res = r }
|
168
|
+
pool.perform { raise 'boom' }
|
169
|
+
|
170
|
+
assert_raises(RuntimeError) do
|
171
|
+
EM.run { EM.next_tick { EM.stop } }
|
172
|
+
end
|
173
|
+
|
174
|
+
assert_equal [], pool.contents
|
175
|
+
assert_equal :res, res
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_removed_list_does_not_leak_on_errors
|
179
|
+
pool.add :res
|
180
|
+
|
181
|
+
pool.on_error do |r|
|
182
|
+
# This is actually the wrong thing to do, and not required, but some users
|
183
|
+
# might do it. When they do, they would find that @removed would cause a
|
184
|
+
# slow leak.
|
185
|
+
pool.remove r
|
186
|
+
end
|
187
|
+
|
188
|
+
pool.perform { d = EM::DefaultDeferrable.new; d.fail; d }
|
189
|
+
|
190
|
+
EM.run { EM.next_tick { EM.stop } }
|
191
|
+
assert_equal [], pool.instance_variable_get(:@removed)
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
@@ -24,6 +24,7 @@ class TestProxyConnection < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def unbind
|
27
|
+
$proxied_bytes = self.get_proxied_bytes
|
27
28
|
@client.close_connection_after_writing
|
28
29
|
end
|
29
30
|
end
|
@@ -94,7 +95,7 @@ class TestProxyConnection < Test::Unit::TestCase
|
|
94
95
|
end
|
95
96
|
|
96
97
|
def receive_data(data)
|
97
|
-
EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
|
98
|
+
@proxy = EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
@@ -134,6 +135,17 @@ class TestProxyConnection < Test::Unit::TestCase
|
|
134
135
|
assert_equal("I know!", $client_data)
|
135
136
|
end
|
136
137
|
|
138
|
+
def test_proxied_bytes
|
139
|
+
EM.run {
|
140
|
+
EM.start_server("127.0.0.1", @port, Server)
|
141
|
+
EM.start_server("127.0.0.1", @proxy_port, ProxyServer, @port)
|
142
|
+
EM.connect("127.0.0.1", @proxy_port, Client)
|
143
|
+
}
|
144
|
+
|
145
|
+
assert_equal("I know!", $client_data)
|
146
|
+
assert_equal("I know!".bytesize, $proxied_bytes)
|
147
|
+
end
|
148
|
+
|
137
149
|
def test_partial_proxy_connection
|
138
150
|
EM.run {
|
139
151
|
EM.start_server("127.0.0.1", @port, Server)
|
data/tests/test_unbind_reason.rb
CHANGED
@@ -2,6 +2,15 @@ require 'em_test_helper'
|
|
2
2
|
require 'socket'
|
3
3
|
|
4
4
|
class TestUnbindReason < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class StubConnection < EM::Connection
|
7
|
+
attr_reader :error
|
8
|
+
def unbind(reason = nil)
|
9
|
+
@error = reason
|
10
|
+
EM.stop
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
def test_connect_timeout
|
6
15
|
error = nil
|
7
16
|
EM.run {
|
@@ -13,7 +22,7 @@ class TestUnbindReason < Test::Unit::TestCase
|
|
13
22
|
}
|
14
23
|
conn.pending_connect_timeout = 0.1
|
15
24
|
}
|
16
|
-
assert_equal
|
25
|
+
assert_equal Errno::ETIMEDOUT, error
|
17
26
|
end
|
18
27
|
|
19
28
|
def test_connect_refused
|
@@ -26,6 +35,14 @@ class TestUnbindReason < Test::Unit::TestCase
|
|
26
35
|
end
|
27
36
|
}
|
28
37
|
}
|
29
|
-
assert_equal
|
38
|
+
assert_equal Errno::ECONNREFUSED, error
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_optional_argument
|
42
|
+
conn = nil
|
43
|
+
EM.run {
|
44
|
+
conn = EM.connect '127.0.0.1', 12388, StubConnection
|
45
|
+
}
|
46
|
+
assert_equal Errno::ECONNREFUSED, conn.error
|
30
47
|
end
|
31
48
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eventmachine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 379161805
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
-
|
11
|
-
-
|
12
|
-
version: 1.0.0.
|
10
|
+
- rc
|
11
|
+
- 1
|
12
|
+
version: 1.0.0.rc.1
|
13
13
|
platform: x86-mswin32-60
|
14
14
|
authors:
|
15
15
|
- Francis Cianfrocca
|
@@ -18,7 +18,7 @@ autorequire:
|
|
18
18
|
bindir: bin
|
19
19
|
cert_chain: []
|
20
20
|
|
21
|
-
date:
|
21
|
+
date: 2012-06-18 00:00:00 -07:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -53,20 +53,6 @@ dependencies:
|
|
53
53
|
version: 0.7.2
|
54
54
|
type: :development
|
55
55
|
version_requirements: *id002
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: bluecloth
|
58
|
-
prerelease: false
|
59
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
60
|
-
none: false
|
61
|
-
requirements:
|
62
|
-
- - ">="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
hash: 3
|
65
|
-
segments:
|
66
|
-
- 0
|
67
|
-
version: "0"
|
68
|
-
type: :development
|
69
|
-
version_requirements: *id003
|
70
56
|
description: |-
|
71
57
|
EventMachine implements a fast, single-threaded engine for arbitrary network
|
72
58
|
communications. It's extremely easy to use in Ruby. EventMachine wraps all
|
@@ -206,9 +192,9 @@ files:
|
|
206
192
|
- lib/em/version.rb
|
207
193
|
- lib/eventmachine.rb
|
208
194
|
- lib/jeventmachine.rb
|
209
|
-
-
|
210
|
-
-
|
211
|
-
-
|
195
|
+
- rakelib/cpp.rake_example
|
196
|
+
- rakelib/package.rake
|
197
|
+
- rakelib/test.rake
|
212
198
|
- tests/client.crt
|
213
199
|
- tests/client.key
|
214
200
|
- tests/em_test_helper.rb
|
@@ -229,6 +215,7 @@ files:
|
|
229
215
|
- tests/test_hc.rb
|
230
216
|
- tests/test_httpclient.rb
|
231
217
|
- tests/test_httpclient2.rb
|
218
|
+
- tests/test_idle_connection.rb
|
232
219
|
- tests/test_inactivity_timeout.rb
|
233
220
|
- tests/test_kb.rb
|
234
221
|
- tests/test_ltp.rb
|