eventmachine 1.0.0.beta.3-x86-mingw32 → 1.0.0.beta.4.1-x86-mingw32
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/.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 +48 -56
- data/ext/em.h +12 -2
- data/ext/extconf.rb +3 -3
- data/ext/fastfilereader/extconf.rb +1 -1
- 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 +96 -32
- 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
|