eventmachine 1.0.0.beta.3 → 1.0.0.beta.4
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 +4 -1
- 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 +47 -55
- data/ext/em.h +12 -2
- 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 +12 -2
- 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 +262 -192
- data/README +0 -81
- data/tasks/doc.rake +0 -30
@@ -357,7 +357,7 @@ module EventMachine
|
|
357
357
|
|
358
358
|
def process_auth_line(line)
|
359
359
|
plain = line.unpack("m").first
|
360
|
-
|
360
|
+
_,user,psw = plain.split("\000")
|
361
361
|
if receive_plain_auth user,psw
|
362
362
|
send_data "235 authentication ok\r\n"
|
363
363
|
@state << :auth
|
data/lib/em/protocols/stomp.rb
CHANGED
@@ -64,12 +64,14 @@ module EventMachine
|
|
64
64
|
# Body of the message
|
65
65
|
attr_accessor :body
|
66
66
|
|
67
|
-
|
67
|
+
# @private
|
68
|
+
def initialize
|
68
69
|
@header = {}
|
69
70
|
@state = :precommand
|
70
71
|
@content_length = nil
|
71
72
|
end
|
72
|
-
|
73
|
+
# @private
|
74
|
+
def consume_line line
|
73
75
|
if @state == :precommand
|
74
76
|
unless line =~ /\A\s*\Z/
|
75
77
|
@command = line
|
@@ -100,8 +102,7 @@ module EventMachine
|
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
#
|
104
|
-
|
105
|
+
# @private
|
105
106
|
def send_frame verb, headers={}, body=""
|
106
107
|
ary = [verb, "\n"]
|
107
108
|
headers.each {|k,v| ary << "#{k}:#{v}\n" }
|
@@ -113,6 +114,7 @@ module EventMachine
|
|
113
114
|
send_data ary.join
|
114
115
|
end
|
115
116
|
|
117
|
+
# @private
|
116
118
|
def receive_line line
|
117
119
|
@stomp_initialized || init_message_reader
|
118
120
|
@stomp_message.consume_line(line) {|outcome|
|
@@ -127,12 +129,14 @@ module EventMachine
|
|
127
129
|
}
|
128
130
|
end
|
129
131
|
|
132
|
+
# @private
|
130
133
|
def receive_binary_data data
|
131
134
|
@stomp_message.body = data[0..-2]
|
132
135
|
receive_msg(@stomp_message) if respond_to?(:receive_msg)
|
133
136
|
init_message_reader
|
134
137
|
end
|
135
138
|
|
139
|
+
# @private
|
136
140
|
def init_message_reader
|
137
141
|
@stomp_initialized = true
|
138
142
|
set_delimiter "\n"
|
@@ -140,8 +144,6 @@ module EventMachine
|
|
140
144
|
@stomp_message = Message.new
|
141
145
|
end
|
142
146
|
|
143
|
-
# :startdoc:
|
144
|
-
|
145
147
|
# Invoked with an incoming Stomp::Message received from the STOMP server
|
146
148
|
def receive_msg msg
|
147
149
|
# stub, overwrite this in your handler
|
data/lib/em/protocols/tcptest.rb
CHANGED
@@ -27,7 +27,8 @@
|
|
27
27
|
module EventMachine
|
28
28
|
module Protocols
|
29
29
|
|
30
|
-
|
30
|
+
# @private
|
31
|
+
class TcpConnectTester < Connection
|
31
32
|
include EventMachine::Deferrable
|
32
33
|
|
33
34
|
def self.test( host, port )
|
@@ -50,4 +51,4 @@ module EventMachine
|
|
50
51
|
end
|
51
52
|
|
52
53
|
end
|
53
|
-
end
|
54
|
+
end
|
data/lib/em/pure_ruby.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
5
5
|
# Date:: 8 Apr 2006
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# See EventMachine and EventMachine::Connection for documentation and
|
8
8
|
# usage examples.
|
9
9
|
#
|
@@ -11,17 +11,17 @@
|
|
11
11
|
#
|
12
12
|
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
13
|
# Gmail: blackhedd
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# This program is free software; you can redistribute it and/or modify
|
16
16
|
# it under the terms of either: 1) the GNU General Public License
|
17
17
|
# as published by the Free Software Foundation; either version 2 of the
|
18
18
|
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# See the file COPYING for complete licensing information.
|
21
21
|
#
|
22
22
|
#-------------------------------------------------------------------
|
23
23
|
#
|
24
|
-
#
|
24
|
+
#
|
25
25
|
|
26
26
|
# TODO List:
|
27
27
|
# TCP-connects currently assume non-blocking connect is available- need to
|
@@ -34,320 +34,330 @@ require 'socket'
|
|
34
34
|
require 'fcntl'
|
35
35
|
require 'set'
|
36
36
|
|
37
|
-
|
37
|
+
# @private
|
38
|
+
module EventMachine
|
38
39
|
class << self
|
39
40
|
# This is mostly useful for automated tests.
|
40
41
|
# Return a distinctive symbol so the caller knows whether he's dealing
|
41
42
|
# with an extension or with a pure-Ruby library.
|
43
|
+
# @private
|
42
44
|
def library_type
|
43
45
|
:pure_ruby
|
44
46
|
end
|
45
47
|
|
46
|
-
#
|
48
|
+
# @private
|
47
49
|
def initialize_event_machine
|
48
50
|
Reactor.instance.initialize_for_run
|
49
51
|
end
|
50
52
|
|
51
|
-
# #add_oneshot_timer
|
52
|
-
#--
|
53
53
|
# Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby
|
54
54
|
# processor still wants them in seconds.
|
55
|
+
# @private
|
55
56
|
def add_oneshot_timer interval
|
56
57
|
Reactor.instance.install_oneshot_timer(interval / 1000)
|
57
58
|
end
|
58
59
|
|
59
|
-
#
|
60
|
+
# @private
|
60
61
|
def run_machine
|
61
62
|
Reactor.instance.run
|
62
63
|
end
|
63
64
|
|
64
|
-
#
|
65
|
+
# @private
|
65
66
|
def release_machine
|
66
67
|
end
|
67
68
|
|
68
|
-
#
|
69
|
+
# @private
|
69
70
|
def stop
|
70
71
|
Reactor.instance.stop
|
71
72
|
end
|
72
73
|
|
73
|
-
#
|
74
|
-
# TODO, what do we return here if we can't connect?
|
74
|
+
# @private
|
75
75
|
def connect_server host, port
|
76
76
|
bind_connect_server nil, nil, host, port
|
77
77
|
end
|
78
78
|
|
79
|
+
# @private
|
79
80
|
def bind_connect_server bind_addr, bind_port, host, port
|
80
81
|
EvmaTCPClient.connect(bind_addr, bind_port, host, port).uuid
|
81
82
|
end
|
82
83
|
|
83
|
-
#
|
84
|
+
# @private
|
84
85
|
def send_data target, data, datalength
|
85
86
|
selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
|
86
87
|
selectable.send_data data
|
87
88
|
end
|
88
89
|
|
89
|
-
|
90
|
+
|
90
91
|
# The extension version does NOT raise any kind of an error if an attempt is made
|
91
92
|
# to close a non-existent connection. Not sure whether we should. For now, we'll
|
92
93
|
# raise an error here in that case.
|
94
|
+
# @private
|
93
95
|
def close_connection target, after_writing
|
94
96
|
selectable = Reactor.instance.get_selectable( target ) or raise "unknown close_connection target"
|
95
97
|
selectable.schedule_close after_writing
|
96
98
|
end
|
97
99
|
|
98
|
-
#
|
100
|
+
# @private
|
99
101
|
def start_tcp_server host, port
|
100
102
|
(s = EvmaTCPServer.start_server host, port) or raise "no acceptor"
|
101
103
|
s.uuid
|
102
104
|
end
|
103
105
|
|
104
|
-
#
|
106
|
+
# @private
|
105
107
|
def stop_tcp_server sig
|
106
108
|
s = Reactor.instance.get_selectable(sig)
|
107
109
|
s.schedule_close
|
108
110
|
end
|
109
111
|
|
110
|
-
#
|
112
|
+
# @private
|
111
113
|
def start_unix_server chain
|
112
114
|
(s = EvmaUNIXServer.start_server chain) or raise "no acceptor"
|
113
115
|
s.uuid
|
114
116
|
end
|
115
117
|
|
116
|
-
#
|
118
|
+
# @private
|
117
119
|
def connect_unix_server chain
|
118
120
|
EvmaUNIXClient.connect(chain).uuid
|
119
121
|
end
|
120
122
|
|
121
|
-
#
|
123
|
+
# @private
|
122
124
|
def signal_loopbreak
|
123
125
|
Reactor.instance.signal_loopbreak
|
124
126
|
end
|
125
127
|
|
126
|
-
#
|
128
|
+
# @private
|
127
129
|
def get_peername sig
|
128
130
|
selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target"
|
129
131
|
selectable.get_peername
|
130
132
|
end
|
131
133
|
|
132
|
-
#
|
134
|
+
# @private
|
133
135
|
def open_udp_socket host, port
|
134
136
|
EvmaUDPSocket.create(host, port).uuid
|
135
137
|
end
|
136
138
|
|
137
|
-
#
|
139
|
+
# This is currently only for UDP!
|
138
140
|
# We need to make it work with unix-domain sockets as well.
|
141
|
+
# @private
|
139
142
|
def send_datagram target, data, datalength, host, port
|
140
143
|
selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
|
141
144
|
selectable.send_datagram data, Socket::pack_sockaddr_in(port, host)
|
142
145
|
end
|
143
146
|
|
144
147
|
|
145
|
-
#
|
148
|
+
# Sets reactor quantum in milliseconds. The underlying Reactor function wants a (possibly
|
146
149
|
# fractional) number of seconds.
|
150
|
+
# @private
|
147
151
|
def set_timer_quantum interval
|
148
152
|
Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
|
149
153
|
end
|
150
154
|
|
151
|
-
#
|
155
|
+
# This method is a harmless no-op in the pure-Ruby implementation. This is intended to ensure
|
152
156
|
# that user code behaves properly across different EM implementations.
|
157
|
+
# @private
|
153
158
|
def epoll
|
154
159
|
end
|
155
160
|
|
156
|
-
#
|
161
|
+
# This method is not implemented for pure-Ruby implementation
|
162
|
+
# @private
|
157
163
|
def ssl?
|
158
164
|
false
|
159
165
|
end
|
160
166
|
|
161
|
-
#
|
167
|
+
# This method is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
|
162
168
|
# per-process file-descriptor limit.
|
169
|
+
# @private
|
163
170
|
def set_rlimit_nofile n
|
164
171
|
1024
|
165
172
|
end
|
166
173
|
|
167
|
-
#
|
174
|
+
# This method is a harmless no-op in pure Ruby, which doesn't have a built-in limit
|
168
175
|
# on the number of available timers.
|
176
|
+
# @private
|
169
177
|
def set_max_timer_count n
|
170
178
|
end
|
171
179
|
|
172
|
-
#
|
180
|
+
# @private
|
181
|
+
def get_sock_opt signature, level, optname
|
182
|
+
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
|
183
|
+
selectable.getsockopt level, optname
|
184
|
+
end
|
185
|
+
|
186
|
+
# @private
|
187
|
+
def set_sock_opt signature, level, optname, optval
|
188
|
+
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
|
189
|
+
selectable.setsockopt level, optname, optval
|
190
|
+
end
|
191
|
+
|
192
|
+
# @private
|
173
193
|
def send_file_data sig, filename
|
174
194
|
sz = File.size(filename)
|
175
195
|
raise "file too large" if sz > 32*1024
|
176
196
|
data =
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
197
|
+
begin
|
198
|
+
File.read filename
|
199
|
+
rescue
|
200
|
+
""
|
201
|
+
end
|
182
202
|
send_data sig, data, data.length
|
183
203
|
end
|
184
204
|
|
185
|
-
#
|
186
|
-
#
|
205
|
+
# @private
|
187
206
|
def get_outbound_data_size sig
|
188
207
|
r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target"
|
189
208
|
r.get_outbound_data_size
|
190
209
|
end
|
191
210
|
|
192
|
-
#
|
193
|
-
#
|
211
|
+
# @private
|
194
212
|
def read_keyboard
|
195
213
|
EvmaKeyboard.open.uuid
|
196
214
|
end
|
197
215
|
|
198
|
-
#
|
199
|
-
#
|
216
|
+
# @private
|
200
217
|
def set_comm_inactivity_timeout sig, tm
|
201
218
|
r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
|
202
219
|
r.set_inactivity_timeout tm
|
203
220
|
end
|
204
221
|
end
|
205
|
-
|
206
222
|
end
|
207
223
|
|
208
224
|
|
209
|
-
|
210
|
-
|
211
|
-
module EventMachine #:nodoc: all
|
212
|
-
|
225
|
+
module EventMachine
|
226
|
+
# @private
|
213
227
|
class Error < Exception; end
|
214
|
-
|
215
228
|
end
|
216
229
|
|
217
|
-
|
218
|
-
|
219
|
-
module EventMachine #:nodoc: all
|
230
|
+
module EventMachine
|
231
|
+
# @private
|
220
232
|
class Connection
|
233
|
+
# @private
|
221
234
|
def get_outbound_data_size
|
222
235
|
EventMachine::get_outbound_data_size @signature
|
223
236
|
end
|
224
237
|
end
|
225
238
|
end
|
226
239
|
|
227
|
-
|
228
|
-
|
229
|
-
module EventMachine #:nodoc: all
|
240
|
+
module EventMachine
|
230
241
|
|
231
242
|
# Factored out so we can substitute other implementations
|
232
243
|
# here if desired, such as the one in ActiveRBAC.
|
244
|
+
# @private
|
233
245
|
module UuidGenerator
|
234
|
-
|
235
246
|
def self.generate
|
236
247
|
@ix ||= 0
|
237
248
|
@ix += 1
|
238
249
|
end
|
239
|
-
|
240
250
|
end
|
241
|
-
|
242
251
|
end
|
243
252
|
|
244
|
-
#-----------------------------------------------------------------
|
245
|
-
|
246
|
-
module EventMachine #:nodoc: all
|
247
253
|
|
254
|
+
module EventMachine
|
255
|
+
# @private
|
248
256
|
TimerFired = 100
|
257
|
+
# @private
|
249
258
|
ConnectionData = 101
|
259
|
+
# @private
|
250
260
|
ConnectionUnbound = 102
|
261
|
+
# @private
|
251
262
|
ConnectionAccepted = 103
|
263
|
+
# @private
|
252
264
|
ConnectionCompleted = 104
|
265
|
+
# @private
|
253
266
|
LoopbreakSignalled = 105
|
254
|
-
|
255
267
|
end
|
256
268
|
|
257
|
-
|
269
|
+
module EventMachine
|
270
|
+
# @private
|
271
|
+
class Reactor
|
272
|
+
include Singleton
|
258
273
|
|
259
|
-
|
260
|
-
class Reactor
|
261
|
-
include Singleton
|
274
|
+
HeartbeatInterval = 2
|
262
275
|
|
263
|
-
|
276
|
+
attr_reader :current_loop_time
|
264
277
|
|
265
|
-
|
278
|
+
def initialize
|
279
|
+
initialize_for_run
|
280
|
+
end
|
266
281
|
|
267
|
-
|
268
|
-
|
269
|
-
|
282
|
+
def install_oneshot_timer interval
|
283
|
+
uuid = UuidGenerator::generate
|
284
|
+
#@timers << [Time.now + interval, uuid]
|
285
|
+
#@timers.sort! {|a,b| a.first <=> b.first}
|
286
|
+
@timers.add([Time.now + interval, uuid])
|
287
|
+
uuid
|
288
|
+
end
|
270
289
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
290
|
+
# Called before run, this is a good place to clear out arrays
|
291
|
+
# with cruft that may be left over from a previous run.
|
292
|
+
# @private
|
293
|
+
def initialize_for_run
|
294
|
+
@running = false
|
295
|
+
@stop_scheduled = false
|
296
|
+
@selectables ||= {}; @selectables.clear
|
297
|
+
@timers = SortedSet.new # []
|
298
|
+
set_timer_quantum(0.1)
|
299
|
+
@current_loop_time = Time.now
|
300
|
+
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
301
|
+
end
|
280
302
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
@running = false
|
285
|
-
@stop_scheduled = false
|
286
|
-
@selectables ||= {}; @selectables.clear
|
287
|
-
@timers = SortedSet.new # []
|
288
|
-
set_timer_quantum(0.1)
|
289
|
-
@current_loop_time = Time.now
|
290
|
-
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
291
|
-
end
|
303
|
+
def add_selectable io
|
304
|
+
@selectables[io.uuid] = io
|
305
|
+
end
|
292
306
|
|
293
|
-
|
294
|
-
|
295
|
-
|
307
|
+
def get_selectable uuid
|
308
|
+
@selectables[uuid]
|
309
|
+
end
|
296
310
|
|
297
|
-
|
298
|
-
|
299
|
-
|
311
|
+
def run
|
312
|
+
raise Error.new( "already running" ) if @running
|
313
|
+
@running = true
|
300
314
|
|
301
|
-
|
302
|
-
|
303
|
-
@running = true
|
315
|
+
begin
|
316
|
+
open_loopbreaker
|
304
317
|
|
305
|
-
|
306
|
-
|
318
|
+
loop {
|
319
|
+
@current_loop_time = Time.now
|
307
320
|
|
308
|
-
|
309
|
-
|
321
|
+
break if @stop_scheduled
|
322
|
+
run_timers
|
323
|
+
break if @stop_scheduled
|
324
|
+
crank_selectables
|
325
|
+
break if @stop_scheduled
|
326
|
+
run_heartbeats
|
327
|
+
}
|
328
|
+
ensure
|
329
|
+
close_loopbreaker
|
330
|
+
@selectables.each {|k, io| io.close}
|
331
|
+
@selectables.clear
|
310
332
|
|
311
|
-
|
312
|
-
|
313
|
-
break if @stop_scheduled
|
314
|
-
crank_selectables
|
315
|
-
break if @stop_scheduled
|
316
|
-
run_heartbeats
|
317
|
-
}
|
318
|
-
ensure
|
319
|
-
close_loopbreaker
|
320
|
-
@selectables.each {|k, io| io.close}
|
321
|
-
@selectables.clear
|
333
|
+
@running = false
|
334
|
+
end
|
322
335
|
|
323
|
-
@running = false
|
324
336
|
end
|
325
337
|
|
326
|
-
|
338
|
+
def run_timers
|
339
|
+
@timers.each {|t|
|
340
|
+
if t.first <= @current_loop_time
|
341
|
+
@timers.delete t
|
342
|
+
EventMachine::event_callback "", TimerFired, t.last
|
343
|
+
else
|
344
|
+
break
|
345
|
+
end
|
346
|
+
}
|
347
|
+
#while @timers.length > 0 and @timers.first.first <= now
|
348
|
+
# t = @timers.shift
|
349
|
+
# EventMachine::event_callback "", TimerFired, t.last
|
350
|
+
#end
|
351
|
+
end
|
327
352
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
@
|
332
|
-
EventMachine::event_callback "", TimerFired, t.last
|
333
|
-
else
|
334
|
-
break
|
353
|
+
def run_heartbeats
|
354
|
+
if @next_heartbeat <= @current_loop_time
|
355
|
+
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
356
|
+
@selectables.each {|k,io| io.heartbeat}
|
335
357
|
end
|
336
|
-
}
|
337
|
-
#while @timers.length > 0 and @timers.first.first <= now
|
338
|
-
# t = @timers.shift
|
339
|
-
# EventMachine::event_callback "", TimerFired, t.last
|
340
|
-
#end
|
341
|
-
end
|
342
|
-
|
343
|
-
def run_heartbeats
|
344
|
-
if @next_heartbeat <= @current_loop_time
|
345
|
-
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
346
|
-
@selectables.each {|k,io| io.heartbeat}
|
347
358
|
end
|
348
|
-
end
|
349
359
|
|
350
|
-
|
360
|
+
def crank_selectables
|
351
361
|
#$stderr.write 'R'
|
352
362
|
|
353
363
|
readers = @selectables.values.select {|io| io.select_for_reading?}
|
@@ -364,57 +374,55 @@ class Reactor
|
|
364
374
|
true
|
365
375
|
end
|
366
376
|
}
|
367
|
-
|
377
|
+
end
|
368
378
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
379
|
+
# #stop
|
380
|
+
def stop
|
381
|
+
raise Error.new( "not running") unless @running
|
382
|
+
@stop_scheduled = true
|
383
|
+
end
|
384
|
+
|
385
|
+
def open_loopbreaker
|
386
|
+
# Can't use an IO.pipe because they can't be set nonselectable in Windows.
|
387
|
+
# Pick a random localhost UDP port.
|
388
|
+
#@loopbreak_writer.close if @loopbreak_writer
|
389
|
+
#rd,@loopbreak_writer = IO.pipe
|
390
|
+
@loopbreak_reader = UDPSocket.new
|
391
|
+
@loopbreak_writer = UDPSocket.new
|
392
|
+
bound = false
|
393
|
+
100.times {
|
394
|
+
@loopbreak_port = rand(10000) + 40000
|
395
|
+
begin
|
396
|
+
@loopbreak_reader.bind "localhost", @loopbreak_port
|
397
|
+
bound = true
|
398
|
+
break
|
399
|
+
rescue
|
400
|
+
end
|
401
|
+
}
|
402
|
+
raise "Unable to bind Loopbreaker" unless bound
|
403
|
+
LoopbreakReader.new(@loopbreak_reader)
|
404
|
+
end
|
374
405
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
#rd,@loopbreak_writer = IO.pipe
|
380
|
-
@loopbreak_reader = UDPSocket.new
|
381
|
-
@loopbreak_writer = UDPSocket.new
|
382
|
-
bound = false
|
383
|
-
100.times {
|
384
|
-
@loopbreak_port = rand(10000) + 40000
|
385
|
-
begin
|
386
|
-
@loopbreak_reader.bind "localhost", @loopbreak_port
|
387
|
-
bound = true
|
388
|
-
break
|
389
|
-
rescue
|
390
|
-
end
|
391
|
-
}
|
392
|
-
raise "Unable to bind Loopbreaker" unless bound
|
393
|
-
LoopbreakReader.new(@loopbreak_reader)
|
394
|
-
end
|
406
|
+
def close_loopbreaker
|
407
|
+
@loopbreak_writer.close
|
408
|
+
@loopbreak_writer = nil
|
409
|
+
end
|
395
410
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
411
|
+
def signal_loopbreak
|
412
|
+
#@loopbreak_writer.write '+' if @loopbreak_writer
|
413
|
+
@loopbreak_writer.send('+',0,"localhost",@loopbreak_port) if @loopbreak_writer
|
414
|
+
end
|
400
415
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
end
|
416
|
+
def set_timer_quantum interval_in_seconds
|
417
|
+
@timer_quantum = interval_in_seconds
|
418
|
+
end
|
405
419
|
|
406
|
-
def set_timer_quantum interval_in_seconds
|
407
|
-
@timer_quantum = interval_in_seconds
|
408
420
|
end
|
409
421
|
|
410
422
|
end
|
411
423
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
#--------------------------------------------------------------
|
416
|
-
|
417
|
-
class IO #:nodoc: all
|
424
|
+
# @private
|
425
|
+
class IO
|
418
426
|
extend Forwardable
|
419
427
|
def_delegator :@my_selectable, :close_scheduled?
|
420
428
|
def_delegator :@my_selectable, :select_for_reading?
|
@@ -431,9 +439,8 @@ class IO #:nodoc: all
|
|
431
439
|
def_delegator :@my_selectable, :heartbeat
|
432
440
|
end
|
433
441
|
|
434
|
-
|
435
|
-
|
436
|
-
module EventMachine #:nodoc: all
|
442
|
+
module EventMachine
|
443
|
+
# @private
|
437
444
|
class Selectable
|
438
445
|
|
439
446
|
attr_reader :io, :uuid
|
@@ -453,7 +460,7 @@ module EventMachine #:nodoc: all
|
|
453
460
|
s = Socket.for_fd(@io.fileno)
|
454
461
|
s.fcntl( Fcntl::F_SETFL, Fcntl::O_NONBLOCK )
|
455
462
|
rescue Errno::EINVAL, Errno::EBADF
|
456
|
-
|
463
|
+
warn "Serious error: unable to set descriptor non-blocking"
|
457
464
|
end
|
458
465
|
end
|
459
466
|
# TODO, should set CLOEXEC on Unix?
|
@@ -491,11 +498,8 @@ module EventMachine #:nodoc: all
|
|
491
498
|
|
492
499
|
end
|
493
500
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
module EventMachine #:nodoc: all
|
498
|
-
|
501
|
+
module EventMachine
|
502
|
+
# @private
|
499
503
|
class StreamObject < Selectable
|
500
504
|
def initialize io
|
501
505
|
super io
|
@@ -571,10 +575,10 @@ module EventMachine #:nodoc: all
|
|
571
575
|
begin
|
572
576
|
data = data.to_s
|
573
577
|
w = if io.respond_to?(:write_nonblock)
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
+
io.write_nonblock data
|
579
|
+
else
|
580
|
+
io.syswrite data
|
581
|
+
end
|
578
582
|
|
579
583
|
if w < data.length
|
580
584
|
@outbound_q.unshift data[w..-1]
|
@@ -636,7 +640,8 @@ end
|
|
636
640
|
|
637
641
|
|
638
642
|
|
639
|
-
module EventMachine
|
643
|
+
module EventMachine
|
644
|
+
# @private
|
640
645
|
class EvmaTCPClient < StreamObject
|
641
646
|
|
642
647
|
def self.connect bind_addr, bind_port, host, port
|
@@ -683,11 +688,10 @@ module EventMachine #:nodoc: all
|
|
683
688
|
end
|
684
689
|
end
|
685
690
|
|
686
|
-
#--------------------------------------------------------------
|
687
|
-
|
688
691
|
|
689
692
|
|
690
|
-
module EventMachine
|
693
|
+
module EventMachine
|
694
|
+
# @private
|
691
695
|
class EvmaKeyboard < StreamObject
|
692
696
|
|
693
697
|
def self.open
|
@@ -713,11 +717,9 @@ module EventMachine #:nodoc: all
|
|
713
717
|
end
|
714
718
|
|
715
719
|
|
716
|
-
#--------------------------------------------------------------
|
717
|
-
|
718
|
-
|
719
720
|
|
720
|
-
module EventMachine
|
721
|
+
module EventMachine
|
722
|
+
# @private
|
721
723
|
class EvmaUNIXClient < StreamObject
|
722
724
|
|
723
725
|
def self.connect chain
|
@@ -765,7 +767,8 @@ end
|
|
765
767
|
|
766
768
|
#--------------------------------------------------------------
|
767
769
|
|
768
|
-
module EventMachine
|
770
|
+
module EventMachine
|
771
|
+
# @private
|
769
772
|
class EvmaTCPServer < Selectable
|
770
773
|
|
771
774
|
# TODO, refactor and unify with EvmaUNIXServer.
|
@@ -820,7 +823,8 @@ end
|
|
820
823
|
|
821
824
|
#--------------------------------------------------------------
|
822
825
|
|
823
|
-
module EventMachine
|
826
|
+
module EventMachine
|
827
|
+
# @private
|
824
828
|
class EvmaUNIXServer < Selectable
|
825
829
|
|
826
830
|
# TODO, refactor and unify with EvmaTCPServer.
|
@@ -876,7 +880,8 @@ end
|
|
876
880
|
|
877
881
|
#--------------------------------------------------------------
|
878
882
|
|
879
|
-
module EventMachine
|
883
|
+
module EventMachine
|
884
|
+
# @private
|
880
885
|
class LoopbreakReader < Selectable
|
881
886
|
|
882
887
|
def select_for_reading?
|
@@ -884,18 +889,18 @@ module EventMachine #:nodoc: all
|
|
884
889
|
end
|
885
890
|
|
886
891
|
def eventable_read
|
887
|
-
|
888
|
-
|
892
|
+
io.sysread(128)
|
893
|
+
EventMachine::event_callback "", LoopbreakSignalled, ""
|
889
894
|
end
|
890
895
|
|
891
896
|
end
|
892
897
|
end
|
893
898
|
|
894
|
-
#--------------------------------------------------------------
|
895
|
-
|
896
899
|
|
897
|
-
module EventMachine #:nodoc: all
|
898
900
|
|
901
|
+
# @private
|
902
|
+
module EventMachine
|
903
|
+
# @private
|
899
904
|
class DatagramObject < Selectable
|
900
905
|
def initialize io
|
901
906
|
super io
|
@@ -939,9 +944,8 @@ module EventMachine #:nodoc: all
|
|
939
944
|
end
|
940
945
|
|
941
946
|
|
942
|
-
|
943
|
-
|
944
|
-
module EventMachine #:nodoc: all
|
947
|
+
module EventMachine
|
948
|
+
# @private
|
945
949
|
class EvmaUDPSocket < DatagramObject
|
946
950
|
|
947
951
|
class << self
|