eventmachine 0.9.0 → 0.10.0
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/DEFERRABLES +3 -3
- data/PURE_RUBY +77 -0
- data/ext/cmain.cpp +41 -2
- data/ext/ed.cpp +67 -3
- data/ext/ed.h +4 -1
- data/ext/em.cpp +33 -10
- data/ext/em.h +6 -14
- data/ext/eventmachine.h +4 -1
- data/ext/pipe.cpp +21 -3
- data/ext/rubymain.cpp +38 -1
- data/ext/ssl.cpp +9 -3
- data/lib/em/streamer.rb +1 -3
- data/lib/eventmachine.rb +190 -38
- data/lib/eventmachine_version.rb +2 -2
- data/lib/pr_eventmachine.rb +309 -28
- data/lib/protocols/httpcli2.rb +784 -0
- data/lib/protocols/saslauth.rb +121 -0
- data/lib/protocols/smtpclient.rb +41 -10
- data/lib/protocols/smtpserver.rb +30 -1
- data/tests/test_basic.rb +33 -2
- data/tests/test_epoll.rb +9 -3
- data/tests/test_errors.rb +72 -0
- data/tests/test_httpclient2.rb +132 -0
- data/tests/test_pure.rb +127 -0
- data/tests/test_timers.rb +30 -1
- metadata +37 -32
- data/ext/eee +0 -173
- data/lib/svn-commit.tmp +0 -4
data/lib/eventmachine_version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: eventmachine_version.rb
|
1
|
+
# $Id: eventmachine_version.rb 608 2007-12-09 21:04:39Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -25,7 +25,7 @@
|
|
25
25
|
|
26
26
|
module EventMachine
|
27
27
|
|
28
|
-
VERSION = "0.
|
28
|
+
VERSION = "0.10.0"
|
29
29
|
|
30
30
|
end
|
31
31
|
|
data/lib/pr_eventmachine.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: pr_eventmachine.rb
|
1
|
+
# $Id: pr_eventmachine.rb 604 2007-12-06 12:31:39Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -32,6 +32,7 @@ require 'singleton'
|
|
32
32
|
require 'forwardable'
|
33
33
|
require 'socket'
|
34
34
|
require 'fcntl'
|
35
|
+
require 'set'
|
35
36
|
|
36
37
|
|
37
38
|
module EventMachine
|
@@ -99,6 +100,23 @@ module EventMachine
|
|
99
100
|
s.uuid
|
100
101
|
end
|
101
102
|
|
103
|
+
# #stop_tcp_server
|
104
|
+
def stop_tcp_server sig
|
105
|
+
s = Reactor.instance.get_selectable(sig)
|
106
|
+
s.schedule_close
|
107
|
+
end
|
108
|
+
|
109
|
+
# #start_unix_server
|
110
|
+
def start_unix_server chain
|
111
|
+
(s = EvmaUNIXServer.start_server chain) or raise "no acceptor"
|
112
|
+
s.uuid
|
113
|
+
end
|
114
|
+
|
115
|
+
# #connect_unix_server
|
116
|
+
def connect_unix_server chain
|
117
|
+
EvmaUNIXClient.connect(chain).uuid
|
118
|
+
end
|
119
|
+
|
102
120
|
# #signal_loopbreak
|
103
121
|
def signal_loopbreak
|
104
122
|
Reactor.instance.signal_loopbreak
|
@@ -129,6 +147,54 @@ module EventMachine
|
|
129
147
|
Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
|
130
148
|
end
|
131
149
|
|
150
|
+
# #epoll is a harmless no-op in the pure-Ruby implementation. This is intended to ensure
|
151
|
+
# that user code behaves properly across different EM implementations.
|
152
|
+
def epoll
|
153
|
+
end
|
154
|
+
|
155
|
+
# #set_rlimit_nofile is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
|
156
|
+
# per-process file-descriptor limit.
|
157
|
+
def set_rlimit_nofile n
|
158
|
+
1024
|
159
|
+
end
|
160
|
+
|
161
|
+
# #set_max_timer_count is a harmless no-op in pure Ruby, which doesn't have a built-in limit
|
162
|
+
# on the number of available timers.
|
163
|
+
def set_max_timer_count n
|
164
|
+
end
|
165
|
+
|
166
|
+
# #send_file_data
|
167
|
+
def send_file_data sig, filename
|
168
|
+
sz = File.size(filename)
|
169
|
+
raise "file too large" if sz > 32*1024
|
170
|
+
data =
|
171
|
+
begin
|
172
|
+
File.read filename
|
173
|
+
rescue
|
174
|
+
""
|
175
|
+
end
|
176
|
+
send_data sig, data, data.length
|
177
|
+
end
|
178
|
+
|
179
|
+
# #get_outbound_data_size
|
180
|
+
#
|
181
|
+
def get_outbound_data_size sig
|
182
|
+
r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target"
|
183
|
+
r.get_outbound_data_size
|
184
|
+
end
|
185
|
+
|
186
|
+
# #read_keyboard
|
187
|
+
#
|
188
|
+
def read_keyboard
|
189
|
+
EvmaKeyboard.open.uuid
|
190
|
+
end
|
191
|
+
|
192
|
+
# #set_comm_inactivity_timeout
|
193
|
+
#
|
194
|
+
def set_comm_inactivity_timeout sig, tm
|
195
|
+
r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
|
196
|
+
r.set_inactivity_timeout tm
|
197
|
+
end
|
132
198
|
end
|
133
199
|
|
134
200
|
end
|
@@ -144,6 +210,16 @@ end
|
|
144
210
|
|
145
211
|
#-----------------------------------------------------------------
|
146
212
|
|
213
|
+
module EventMachine
|
214
|
+
class Connection
|
215
|
+
def get_outbound_data_size
|
216
|
+
EventMachine::get_outbound_data_size @signature
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
#-----------------------------------------------------------------
|
222
|
+
|
147
223
|
module EventMachine
|
148
224
|
|
149
225
|
# Factored out so we can substitute other implementations
|
@@ -171,11 +247,11 @@ end
|
|
171
247
|
module EventMachine
|
172
248
|
|
173
249
|
TimerFired = 100
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
250
|
+
ConnectionData = 101
|
251
|
+
ConnectionUnbound = 102
|
252
|
+
ConnectionAccepted = 103
|
253
|
+
ConnectionCompleted = 104
|
254
|
+
LoopbreakSignalled = 105
|
179
255
|
|
180
256
|
end
|
181
257
|
|
@@ -185,14 +261,21 @@ module EventMachine
|
|
185
261
|
class Reactor
|
186
262
|
include Singleton
|
187
263
|
|
264
|
+
HeartbeatInterval = 2
|
265
|
+
|
266
|
+
attr_reader :current_loop_time
|
267
|
+
|
188
268
|
def initialize
|
189
269
|
initialize_for_run
|
190
270
|
end
|
191
271
|
|
272
|
+
#--
|
273
|
+
# Replaced original implementation 05Dec07, was way too slow because of the sort.
|
192
274
|
def install_oneshot_timer interval
|
193
275
|
uuid = UuidGenerator::generate
|
194
|
-
|
195
|
-
|
276
|
+
#@timers << [Time.now + interval, uuid]
|
277
|
+
#@timers.sort! {|a,b| a.first <=> b.first}
|
278
|
+
@timers.add([Time.now + interval, uuid])
|
196
279
|
uuid
|
197
280
|
end
|
198
281
|
|
@@ -202,8 +285,10 @@ class Reactor
|
|
202
285
|
@running = false
|
203
286
|
@stop_scheduled = false
|
204
287
|
@selectables ||= {}; @selectables.clear
|
205
|
-
@timers = []
|
206
|
-
set_timer_quantum(0.
|
288
|
+
@timers = SortedSet.new # []
|
289
|
+
set_timer_quantum(0.1)
|
290
|
+
@current_loop_time = Time.now
|
291
|
+
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
207
292
|
end
|
208
293
|
|
209
294
|
def add_selectable io
|
@@ -217,27 +302,49 @@ class Reactor
|
|
217
302
|
def run
|
218
303
|
raise Error.new( "already running" ) if @running
|
219
304
|
@running = true
|
220
|
-
open_loopbreaker
|
221
305
|
|
222
|
-
|
223
|
-
|
224
|
-
run_timers
|
225
|
-
break if @stop_scheduled
|
226
|
-
crank_selectables
|
227
|
-
}
|
306
|
+
begin
|
307
|
+
open_loopbreaker
|
228
308
|
|
229
|
-
|
230
|
-
|
231
|
-
|
309
|
+
loop {
|
310
|
+
@current_loop_time = Time.now
|
311
|
+
|
312
|
+
break if @stop_scheduled
|
313
|
+
run_timers
|
314
|
+
break if @stop_scheduled
|
315
|
+
crank_selectables
|
316
|
+
break if @stop_scheduled
|
317
|
+
run_heartbeats
|
318
|
+
}
|
319
|
+
ensure
|
320
|
+
close_loopbreaker
|
321
|
+
@selectables.each {|k, io| io.close}
|
322
|
+
@selectables.clear
|
323
|
+
|
324
|
+
@running = false
|
325
|
+
end
|
232
326
|
|
233
|
-
@running = false
|
234
327
|
end
|
235
328
|
|
236
329
|
def run_timers
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
330
|
+
@timers.each {|t|
|
331
|
+
if t.first <= @current_loop_time
|
332
|
+
@timers.delete t
|
333
|
+
EventMachine::event_callback "", TimerFired, t.last
|
334
|
+
else
|
335
|
+
break
|
336
|
+
end
|
337
|
+
}
|
338
|
+
#while @timers.length > 0 and @timers.first.first <= now
|
339
|
+
# t = @timers.shift
|
340
|
+
# EventMachine::event_callback "", TimerFired, t.last
|
341
|
+
#end
|
342
|
+
end
|
343
|
+
|
344
|
+
def run_heartbeats
|
345
|
+
if @next_heartbeat <= @current_loop_time
|
346
|
+
@next_heartbeat = @current_loop_time + HeartbeatInterval
|
347
|
+
@selectables.each {|k,io| io.heartbeat}
|
241
348
|
end
|
242
349
|
end
|
243
350
|
|
@@ -304,6 +411,9 @@ class IO
|
|
304
411
|
def_delegator :@my_selectable, :schedule_close
|
305
412
|
def_delegator :@my_selectable, :get_peername
|
306
413
|
def_delegator :@my_selectable, :send_datagram
|
414
|
+
def_delegator :@my_selectable, :get_outbound_data_size
|
415
|
+
def_delegator :@my_selectable, :set_inactivity_timeout
|
416
|
+
def_delegator :@my_selectable, :heartbeat
|
307
417
|
end
|
308
418
|
|
309
419
|
#--------------------------------------------------------------
|
@@ -316,6 +426,7 @@ module EventMachine
|
|
316
426
|
def initialize io
|
317
427
|
@uuid = UuidGenerator.generate
|
318
428
|
@io = io
|
429
|
+
@last_activity = Reactor.instance.current_loop_time
|
319
430
|
|
320
431
|
m = @io.fcntl(Fcntl::F_GETFL, 0)
|
321
432
|
@io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m)
|
@@ -344,6 +455,12 @@ module EventMachine
|
|
344
455
|
nil
|
345
456
|
end
|
346
457
|
|
458
|
+
def set_inactivity_timeout tm
|
459
|
+
@inactivity_timeout = tm
|
460
|
+
end
|
461
|
+
|
462
|
+
def heartbeat
|
463
|
+
end
|
347
464
|
end
|
348
465
|
|
349
466
|
end
|
@@ -384,9 +501,12 @@ module EventMachine
|
|
384
501
|
# Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
|
385
502
|
# If we have it, then we can read multiple times safely to improve
|
386
503
|
# performance.
|
504
|
+
# The last-activity clock ASSUMES that we only come here when we
|
505
|
+
# have selected readable.
|
387
506
|
# TODO, coalesce multiple reads into a single event.
|
388
507
|
# TODO, do the function check somewhere else and cache it.
|
389
508
|
def eventable_read
|
509
|
+
@last_activity = Reactor.instance.current_loop_time
|
390
510
|
begin
|
391
511
|
if io.respond_to?(:read_nonblock)
|
392
512
|
10.times {
|
@@ -399,7 +519,7 @@ module EventMachine
|
|
399
519
|
end
|
400
520
|
rescue Errno::EAGAIN
|
401
521
|
# no-op
|
402
|
-
rescue Errno::ECONNRESET, EOFError
|
522
|
+
rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError
|
403
523
|
@close_scheduled = true
|
404
524
|
EventMachine::event_callback uuid, ConnectionUnbound, nil
|
405
525
|
end
|
@@ -416,8 +536,11 @@ module EventMachine
|
|
416
536
|
# one busy connection could hog output buffers and slow down other
|
417
537
|
# connections. Also we should coalesce small writes.
|
418
538
|
# URGENT TODO: Coalesce small writes. They are a performance killer.
|
539
|
+
# The last-activity recorder ASSUMES we'll only come here if we've
|
540
|
+
# selected writable.
|
419
541
|
def eventable_write
|
420
542
|
# coalesce the outbound array here, perhaps
|
543
|
+
@last_activity = Reactor.instance.current_loop_time
|
421
544
|
while data = @outbound_q.shift do
|
422
545
|
begin
|
423
546
|
data = data.to_s
|
@@ -433,7 +556,7 @@ module EventMachine
|
|
433
556
|
end
|
434
557
|
rescue Errno::EAGAIN
|
435
558
|
@outbound_q.unshift data
|
436
|
-
rescue EOFError, Errno::ECONNRESET
|
559
|
+
rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED
|
437
560
|
@close_scheduled = true
|
438
561
|
@outbound_q.clear
|
439
562
|
end
|
@@ -467,6 +590,16 @@ module EventMachine
|
|
467
590
|
io.getpeername
|
468
591
|
end
|
469
592
|
|
593
|
+
# #get_outbound_data_size
|
594
|
+
def get_outbound_data_size
|
595
|
+
@outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
|
596
|
+
end
|
597
|
+
|
598
|
+
def heartbeat
|
599
|
+
if @inactivity_timeout and (@last_activity + @inactivity_timeout) < Reactor.instance.current_loop_time
|
600
|
+
schedule_close true
|
601
|
+
end
|
602
|
+
end
|
470
603
|
end
|
471
604
|
|
472
605
|
|
@@ -509,7 +642,88 @@ module EventMachine
|
|
509
642
|
def eventable_write
|
510
643
|
if @pending
|
511
644
|
@pending = false
|
512
|
-
|
645
|
+
if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
|
646
|
+
EventMachine::event_callback uuid, ConnectionCompleted, ""
|
647
|
+
end
|
648
|
+
else
|
649
|
+
super
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
|
654
|
+
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
#--------------------------------------------------------------
|
659
|
+
|
660
|
+
|
661
|
+
|
662
|
+
module EventMachine
|
663
|
+
class EvmaKeyboard < StreamObject
|
664
|
+
|
665
|
+
def self.open
|
666
|
+
EvmaKeyboard.new STDIN
|
667
|
+
end
|
668
|
+
|
669
|
+
|
670
|
+
def initialize io
|
671
|
+
super
|
672
|
+
end
|
673
|
+
|
674
|
+
|
675
|
+
def select_for_writing?
|
676
|
+
false
|
677
|
+
end
|
678
|
+
|
679
|
+
def select_for_reading?
|
680
|
+
true
|
681
|
+
end
|
682
|
+
|
683
|
+
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
|
688
|
+
#--------------------------------------------------------------
|
689
|
+
|
690
|
+
|
691
|
+
|
692
|
+
module EventMachine
|
693
|
+
class EvmaUNIXClient < StreamObject
|
694
|
+
|
695
|
+
def self.connect chain
|
696
|
+
sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
|
697
|
+
begin
|
698
|
+
# TODO, this assumes a current Ruby snapshot.
|
699
|
+
# We need to degrade to a nonblocking connect otherwise.
|
700
|
+
sd.connect_nonblock( Socket.pack_sockaddr_un( chain ))
|
701
|
+
rescue Errno::EINPROGRESS
|
702
|
+
end
|
703
|
+
EvmaUNIXClient.new sd
|
704
|
+
end
|
705
|
+
|
706
|
+
|
707
|
+
def initialize io
|
708
|
+
super
|
709
|
+
@pending = true
|
710
|
+
end
|
711
|
+
|
712
|
+
|
713
|
+
def select_for_writing?
|
714
|
+
@pending ? true : super
|
715
|
+
end
|
716
|
+
|
717
|
+
def select_for_reading?
|
718
|
+
@pending ? false : super
|
719
|
+
end
|
720
|
+
|
721
|
+
def eventable_write
|
722
|
+
if @pending
|
723
|
+
@pending = false
|
724
|
+
if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
|
725
|
+
EventMachine::event_callback uuid, ConnectionCompleted, ""
|
726
|
+
end
|
513
727
|
else
|
514
728
|
super
|
515
729
|
end
|
@@ -526,6 +740,8 @@ end
|
|
526
740
|
module EventMachine
|
527
741
|
class EvmaTCPServer < Selectable
|
528
742
|
|
743
|
+
# TODO, refactor and unify with EvmaUNIXServer.
|
744
|
+
|
529
745
|
class << self
|
530
746
|
# Versions of ruby 1.8.4 later than May 26 2006 will work properly
|
531
747
|
# with an object of type TCPServer. Prior versions won't so we
|
@@ -564,6 +780,66 @@ module EventMachine
|
|
564
780
|
end
|
565
781
|
end
|
566
782
|
|
783
|
+
#--
|
784
|
+
#
|
785
|
+
def schedule_close
|
786
|
+
@close_scheduled = true
|
787
|
+
end
|
788
|
+
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
|
793
|
+
#--------------------------------------------------------------
|
794
|
+
|
795
|
+
module EventMachine
|
796
|
+
class EvmaUNIXServer < Selectable
|
797
|
+
|
798
|
+
# TODO, refactor and unify with EvmaTCPServer.
|
799
|
+
|
800
|
+
class << self
|
801
|
+
# Versions of ruby 1.8.4 later than May 26 2006 will work properly
|
802
|
+
# with an object of type TCPServer. Prior versions won't so we
|
803
|
+
# play it safe and just build a socket.
|
804
|
+
#
|
805
|
+
def start_server chain
|
806
|
+
sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
|
807
|
+
sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
|
808
|
+
sd.bind( Socket.pack_sockaddr_un( chain ))
|
809
|
+
sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
|
810
|
+
EvmaUNIXServer.new sd
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
def initialize io
|
815
|
+
super io
|
816
|
+
end
|
817
|
+
|
818
|
+
|
819
|
+
def select_for_reading?
|
820
|
+
true
|
821
|
+
end
|
822
|
+
|
823
|
+
#--
|
824
|
+
# accept_nonblock returns an array consisting of the accepted
|
825
|
+
# socket and a sockaddr_in which names the peer.
|
826
|
+
# Don't accept more than 10 at a time.
|
827
|
+
def eventable_read
|
828
|
+
begin
|
829
|
+
10.times {
|
830
|
+
descriptor,peername = io.accept_nonblock
|
831
|
+
sd = StreamObject.new descriptor
|
832
|
+
EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
|
833
|
+
}
|
834
|
+
rescue Errno::EWOULDBLOCK, Errno::EAGAIN
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
#--
|
839
|
+
#
|
840
|
+
def schedule_close
|
841
|
+
@close_scheduled = true
|
842
|
+
end
|
567
843
|
|
568
844
|
end
|
569
845
|
end
|
@@ -623,6 +899,11 @@ module EventMachine
|
|
623
899
|
true
|
624
900
|
end
|
625
901
|
|
902
|
+
# #get_outbound_data_size
|
903
|
+
def get_outbound_data_size
|
904
|
+
@outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
|
905
|
+
end
|
906
|
+
|
626
907
|
|
627
908
|
end
|
628
909
|
|