eventmachine 1.0.0.beta.3-java → 1.0.0.beta.4-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.yardopts +5 -1
- data/{docs/GNU → GNU} +0 -0
- data/Gemfile +1 -0
- data/{docs/COPYING → LICENSE} +0 -0
- data/README.md +109 -0
- data/Rakefile +8 -0
- data/docs/DocumentationGuidesIndex.md +27 -0
- data/docs/GettingStarted.md +521 -0
- data/docs/{ChangeLog → old/ChangeLog} +0 -0
- data/docs/{DEFERRABLES → old/DEFERRABLES} +0 -0
- data/docs/{EPOLL → old/EPOLL} +0 -0
- data/docs/{INSTALL → old/INSTALL} +0 -0
- data/docs/{KEYBOARD → old/KEYBOARD} +0 -0
- data/docs/{LEGAL → old/LEGAL} +0 -0
- data/docs/{LIGHTWEIGHT_CONCURRENCY → old/LIGHTWEIGHT_CONCURRENCY} +0 -0
- data/docs/{PURE_RUBY → old/PURE_RUBY} +0 -0
- data/docs/{RELEASE_NOTES → old/RELEASE_NOTES} +0 -0
- data/docs/{SMTP → old/SMTP} +0 -0
- data/docs/{SPAWNED_PROCESSES → old/SPAWNED_PROCESSES} +0 -0
- data/docs/{TODO → old/TODO} +0 -0
- data/eventmachine.gemspec +5 -2
- data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
- data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
- data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
- data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
- data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
- data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
- data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
- data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
- data/examples/{ex_channel.rb → old/ex_channel.rb} +3 -3
- data/examples/{ex_queue.rb → old/ex_queue.rb} +0 -0
- data/examples/{ex_tick_loop_array.rb → old/ex_tick_loop_array.rb} +0 -0
- data/examples/{ex_tick_loop_counter.rb → old/ex_tick_loop_counter.rb} +0 -0
- data/examples/{helper.rb → old/helper.rb} +0 -0
- data/ext/cmain.cpp +3 -3
- data/ext/ed.cpp +90 -15
- data/ext/ed.h +5 -5
- data/ext/em.cpp +59 -65
- data/ext/em.h +12 -2
- data/ext/extconf.rb +3 -3
- data/ext/pipe.cpp +2 -2
- data/ext/project.h +1 -1
- data/ext/rubymain.cpp +48 -3
- data/ext/ssl.cpp +5 -0
- data/java/src/com/rubyeventmachine/EmReactor.java +2 -2
- data/lib/em/buftok.rb +35 -63
- data/lib/em/callback.rb +43 -11
- data/lib/em/channel.rb +21 -14
- data/lib/em/completion.rb +304 -0
- data/lib/em/connection.rb +339 -209
- data/lib/em/deferrable.rb +4 -0
- data/lib/em/deferrable/pool.rb +2 -0
- data/lib/em/file_watch.rb +37 -18
- data/lib/em/iterator.rb +42 -42
- data/lib/em/pool.rb +146 -0
- data/lib/em/process_watch.rb +5 -4
- data/lib/em/processes.rb +8 -4
- data/lib/em/protocols/httpclient.rb +22 -11
- data/lib/em/protocols/httpclient2.rb +15 -5
- data/lib/em/protocols/line_protocol.rb +2 -1
- data/lib/em/protocols/memcache.rb +17 -9
- data/lib/em/protocols/object_protocol.rb +2 -1
- data/lib/em/protocols/postgres3.rb +8 -9
- data/lib/em/protocols/smtpclient.rb +19 -11
- data/lib/em/protocols/smtpserver.rb +1 -1
- data/lib/em/protocols/stomp.rb +8 -6
- data/lib/em/protocols/tcptest.rb +3 -2
- data/lib/em/pure_ruby.rb +212 -208
- data/lib/em/queue.rb +22 -13
- data/lib/em/resolver.rb +70 -64
- data/lib/em/spawnable.rb +6 -3
- data/lib/em/streamer.rb +33 -45
- data/lib/em/threaded_resource.rb +90 -0
- data/lib/em/timers.rb +6 -2
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +538 -602
- data/lib/jeventmachine.rb +22 -1
- data/tasks/package.rake +13 -3
- data/tasks/test.rake +1 -0
- data/tests/em_test_helper.rb +12 -3
- data/tests/test_completion.rb +177 -0
- data/tests/test_epoll.rb +2 -2
- data/tests/test_httpclient.rb +9 -9
- data/tests/test_httpclient2.rb +11 -9
- data/tests/test_ltp.rb +2 -10
- data/tests/test_pool.rb +128 -0
- data/tests/test_processes.rb +20 -2
- data/tests/test_queue.rb +8 -0
- data/tests/test_resolver.rb +1 -1
- data/tests/test_set_sock_opt.rb +37 -0
- data/tests/test_shutdown_hooks.rb +23 -0
- data/tests/test_threaded_resource.rb +53 -0
- data/tests/test_unbind_reason.rb +31 -0
- metadata +87 -45
- data/README +0 -81
- data/tasks/doc.rake +0 -30
@@ -0,0 +1,141 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems' # or use Bundler.setup
|
4
|
+
require 'eventmachine'
|
5
|
+
|
6
|
+
class SimpleChatServer < EM::Connection
|
7
|
+
|
8
|
+
@@connected_clients = Array.new
|
9
|
+
DM_REGEXP = /^@([a-zA-Z0-9]+)\s*:?\s+(.+)/.freeze
|
10
|
+
|
11
|
+
attr_reader :username
|
12
|
+
|
13
|
+
|
14
|
+
#
|
15
|
+
# EventMachine handlers
|
16
|
+
#
|
17
|
+
|
18
|
+
def post_init
|
19
|
+
@username = nil
|
20
|
+
|
21
|
+
puts "A client has connected..."
|
22
|
+
ask_username
|
23
|
+
end
|
24
|
+
|
25
|
+
def unbind
|
26
|
+
@@connected_clients.delete(self)
|
27
|
+
puts "[info] #{@username} has left" if entered_username?
|
28
|
+
end
|
29
|
+
|
30
|
+
def receive_data(data)
|
31
|
+
if entered_username?
|
32
|
+
handle_chat_message(data.strip)
|
33
|
+
else
|
34
|
+
handle_username(data.strip)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
#
|
40
|
+
# Username handling
|
41
|
+
#
|
42
|
+
|
43
|
+
def entered_username?
|
44
|
+
!@username.nil? && !@username.empty?
|
45
|
+
end # entered_username?
|
46
|
+
|
47
|
+
def handle_username(input)
|
48
|
+
if input.empty?
|
49
|
+
send_line("Blank usernames are not allowed. Try again.")
|
50
|
+
ask_username
|
51
|
+
else
|
52
|
+
@username = input
|
53
|
+
@@connected_clients.push(self)
|
54
|
+
self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") }
|
55
|
+
puts "#{@username} has joined"
|
56
|
+
|
57
|
+
self.send_line("[info] Ohai, #{@username}")
|
58
|
+
end
|
59
|
+
end # handle_username(input)
|
60
|
+
|
61
|
+
def ask_username
|
62
|
+
self.send_line("[info] Enter your username:")
|
63
|
+
end # ask_username
|
64
|
+
|
65
|
+
|
66
|
+
#
|
67
|
+
# Message handling
|
68
|
+
#
|
69
|
+
|
70
|
+
def handle_chat_message(msg)
|
71
|
+
if command?(msg)
|
72
|
+
self.handle_command(msg)
|
73
|
+
else
|
74
|
+
if direct_message?(msg)
|
75
|
+
self.handle_direct_message(msg)
|
76
|
+
else
|
77
|
+
self.announce(msg, "#{@username}:")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end # handle_chat_message(msg)
|
81
|
+
|
82
|
+
def direct_message?(input)
|
83
|
+
input =~ DM_REGEXP
|
84
|
+
end # direct_message?(input)
|
85
|
+
|
86
|
+
def handle_direct_message(input)
|
87
|
+
username, message = parse_direct_message(input)
|
88
|
+
|
89
|
+
if connection = @@connected_clients.find { |c| c.username == username }
|
90
|
+
puts "[dm] @#{@username} => @#{username}"
|
91
|
+
connection.send_line("[dm] @#{@username}: #{message}")
|
92
|
+
else
|
93
|
+
send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}"
|
94
|
+
end
|
95
|
+
end # handle_direct_message(input)
|
96
|
+
|
97
|
+
def parse_direct_message(input)
|
98
|
+
return [$1, $2] if input =~ DM_REGEXP
|
99
|
+
end # parse_direct_message(input)
|
100
|
+
|
101
|
+
|
102
|
+
#
|
103
|
+
# Commands handling
|
104
|
+
#
|
105
|
+
|
106
|
+
def command?(input)
|
107
|
+
input =~ /(exit|status)$/i
|
108
|
+
end # command?(input)
|
109
|
+
|
110
|
+
def handle_command(cmd)
|
111
|
+
case cmd
|
112
|
+
when /exit$/i then self.close_connection
|
113
|
+
when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room")
|
114
|
+
end
|
115
|
+
end # handle_command(cmd)
|
116
|
+
|
117
|
+
|
118
|
+
#
|
119
|
+
# Helpers
|
120
|
+
#
|
121
|
+
|
122
|
+
def announce(msg = nil, prefix = "[chat server]")
|
123
|
+
@@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty?
|
124
|
+
end # announce(msg)
|
125
|
+
|
126
|
+
def other_peers
|
127
|
+
@@connected_clients.reject { |c| self == c }
|
128
|
+
end # other_peers
|
129
|
+
|
130
|
+
def send_line(line)
|
131
|
+
self.send_data("#{line}\n")
|
132
|
+
end # send_line(line)
|
133
|
+
end
|
134
|
+
|
135
|
+
EventMachine.run do
|
136
|
+
# hit Control + C to stop
|
137
|
+
Signal.trap("INT") { EventMachine.stop }
|
138
|
+
Signal.trap("TERM") { EventMachine.stop }
|
139
|
+
|
140
|
+
EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer)
|
141
|
+
end
|
@@ -33,11 +33,11 @@ EM.run do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# This part of the example is more fake, but imagine sleep was in fact a
|
36
|
+
# This part of the example is more fake, but imagine sleep was in fact a
|
37
37
|
# long running calculation to achieve the value.
|
38
38
|
40.times do
|
39
39
|
EM.defer lambda { v = sleep(rand * 2); RandChannel << [Time.now, v] }
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
EM.add_timer(5) { EM.stop }
|
43
|
-
end
|
43
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/ext/cmain.cpp
CHANGED
@@ -220,7 +220,7 @@ evma_pause
|
|
220
220
|
|
221
221
|
extern "C" int evma_pause (const unsigned long binding)
|
222
222
|
{
|
223
|
-
|
223
|
+
EventableDescriptor *cd = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
|
224
224
|
if (cd)
|
225
225
|
return cd->Pause() ? 1 : 0;
|
226
226
|
|
@@ -233,7 +233,7 @@ evma_resume
|
|
233
233
|
|
234
234
|
extern "C" int evma_resume (const unsigned long binding)
|
235
235
|
{
|
236
|
-
|
236
|
+
EventableDescriptor *cd = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
|
237
237
|
if (cd)
|
238
238
|
return cd->Resume() ? 1 : 0;
|
239
239
|
|
@@ -246,7 +246,7 @@ evma_is_paused
|
|
246
246
|
|
247
247
|
extern "C" int evma_is_paused (const unsigned long binding)
|
248
248
|
{
|
249
|
-
|
249
|
+
EventableDescriptor *cd = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
|
250
250
|
if (cd)
|
251
251
|
return cd->IsPaused() ? 1 : 0;
|
252
252
|
|
data/ext/ed.cpp
CHANGED
@@ -63,7 +63,8 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
|
|
63
63
|
MaxOutboundBufSize(0),
|
64
64
|
MyEventMachine (em),
|
65
65
|
PendingConnectTimeout(20000000),
|
66
|
-
InactivityTimeout (0)
|
66
|
+
InactivityTimeout (0),
|
67
|
+
bPaused (false)
|
67
68
|
{
|
68
69
|
/* There are three ways to close a socket, all of which should
|
69
70
|
* automatically signal to the event machine that this object
|
@@ -107,7 +108,7 @@ EventableDescriptor::~EventableDescriptor
|
|
107
108
|
EventableDescriptor::~EventableDescriptor()
|
108
109
|
{
|
109
110
|
if (NextHeartbeat)
|
110
|
-
MyEventMachine->ClearHeartbeat(NextHeartbeat);
|
111
|
+
MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
|
111
112
|
if (EventCallback && bCallbackUnbind)
|
112
113
|
(*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
|
113
114
|
if (ProxiedFrom) {
|
@@ -135,10 +136,54 @@ EventableDescriptor::Close
|
|
135
136
|
|
136
137
|
void EventableDescriptor::Close()
|
137
138
|
{
|
139
|
+
/* EventMachine relies on the fact that when close(fd)
|
140
|
+
* is called that the fd is removed from any
|
141
|
+
* epoll event queues.
|
142
|
+
*
|
143
|
+
* However, this is not *always* the behavior of close(fd)
|
144
|
+
*
|
145
|
+
* See man 4 epoll Q6/A6 and then consider what happens
|
146
|
+
* when using pipes with eventmachine.
|
147
|
+
* (As is often done when communicating with a subprocess)
|
148
|
+
*
|
149
|
+
* The pipes end up looking like:
|
150
|
+
*
|
151
|
+
* ls -l /proc/<pid>/fd
|
152
|
+
* ...
|
153
|
+
* lr-x------ 1 root root 64 2011-08-19 21:31 3 -> pipe:[940970]
|
154
|
+
* l-wx------ 1 root root 64 2011-08-19 21:31 4 -> pipe:[940970]
|
155
|
+
*
|
156
|
+
* This meets the critera from man 4 epoll Q6/A4 for not
|
157
|
+
* removing fds from epoll event queues until all fds
|
158
|
+
* that reference the underlying file have been removed.
|
159
|
+
*
|
160
|
+
* If the EventableDescriptor associated with fd 3 is deleted,
|
161
|
+
* its dtor will call EventableDescriptor::Close(),
|
162
|
+
* which will call ::close(int fd).
|
163
|
+
*
|
164
|
+
* However, unless the EventableDescriptor associated with fd 4 is
|
165
|
+
* also deleted before the next call to epoll_wait, events may fire
|
166
|
+
* for fd 3 that were registered with an already deleted
|
167
|
+
* EventableDescriptor.
|
168
|
+
*
|
169
|
+
* Therefore, it is necessary to notify EventMachine that
|
170
|
+
* the fd associated with this EventableDescriptor is
|
171
|
+
* closing.
|
172
|
+
*
|
173
|
+
* EventMachine also never closes fds for STDIN, STDOUT and
|
174
|
+
* STDERR (0, 1 & 2)
|
175
|
+
*/
|
176
|
+
|
138
177
|
// Close the socket right now. Intended for emergencies.
|
139
|
-
if (MySocket != INVALID_SOCKET
|
140
|
-
|
141
|
-
|
178
|
+
if (MySocket != INVALID_SOCKET) {
|
179
|
+
MyEventMachine->Deregister (this);
|
180
|
+
|
181
|
+
// Do not close STDIN, STDOUT, STDERR
|
182
|
+
if (MySocket > 2 && !bWatchOnly) {
|
183
|
+
shutdown (MySocket, 1);
|
184
|
+
close (MySocket);
|
185
|
+
}
|
186
|
+
|
142
187
|
MySocket = INVALID_SOCKET;
|
143
188
|
}
|
144
189
|
}
|
@@ -294,7 +339,7 @@ EventableDescriptor::GetNextHeartbeat
|
|
294
339
|
uint64_t EventableDescriptor::GetNextHeartbeat()
|
295
340
|
{
|
296
341
|
if (NextHeartbeat)
|
297
|
-
MyEventMachine->ClearHeartbeat(NextHeartbeat);
|
342
|
+
MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
|
298
343
|
|
299
344
|
NextHeartbeat = 0;
|
300
345
|
|
@@ -319,7 +364,6 @@ ConnectionDescriptor::ConnectionDescriptor
|
|
319
364
|
|
320
365
|
ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
|
321
366
|
EventableDescriptor (sd, em),
|
322
|
-
bPaused (false),
|
323
367
|
bConnectPending (false),
|
324
368
|
bNotifyReadable (false),
|
325
369
|
bNotifyWritable (false),
|
@@ -703,6 +747,7 @@ void ConnectionDescriptor::Read()
|
|
703
747
|
|
704
748
|
|
705
749
|
int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
|
750
|
+
int e = errno;
|
706
751
|
//cerr << "<R:" << r << ">";
|
707
752
|
|
708
753
|
if (r > 0) {
|
@@ -721,8 +766,21 @@ void ConnectionDescriptor::Read()
|
|
721
766
|
break;
|
722
767
|
}
|
723
768
|
else {
|
724
|
-
|
725
|
-
|
769
|
+
#ifdef OS_UNIX
|
770
|
+
if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EAGAIN) && (e != EINTR)) {
|
771
|
+
#endif
|
772
|
+
#ifdef OS_WIN32
|
773
|
+
if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
|
774
|
+
#endif
|
775
|
+
// 26Mar11: Previously, all read errors were assumed to be EWOULDBLOCK and ignored.
|
776
|
+
// Now, instead, we call Close() on errors like ECONNRESET and ENOTCONN.
|
777
|
+
UnbindReasonCode = e;
|
778
|
+
Close();
|
779
|
+
break;
|
780
|
+
} else {
|
781
|
+
// Basically a would-block, meaning we've read everything there is to read.
|
782
|
+
break;
|
783
|
+
}
|
726
784
|
}
|
727
785
|
|
728
786
|
}
|
@@ -831,9 +889,12 @@ void ConnectionDescriptor::Write()
|
|
831
889
|
// from EventMachine_t::AttachFD as well.
|
832
890
|
SetConnectPending (false);
|
833
891
|
}
|
834
|
-
else
|
892
|
+
else {
|
893
|
+
if (o == 0)
|
894
|
+
UnbindReasonCode = error;
|
835
895
|
ScheduleClose (false);
|
836
896
|
//bCloseNow = true;
|
897
|
+
}
|
837
898
|
}
|
838
899
|
else {
|
839
900
|
|
@@ -953,6 +1014,7 @@ void ConnectionDescriptor::_WriteOutboundData()
|
|
953
1014
|
#endif
|
954
1015
|
|
955
1016
|
bool err = false;
|
1017
|
+
int e = errno;
|
956
1018
|
if (bytes_written < 0) {
|
957
1019
|
err = true;
|
958
1020
|
bytes_written = 0;
|
@@ -1003,12 +1065,14 @@ void ConnectionDescriptor::_WriteOutboundData()
|
|
1003
1065
|
|
1004
1066
|
if (err) {
|
1005
1067
|
#ifdef OS_UNIX
|
1006
|
-
if ((
|
1068
|
+
if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
|
1007
1069
|
#endif
|
1008
1070
|
#ifdef OS_WIN32
|
1009
|
-
if ((
|
1071
|
+
if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
|
1010
1072
|
#endif
|
1073
|
+
UnbindReasonCode = e;
|
1011
1074
|
Close();
|
1075
|
+
}
|
1012
1076
|
}
|
1013
1077
|
}
|
1014
1078
|
|
@@ -1019,6 +1083,10 @@ ConnectionDescriptor::ReportErrorStatus
|
|
1019
1083
|
|
1020
1084
|
int ConnectionDescriptor::ReportErrorStatus()
|
1021
1085
|
{
|
1086
|
+
if (MySocket == INVALID_SOCKET) {
|
1087
|
+
return -1;
|
1088
|
+
}
|
1089
|
+
|
1022
1090
|
int error;
|
1023
1091
|
socklen_t len;
|
1024
1092
|
len = sizeof(error);
|
@@ -1030,8 +1098,10 @@ int ConnectionDescriptor::ReportErrorStatus()
|
|
1030
1098
|
#endif
|
1031
1099
|
if ((o == 0) && (error == 0))
|
1032
1100
|
return 0;
|
1101
|
+
else if (o == 0)
|
1102
|
+
return error;
|
1033
1103
|
else
|
1034
|
-
return 1;
|
1104
|
+
return -1;
|
1035
1105
|
}
|
1036
1106
|
|
1037
1107
|
|
@@ -1198,14 +1268,18 @@ void ConnectionDescriptor::Heartbeat()
|
|
1198
1268
|
*/
|
1199
1269
|
|
1200
1270
|
if (bConnectPending) {
|
1201
|
-
if ((MyEventMachine->GetCurrentLoopTime() - CreatedAt) >= PendingConnectTimeout)
|
1271
|
+
if ((MyEventMachine->GetCurrentLoopTime() - CreatedAt) >= PendingConnectTimeout) {
|
1272
|
+
UnbindReasonCode = ETIMEDOUT;
|
1202
1273
|
ScheduleClose (false);
|
1203
1274
|
//bCloseNow = true;
|
1275
|
+
}
|
1204
1276
|
}
|
1205
1277
|
else {
|
1206
|
-
if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout))
|
1278
|
+
if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) {
|
1279
|
+
UnbindReasonCode = ETIMEDOUT;
|
1207
1280
|
ScheduleClose (false);
|
1208
1281
|
//bCloseNow = true;
|
1282
|
+
}
|
1209
1283
|
}
|
1210
1284
|
}
|
1211
1285
|
|
@@ -1582,6 +1656,7 @@ void DatagramDescriptor::Write()
|
|
1582
1656
|
#ifdef OS_WIN32
|
1583
1657
|
if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
|
1584
1658
|
#endif
|
1659
|
+
UnbindReasonCode = e;
|
1585
1660
|
Close();
|
1586
1661
|
break;
|
1587
1662
|
}
|
data/ext/ed.h
CHANGED
@@ -88,10 +88,11 @@ class EventableDescriptor: public Bindable_t
|
|
88
88
|
virtual void StopProxy();
|
89
89
|
virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
|
90
90
|
virtual int SendOutboundData(const char*,int){ return -1; }
|
91
|
-
virtual bool IsPaused(){ return
|
92
|
-
virtual bool Pause(){ return
|
93
|
-
virtual bool Resume(){
|
91
|
+
virtual bool IsPaused(){ return bPaused; }
|
92
|
+
virtual bool Pause(){ bPaused = true; return bPaused; }
|
93
|
+
virtual bool Resume(){ bPaused = false; return bPaused; }
|
94
94
|
|
95
|
+
void SetUnbindReasonCode(int code){ UnbindReasonCode = code; }
|
95
96
|
virtual int ReportErrorStatus(){ return 0; }
|
96
97
|
virtual bool IsConnectPending(){ return false; }
|
97
98
|
virtual uint64_t GetNextHeartbeat();
|
@@ -126,6 +127,7 @@ class EventableDescriptor: public Bindable_t
|
|
126
127
|
uint64_t InactivityTimeout;
|
127
128
|
uint64_t LastActivity;
|
128
129
|
uint64_t NextHeartbeat;
|
130
|
+
bool bPaused;
|
129
131
|
};
|
130
132
|
|
131
133
|
|
@@ -169,7 +171,6 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
169
171
|
void SetNotifyWritable (bool);
|
170
172
|
void SetWatchOnly (bool);
|
171
173
|
|
172
|
-
bool IsPaused(){ return bPaused; }
|
173
174
|
bool Pause();
|
174
175
|
bool Resume();
|
175
176
|
|
@@ -216,7 +217,6 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
216
217
|
};
|
217
218
|
|
218
219
|
protected:
|
219
|
-
bool bPaused;
|
220
220
|
bool bConnectPending;
|
221
221
|
|
222
222
|
bool bNotifyReadable;
|
data/ext/em.cpp
CHANGED
@@ -415,9 +415,17 @@ void EventMachine_t::QueueHeartbeat(EventableDescriptor *ed)
|
|
415
415
|
EventMachine_t::ClearHeartbeat
|
416
416
|
******************************/
|
417
417
|
|
418
|
-
void EventMachine_t::ClearHeartbeat(uint64_t key)
|
418
|
+
void EventMachine_t::ClearHeartbeat(uint64_t key, EventableDescriptor* ed)
|
419
419
|
{
|
420
|
-
|
420
|
+
multimap<uint64_t,EventableDescriptor*>::iterator it;
|
421
|
+
pair<multimap<uint64_t,EventableDescriptor*>::iterator,multimap<uint64_t,EventableDescriptor*>::iterator> ret;
|
422
|
+
ret = Heartbeats.equal_range (key);
|
423
|
+
for (it = ret.first; it != ret.second; ++it) {
|
424
|
+
if (it->second == ed) {
|
425
|
+
Heartbeats.erase (it);
|
426
|
+
break;
|
427
|
+
}
|
428
|
+
}
|
421
429
|
}
|
422
430
|
|
423
431
|
/*******************
|
@@ -465,8 +473,7 @@ void EventMachine_t::Run()
|
|
465
473
|
|
466
474
|
while (true) {
|
467
475
|
_UpdateTime();
|
468
|
-
|
469
|
-
break;
|
476
|
+
_RunTimers();
|
470
477
|
|
471
478
|
/* _Add must precede _Modify because the same descriptor might
|
472
479
|
* be on both lists during the same pass through the machine,
|
@@ -513,7 +520,8 @@ bool EventMachine_t::_RunEpollOnce()
|
|
513
520
|
assert (epfd != -1);
|
514
521
|
int s;
|
515
522
|
|
516
|
-
timeval tv
|
523
|
+
timeval tv;
|
524
|
+
_TimeTilNextEvent(&tv);
|
517
525
|
|
518
526
|
#ifdef BUILD_FOR_RUBY
|
519
527
|
int ret = 0;
|
@@ -583,7 +591,8 @@ bool EventMachine_t::_RunKqueueOnce()
|
|
583
591
|
assert (kqfd != -1);
|
584
592
|
int k;
|
585
593
|
|
586
|
-
timeval tv
|
594
|
+
timeval tv;
|
595
|
+
_TimeTilNextEvent(&tv);
|
587
596
|
|
588
597
|
struct timespec ts;
|
589
598
|
ts.tv_sec = tv.tv_sec;
|
@@ -664,7 +673,7 @@ bool EventMachine_t::_RunKqueueOnce()
|
|
664
673
|
EventMachine_t::_TimeTilNextEvent
|
665
674
|
*********************************/
|
666
675
|
|
667
|
-
timeval EventMachine_t::_TimeTilNextEvent()
|
676
|
+
timeval *EventMachine_t::_TimeTilNextEvent(timeval *tv)
|
668
677
|
{
|
669
678
|
uint64_t next_event = 0;
|
670
679
|
|
@@ -683,17 +692,17 @@ timeval EventMachine_t::_TimeTilNextEvent()
|
|
683
692
|
next_event = MyCurrentLoopTime;
|
684
693
|
}
|
685
694
|
|
686
|
-
timeval tv;
|
687
|
-
|
688
695
|
if (next_event == 0) {
|
689
|
-
tv = Quantum;
|
696
|
+
// tv->tv_sec = Quantum->tv_sec;
|
697
|
+
// tv->tv_usec = Quantum->tv_usec;
|
698
|
+
return NULL;
|
690
699
|
} else {
|
691
700
|
if (next_event > MyCurrentLoopTime) {
|
692
701
|
uint64_t duration = next_event - MyCurrentLoopTime;
|
693
|
-
tv
|
694
|
-
tv
|
702
|
+
tv->tv_sec = duration / 1000000;
|
703
|
+
tv->tv_usec = duration % 1000000;
|
695
704
|
} else {
|
696
|
-
tv
|
705
|
+
tv->tv_sec = tv->tv_usec = 0;
|
697
706
|
}
|
698
707
|
}
|
699
708
|
|
@@ -899,7 +908,7 @@ bool EventMachine_t::_RunSelectOnce()
|
|
899
908
|
{ // read and write the sockets
|
900
909
|
//timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
|
901
910
|
//timeval tv = Quantum;
|
902
|
-
SelectData.tv
|
911
|
+
_TimeTilNextEvent(&SelectData.tv);
|
903
912
|
int s = SelectData._Select();
|
904
913
|
//rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
|
905
914
|
//int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
|
@@ -1005,10 +1014,9 @@ void EventMachine_t::_ReadLoopBreaker()
|
|
1005
1014
|
EventMachine_t::_RunTimers
|
1006
1015
|
**************************/
|
1007
1016
|
|
1008
|
-
|
1017
|
+
void EventMachine_t::_RunTimers()
|
1009
1018
|
{
|
1010
1019
|
// These are caller-defined timer handlers.
|
1011
|
-
// Return T/F to indicate whether we should continue the main loop.
|
1012
1020
|
// We rely on the fact that multimaps sort by their keys to avoid
|
1013
1021
|
// inspecting the whole list every time we come here.
|
1014
1022
|
// Just keep inspecting and processing the list head until we hit
|
@@ -1024,7 +1032,6 @@ bool EventMachine_t::_RunTimers()
|
|
1024
1032
|
(*EventCallback) (0, EM_TIMER_FIRED, NULL, i->second.GetBinding());
|
1025
1033
|
Timers.erase (i);
|
1026
1034
|
}
|
1027
|
-
return true;
|
1028
1035
|
}
|
1029
1036
|
|
1030
1037
|
|
@@ -1096,34 +1103,6 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1096
1103
|
throw std::runtime_error (buf);
|
1097
1104
|
}
|
1098
1105
|
|
1099
|
-
/*
|
1100
|
-
sockaddr_in pin;
|
1101
|
-
unsigned long HostAddr;
|
1102
|
-
|
1103
|
-
HostAddr = inet_addr (server);
|
1104
|
-
if (HostAddr == INADDR_NONE) {
|
1105
|
-
hostent *hp = gethostbyname ((char*)server); // Windows requires (char*)
|
1106
|
-
if (!hp) {
|
1107
|
-
// TODO: This gives the caller a fatal error. Not good.
|
1108
|
-
// They can respond by catching RuntimeError (blecch).
|
1109
|
-
// Possibly we need to fire an unbind event and provide
|
1110
|
-
// a status code so user code can detect the cause of the
|
1111
|
-
// failure.
|
1112
|
-
return NULL;
|
1113
|
-
}
|
1114
|
-
HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
|
1115
|
-
}
|
1116
|
-
|
1117
|
-
memset (&pin, 0, sizeof(pin));
|
1118
|
-
pin.sin_family = AF_INET;
|
1119
|
-
pin.sin_addr.s_addr = HostAddr;
|
1120
|
-
pin.sin_port = htons (port);
|
1121
|
-
|
1122
|
-
int sd = socket (AF_INET, SOCK_STREAM, 0);
|
1123
|
-
if (sd == INVALID_SOCKET)
|
1124
|
-
return NULL;
|
1125
|
-
*/
|
1126
|
-
|
1127
1106
|
// From here on, ALL error returns must close the socket.
|
1128
1107
|
// Set the new socket nonblocking.
|
1129
1108
|
if (!SetSocketNonblocking (sd)) {
|
@@ -1150,6 +1129,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1150
1129
|
}
|
1151
1130
|
|
1152
1131
|
unsigned long out = 0;
|
1132
|
+
int e = 0;
|
1153
1133
|
|
1154
1134
|
#ifdef OS_UNIX
|
1155
1135
|
//if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
|
@@ -1183,7 +1163,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1183
1163
|
else if (errno == EINPROGRESS) {
|
1184
1164
|
// Errno will generally always be EINPROGRESS, but on Linux
|
1185
1165
|
// we have to look at getsockopt to be sure what really happened.
|
1186
|
-
int error;
|
1166
|
+
int error = 0;
|
1187
1167
|
socklen_t len;
|
1188
1168
|
len = sizeof(error);
|
1189
1169
|
int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
|
@@ -1197,11 +1177,15 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1197
1177
|
cd->SetConnectPending (true);
|
1198
1178
|
Add (cd);
|
1199
1179
|
out = cd->GetBinding();
|
1180
|
+
} else {
|
1181
|
+
// Fall through to the !out case below.
|
1182
|
+
e = error;
|
1200
1183
|
}
|
1201
1184
|
}
|
1202
1185
|
else {
|
1203
1186
|
// The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
|
1204
1187
|
// Fall through to the !out case below
|
1188
|
+
e = errno;
|
1205
1189
|
}
|
1206
1190
|
|
1207
1191
|
if (!out) {
|
@@ -1220,6 +1204,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
|
|
1220
1204
|
ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
|
1221
1205
|
if (!cd)
|
1222
1206
|
throw std::runtime_error ("no connection allocated");
|
1207
|
+
cd->SetUnbindReasonCode(e);
|
1223
1208
|
cd->ScheduleClose (false);
|
1224
1209
|
Add (cd);
|
1225
1210
|
out = cd->GetBinding();
|
@@ -1526,25 +1511,6 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
|
|
1526
1511
|
goto fail;
|
1527
1512
|
}
|
1528
1513
|
|
1529
|
-
/*
|
1530
|
-
memset (&sin, 0, sizeof(sin));
|
1531
|
-
sin.sin_family = AF_INET;
|
1532
|
-
sin.sin_addr.s_addr = INADDR_ANY;
|
1533
|
-
sin.sin_port = htons (port);
|
1534
|
-
|
1535
|
-
if (server && *server) {
|
1536
|
-
sin.sin_addr.s_addr = inet_addr (server);
|
1537
|
-
if (sin.sin_addr.s_addr == INADDR_NONE) {
|
1538
|
-
hostent *hp = gethostbyname ((char*)server); // Windows requires the cast.
|
1539
|
-
if (hp == NULL) {
|
1540
|
-
//__warning ("hostname not resolved: ", server);
|
1541
|
-
goto fail;
|
1542
|
-
}
|
1543
|
-
sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
|
1544
|
-
}
|
1545
|
-
}
|
1546
|
-
*/
|
1547
|
-
|
1548
1514
|
{ // set reuseaddr to improve performance on restarts.
|
1549
1515
|
int oval = 1;
|
1550
1516
|
if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) {
|
@@ -1824,6 +1790,34 @@ void EventMachine_t::Modify (EventableDescriptor *ed)
|
|
1824
1790
|
}
|
1825
1791
|
|
1826
1792
|
|
1793
|
+
/***********************
|
1794
|
+
EventMachine_t::Deregister
|
1795
|
+
***********************/
|
1796
|
+
|
1797
|
+
void EventMachine_t::Deregister (EventableDescriptor *ed)
|
1798
|
+
{
|
1799
|
+
if (!ed)
|
1800
|
+
throw std::runtime_error ("modified bad descriptor");
|
1801
|
+
#ifdef HAVE_EPOLL
|
1802
|
+
// cut/paste from _CleanupSockets(). The error handling could be
|
1803
|
+
// refactored out of there, but it is cut/paste all over the
|
1804
|
+
// file already.
|
1805
|
+
if (bEpoll) {
|
1806
|
+
assert (epfd != -1);
|
1807
|
+
assert (ed->GetSocket() != INVALID_SOCKET);
|
1808
|
+
int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
|
1809
|
+
// ENOENT or EBADF are not errors because the socket may be already closed when we get here.
|
1810
|
+
if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
|
1811
|
+
char buf [200];
|
1812
|
+
snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
|
1813
|
+
throw std::runtime_error (buf);
|
1814
|
+
}
|
1815
|
+
ModifiedDescriptors.erase(ed);
|
1816
|
+
}
|
1817
|
+
#endif
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
|
1827
1821
|
/**************************************
|
1828
1822
|
EventMachine_t::CreateUnixDomainServer
|
1829
1823
|
**************************************/
|