eventmachine 0.12.8-x86-mswin32-60 → 0.12.10-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.gitignore +14 -13
  2. data/Rakefile +374 -264
  3. data/eventmachine.gemspec +4 -5
  4. data/ext/binder.cpp +125 -126
  5. data/ext/binder.h +46 -48
  6. data/ext/cmain.cpp +184 -42
  7. data/ext/cplusplus.cpp +202 -202
  8. data/ext/ed.cpp +242 -81
  9. data/ext/ed.h +39 -22
  10. data/ext/em.cpp +127 -108
  11. data/ext/em.h +27 -18
  12. data/ext/emwin.cpp +3 -3
  13. data/ext/eventmachine.h +49 -38
  14. data/ext/eventmachine_cpp.h +96 -96
  15. data/ext/extconf.rb +147 -132
  16. data/ext/fastfilereader/extconf.rb +82 -76
  17. data/ext/project.h +151 -140
  18. data/ext/rubymain.cpp +222 -103
  19. data/ext/ssl.cpp +460 -460
  20. data/ext/ssl.h +94 -94
  21. data/java/src/com/rubyeventmachine/EmReactor.java +570 -423
  22. data/java/src/com/rubyeventmachine/EventableChannel.java +69 -57
  23. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +189 -171
  24. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +364 -244
  25. data/java/src/com/rubyeventmachine/{Application.java → application/Application.java} +194 -200
  26. data/java/src/com/rubyeventmachine/{Connection.java → application/Connection.java} +74 -74
  27. data/java/src/com/rubyeventmachine/{ConnectionFactory.java → application/ConnectionFactory.java} +36 -36
  28. data/java/src/com/rubyeventmachine/{DefaultConnectionFactory.java → application/DefaultConnectionFactory.java} +46 -46
  29. data/java/src/com/rubyeventmachine/{PeriodicTimer.java → application/PeriodicTimer.java} +38 -38
  30. data/java/src/com/rubyeventmachine/{Timer.java → application/Timer.java} +54 -54
  31. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +109 -108
  32. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +148 -146
  33. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +53 -53
  34. data/java/src/com/rubyeventmachine/tests/TestServers.java +75 -74
  35. data/java/src/com/rubyeventmachine/tests/TestTimers.java +90 -89
  36. data/lib/em/connection.rb +71 -12
  37. data/lib/em/deferrable.rb +191 -186
  38. data/lib/em/protocols.rb +36 -35
  39. data/lib/em/protocols/httpclient2.rb +590 -582
  40. data/lib/em/protocols/line_and_text.rb +125 -126
  41. data/lib/em/protocols/linetext2.rb +161 -160
  42. data/lib/em/protocols/object_protocol.rb +45 -39
  43. data/lib/em/protocols/smtpclient.rb +357 -331
  44. data/lib/em/protocols/socks4.rb +66 -0
  45. data/lib/em/queue.rb +60 -60
  46. data/lib/em/timers.rb +56 -55
  47. data/lib/em/version.rb +1 -1
  48. data/lib/eventmachine.rb +125 -169
  49. data/lib/jeventmachine.rb +257 -142
  50. data/tasks/{cpp.rake → cpp.rake_example} +76 -76
  51. data/tests/test_attach.rb +125 -100
  52. data/tests/test_basic.rb +1 -2
  53. data/tests/test_connection_count.rb +34 -44
  54. data/tests/test_epoll.rb +0 -2
  55. data/tests/test_get_sock_opt.rb +30 -0
  56. data/tests/test_httpclient2.rb +3 -3
  57. data/tests/test_inactivity_timeout.rb +21 -1
  58. data/tests/test_ltp.rb +182 -188
  59. data/tests/test_next_tick.rb +0 -2
  60. data/tests/test_pause.rb +70 -0
  61. data/tests/test_pending_connect_timeout.rb +48 -0
  62. data/tests/test_ssl_args.rb +78 -67
  63. data/tests/test_timers.rb +162 -141
  64. metadata +13 -11
  65. data/tasks/project.rake +0 -79
  66. data/tasks/tests.rake +0 -193
@@ -0,0 +1,66 @@
1
+ module EventMachine
2
+ module Protocols
3
+ # Basic SOCKS v4 client implementation
4
+ #
5
+ # Use as you would any regular connection:
6
+ #
7
+ # class MyConn < EM::P::Socks4
8
+ # def post_init
9
+ # send_data("sup")
10
+ # end
11
+ #
12
+ # def receive_data(data)
13
+ # send_data("you said: #{data}")
14
+ # end
15
+ # end
16
+ #
17
+ # EM.connect socks_host, socks_port, MyConn, host, port
18
+ #
19
+ class Socks4 < Connection
20
+ def initialize(host, port)
21
+ @host = Socket.gethostbyname(host).last
22
+ @port = port
23
+ @socks_error_code = nil
24
+ @buffer = ''
25
+ setup_methods
26
+ end
27
+
28
+ def setup_methods
29
+ class << self
30
+ def post_init; socks_post_init; end
31
+ def receive_data(*a); socks_receive_data(*a); end
32
+ end
33
+ end
34
+
35
+ def restore_methods
36
+ class << self
37
+ remove_method :post_init
38
+ remove_method :receive_data
39
+ end
40
+ end
41
+
42
+ def socks_post_init
43
+ header = [4, 1, @port, @host, 0].flatten.pack("CCnA4C")
44
+ send_data(header)
45
+ end
46
+
47
+ def socks_receive_data(data)
48
+ @buffer << data
49
+ return if @buffer.size < 8
50
+
51
+ header_resp = @buffer.slice! 0, 8
52
+ _, r = header_resp.unpack("cc")
53
+ if r != 90
54
+ @socks_error_code = r
55
+ close_connection
56
+ return
57
+ end
58
+
59
+ restore_methods
60
+
61
+ post_init
62
+ receive_data(@buffer) unless @buffer.empty?
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,61 +1,61 @@
1
- module EventMachine
2
- # A cross thread, reactor scheduled, linear queue.
3
- #
4
- # This class provides a simple "Queue" like abstraction on top of the reactor
5
- # scheduler. It services two primary purposes:
6
- # * API sugar for stateful protocols
7
- # * Pushing processing onto the same thread as the reactor
8
- #
9
- # See examples/ex_queue.rb for a detailed example.
10
- #
11
- # q = EM::Queue.new
12
- # q.push('one', 'two', 'three')
13
- # 3.times do
14
- # q.pop{ |msg| puts(msg) }
15
- # end
16
- #
17
- class Queue
18
- # Create a new queue
19
- def initialize
20
- @items = []
21
- @popq = []
22
- end
23
-
24
- # Pop items off the queue, running the block on the reactor thread. The pop
25
- # will not happen immediately, but at some point in the future, either in
26
- # the next tick, if the queue has data, or when the queue is populated.
27
- def pop(*a, &b)
28
- cb = EM::Callback(*a, &b)
29
- EM.schedule do
30
- if @items.empty?
31
- @popq << cb
32
- else
33
- cb.call @items.shift
34
- end
35
- end
36
- nil # Always returns nil
37
- end
38
-
39
- # Push items onto the queue in the reactor thread. The items will not appear
40
- # in the queue immediately, but will be scheduled for addition during the
41
- # next reactor tick.
42
- def push(*items)
43
- EM.schedule do
44
- @items.concat items
45
- @popq.shift.call @items.shift until @items.empty? || @popq.empty?
46
- end
47
- end
48
-
49
- # N.B. This is a peek, it's not thread safe, and may only tend toward
50
- # accuracy.
51
- def empty?
52
- @items.empty?
53
- end
54
-
55
- # N.B. This is a peek, it's not thread safe, and may only tend toward
56
- # accuracy.
57
- def size
58
- @items.size
59
- end
60
- end
1
+ module EventMachine
2
+ # A cross thread, reactor scheduled, linear queue.
3
+ #
4
+ # This class provides a simple "Queue" like abstraction on top of the reactor
5
+ # scheduler. It services two primary purposes:
6
+ # * API sugar for stateful protocols
7
+ # * Pushing processing onto the same thread as the reactor
8
+ #
9
+ # See examples/ex_queue.rb for a detailed example.
10
+ #
11
+ # q = EM::Queue.new
12
+ # q.push('one', 'two', 'three')
13
+ # 3.times do
14
+ # q.pop{ |msg| puts(msg) }
15
+ # end
16
+ #
17
+ class Queue
18
+ # Create a new queue
19
+ def initialize
20
+ @items = []
21
+ @popq = []
22
+ end
23
+
24
+ # Pop items off the queue, running the block on the reactor thread. The pop
25
+ # will not happen immediately, but at some point in the future, either in
26
+ # the next tick, if the queue has data, or when the queue is populated.
27
+ def pop(*a, &b)
28
+ cb = EM::Callback(*a, &b)
29
+ EM.schedule do
30
+ if @items.empty?
31
+ @popq << cb
32
+ else
33
+ cb.call @items.shift
34
+ end
35
+ end
36
+ nil # Always returns nil
37
+ end
38
+
39
+ # Push items onto the queue in the reactor thread. The items will not appear
40
+ # in the queue immediately, but will be scheduled for addition during the
41
+ # next reactor tick.
42
+ def push(*items)
43
+ EM.schedule do
44
+ @items.push(*items)
45
+ @popq.shift.call @items.shift until @items.empty? || @popq.empty?
46
+ end
47
+ end
48
+
49
+ # N.B. This is a peek, it's not thread safe, and may only tend toward
50
+ # accuracy.
51
+ def empty?
52
+ @items.empty?
53
+ end
54
+
55
+ # N.B. This is a peek, it's not thread safe, and may only tend toward
56
+ # accuracy.
57
+ def size
58
+ @items.size
59
+ end
60
+ end
61
61
  end
@@ -1,55 +1,56 @@
1
- module EventMachine
2
- # Creates a one-time timer
3
- #
4
- # timer = EventMachine::Timer.new(5) do
5
- # # this will never fire because we cancel it
6
- # end
7
- # timer.cancel
8
- #
9
- class Timer
10
- # Create a new timer that fires after a given number of seconds
11
- def initialize interval, callback=nil, &block
12
- @signature = EventMachine::add_timer(interval, callback || block)
13
- end
14
-
15
- # Cancel the timer
16
- def cancel
17
- EventMachine.send :cancel_timer, @signature
18
- end
19
- end
20
-
21
- # Creates a periodic timer
22
- #
23
- # n = 0
24
- # timer = EventMachine::PeriodicTimer.new(5) do
25
- # puts "the time is #{Time.now}"
26
- # timer.cancel if (n+=1) > 5
27
- # end
28
- #
29
- class PeriodicTimer
30
- # Create a new periodic timer that executes every interval seconds
31
- def initialize interval, callback=nil, &block
32
- @interval = interval
33
- @code = callback || block
34
- schedule
35
- end
36
-
37
- # Cancel the periodic timer
38
- def cancel
39
- @cancelled = true
40
- end
41
-
42
- # Fire the timer every interval seconds
43
- attr_accessor :interval
44
-
45
- def schedule # :nodoc:
46
- EventMachine::add_timer @interval, proc {self.fire}
47
- end
48
- def fire # :nodoc:
49
- unless @cancelled
50
- @code.call
51
- schedule
52
- end
53
- end
54
- end
55
- end
1
+ module EventMachine
2
+ # Creates a one-time timer
3
+ #
4
+ # timer = EventMachine::Timer.new(5) do
5
+ # # this will never fire because we cancel it
6
+ # end
7
+ # timer.cancel
8
+ #
9
+ class Timer
10
+ # Create a new timer that fires after a given number of seconds
11
+ def initialize interval, callback=nil, &block
12
+ @signature = EventMachine::add_timer(interval, callback || block)
13
+ end
14
+
15
+ # Cancel the timer
16
+ def cancel
17
+ EventMachine.send :cancel_timer, @signature
18
+ end
19
+ end
20
+
21
+ # Creates a periodic timer
22
+ #
23
+ # n = 0
24
+ # timer = EventMachine::PeriodicTimer.new(5) do
25
+ # puts "the time is #{Time.now}"
26
+ # timer.cancel if (n+=1) > 5
27
+ # end
28
+ #
29
+ class PeriodicTimer
30
+ # Create a new periodic timer that executes every interval seconds
31
+ def initialize interval, callback=nil, &block
32
+ @interval = interval
33
+ @code = callback || block
34
+ @cancelled = false
35
+ schedule
36
+ end
37
+
38
+ # Cancel the periodic timer
39
+ def cancel
40
+ @cancelled = true
41
+ end
42
+
43
+ # Fire the timer every interval seconds
44
+ attr_accessor :interval
45
+
46
+ def schedule # :nodoc:
47
+ EventMachine::add_timer @interval, method(:fire)
48
+ end
49
+ def fire # :nodoc:
50
+ unless @cancelled
51
+ @code.call
52
+ schedule
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "0.12.8"
2
+ VERSION = "0.12.10"
3
3
  end
@@ -90,6 +90,7 @@ require 'em/file_watch'
90
90
  require 'em/process_watch'
91
91
 
92
92
  require 'shellwords'
93
+ require 'thread'
93
94
 
94
95
  # == Introduction
95
96
  # EventMachine provides a fast, lightweight framework for implementing
@@ -180,6 +181,18 @@ require 'shellwords'
180
181
  # Interesting thought.
181
182
  #
182
183
  module EventMachine
184
+ class <<self
185
+ # Exposed to allow joining on the thread, when run in a multithreaded
186
+ # environment. Performing other actions on the thread has undefined
187
+ # semantics.
188
+ attr_reader :reactor_thread
189
+ end
190
+ @next_tick_mutex = Mutex.new
191
+ @reactor_running = false
192
+ @next_tick_queue = nil
193
+ @threadpool = nil
194
+
195
+
183
196
  # EventMachine::run initializes and runs an event loop.
184
197
  # This method only returns if user-callback code calls stop_event_loop.
185
198
  # Use the supplied block to define your clients and servers.
@@ -231,6 +244,7 @@ module EventMachine
231
244
  @acceptors = {}
232
245
  @timers = {}
233
246
  @wrapped_exception = nil
247
+ @next_tick_queue ||= []
234
248
  begin
235
249
  @reactor_running = true
236
250
  initialize_event_machine
@@ -241,26 +255,31 @@ module EventMachine
241
255
  @reactor_thread = Thread.current
242
256
  run_machine
243
257
  ensure
258
+ until @tails.empty?
259
+ @tails.pop.call
260
+ end
261
+
244
262
  begin
245
263
  release_machine
246
264
  ensure
247
265
  if @threadpool
248
266
  @threadpool.each { |t| t.exit }
249
- @threadpool.each { |t| t.kill! if t.alive? }
267
+ @threadpool.each do |t|
268
+ next unless t.alive?
269
+ # ruby 1.9 has no kill!
270
+ t.respond_to?(:kill!) ? t.kill! : t.kill
271
+ end
250
272
  @threadqueue = nil
251
273
  @resultqueue = nil
274
+ @threadpool = nil
252
275
  end
253
- @threadpool = nil
276
+
254
277
  @next_tick_queue = nil
255
278
  end
256
279
  @reactor_running = false
257
280
  @reactor_thread = nil
258
281
  end
259
282
 
260
- until @tails.empty?
261
- @tails.pop.call
262
- end
263
-
264
283
  raise @wrapped_exception if @wrapped_exception
265
284
  end
266
285
  end
@@ -381,19 +400,18 @@ module EventMachine
381
400
  def self.add_periodic_timer *args, &block
382
401
  interval = args.shift
383
402
  code = args.shift || block
384
- if code
385
- block_1 = proc {
386
- code.call
387
- EventMachine::add_periodic_timer interval, code
388
- }
389
- add_timer interval, block_1
390
- end
403
+
404
+ EventMachine::PeriodicTimer.new(interval, code)
391
405
  end
392
406
 
393
407
  # Cancel a timer using its signature. You can also use EventMachine::Timer#cancel
394
408
  #
395
- def self.cancel_timer signature
396
- @timers[signature] = false if @timers.has_key?(signature)
409
+ def self.cancel_timer timer_or_sig
410
+ if timer_or_sig.respond_to? :cancel
411
+ timer_or_sig.cancel
412
+ else
413
+ @timers[timer_or_sig] = false if @timers.has_key?(timer_or_sig)
414
+ end
397
415
  end
398
416
 
399
417
 
@@ -548,18 +566,7 @@ module EventMachine
548
566
  port = nil
549
567
  end if port
550
568
 
551
- klass = if (handler and handler.is_a?(Class))
552
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
553
- handler
554
- else
555
- Class.new( Connection ) {handler and include handler}
556
- end
557
-
558
- arity = klass.instance_method(:initialize).arity
559
- expected = arity >= 0 ? arity : -(arity + 1)
560
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
561
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
562
- end
569
+ klass = klass_from_handler(Connection, handler, *args)
563
570
 
564
571
  s = if port
565
572
  start_tcp_server server, port
@@ -614,11 +621,13 @@ module EventMachine
614
621
  # def post_init
615
622
  # send_data "GET / HTTP/1.1\r\nHost: _\r\n\r\n"
616
623
  # @data = ""
624
+ # @parsed = false
617
625
  # end
618
626
  #
619
627
  # def receive_data data
620
628
  # @data << data
621
- # if @data =~ /[\n][\r]*[\n]/m
629
+ # if !@parsed and @data =~ /[\n][\r]*[\n]/m
630
+ # @parsed = true
622
631
  # puts "RECEIVED HTTP HEADER:"
623
632
  # $`.each {|line| puts ">>> #{line}" }
624
633
  #
@@ -679,6 +688,12 @@ module EventMachine
679
688
  # to have them behave differently with respect to post_init
680
689
  # if at all possible.
681
690
  #
691
+ def self.connect server, port=nil, handler=nil, *args, &blk
692
+ bind_connect nil, nil, server, port, handler, *args, &blk
693
+ end
694
+
695
+ # EventMachine::bind_connect is like EventMachine::connect, but allows for a local address/port
696
+ # to bind the connection to.
682
697
  def self.bind_connect bind_addr, bind_port, server, port=nil, handler=nil, *args
683
698
  begin
684
699
  port = Integer(port)
@@ -690,22 +705,11 @@ module EventMachine
690
705
  port = nil
691
706
  end if port
692
707
 
693
- klass = if (handler and handler.is_a?(Class))
694
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
695
- handler
696
- else
697
- Class.new( Connection ) {handler and include handler}
698
- end
699
-
700
- arity = klass.instance_method(:initialize).arity
701
- expected = arity >= 0 ? arity : -(arity + 1)
702
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
703
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
704
- end
708
+ klass = klass_from_handler(Connection, handler, *args)
705
709
 
706
710
  s = if port
707
711
  if bind_addr
708
- bind_connect_server bind_addr, bind_port, server, port
712
+ bind_connect_server bind_addr, bind_port.to_i, server, port
709
713
  else
710
714
  connect_server server, port
711
715
  end
@@ -719,30 +723,25 @@ module EventMachine
719
723
  c
720
724
  end
721
725
 
722
- def self.connect server, port=nil, handler=nil, *args, &blk
723
- bind_connect nil, nil, server, port, handler, *args, &blk
724
- end
725
-
726
- # EventMachine::attach registers a given file descriptor or IO object with the eventloop
726
+ # EventMachine::watch registers a given file descriptor or IO object with the eventloop. The
727
+ # file descriptor will not be modified (it will remain blocking or non-blocking).
728
+ #
729
+ # The eventloop can be used to process readable and writable events on the file descriptor, using
730
+ # EventMachine::Connection#notify_readable= and EventMachine::Connection#notify_writable=
727
731
  #
728
- # If the handler provided has the functions notify_readable or notify_writable defined,
729
- # EventMachine will not read or write from the socket, and instead fire the corresponding
730
- # callback on the handler.
732
+ # EventMachine::Connection#notify_readable? and EventMachine::Connection#notify_writable? can be used
733
+ # to check what events are enabled on the connection.
731
734
  #
732
735
  # To detach the file descriptor, use EventMachine::Connection#detach
733
736
  #
734
737
  # === Usage Example
735
738
  #
736
739
  # module SimpleHttpClient
737
- # def initialize sock
738
- # @sock = sock
739
- # end
740
- #
741
740
  # def notify_readable
742
- # header = @sock.readline
741
+ # header = @io.readline
743
742
  #
744
743
  # if header == "\r\n"
745
- # # detach returns the file descriptor number (fd == @sock.fileno)
744
+ # # detach returns the file descriptor number (fd == @io.fileno)
746
745
  # fd = detach
747
746
  # end
748
747
  # rescue EOFError
@@ -752,7 +751,7 @@ module EventMachine
752
751
  # def unbind
753
752
  # EM.next_tick do
754
753
  # # socket is detached from the eventloop, but still open
755
- # data = @sock.read
754
+ # data = @io.read
756
755
  # end
757
756
  # end
758
757
  # end
@@ -760,31 +759,45 @@ module EventMachine
760
759
  # EM.run{
761
760
  # $sock = TCPSocket.new('site.com', 80)
762
761
  # $sock.write("GET / HTTP/1.0\r\n\r\n")
763
- # EM.attach $sock, SimpleHttpClient, $sock
762
+ # conn = EM.watch $sock, SimpleHttpClient
763
+ # conn.notify_readable = true
764
764
  # }
765
765
  #
766
766
  #--
767
767
  # Thanks to Riham Aldakkak (eSpace Technologies) for the initial patch
768
- def EventMachine::attach io, handler=nil, *args
769
- klass = if (handler and handler.is_a?(Class))
770
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
771
- handler
772
- else
773
- Class.new( Connection ) {handler and include handler}
768
+ def EventMachine::watch io, handler=nil, *args, &blk
769
+ attach_io io, true, handler, *args, &blk
770
+ end
771
+
772
+ # Attaches an IO object or file descriptor to the eventloop as a regular connection.
773
+ # The file descriptor will be set as non-blocking, and EventMachine will process
774
+ # receive_data and send_data events on it as it would for any other connection.
775
+ #
776
+ # To watch a fd instead, use EventMachine::watch, which will not alter the state of the socket
777
+ # and fire notify_readable and notify_writable events instead.
778
+ def EventMachine::attach io, handler=nil, *args, &blk
779
+ attach_io io, false, handler, *args, &blk
780
+ end
781
+
782
+ def EventMachine::attach_io io, watch_mode, handler=nil, *args # :nodoc:
783
+ klass = klass_from_handler(Connection, handler, *args)
784
+
785
+ if !watch_mode and klass.public_instance_methods.any?{|m| [:notify_readable, :notify_writable].include? m.to_sym }
786
+ raise ArgumentError, "notify_readable/writable with EM.attach is not supported. Use EM.watch(io){ |c| c.notify_readable = true }"
774
787
  end
775
788
 
776
- arity = klass.instance_method(:initialize).arity
777
- expected = arity >= 0 ? arity : -(arity + 1)
778
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
779
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
789
+ if io.respond_to?(:fileno)
790
+ fd = defined?(JRuby) ? JRuby.runtime.getDescriptorByFileno(io.fileno).getChannel : io.fileno
791
+ else
792
+ fd = io
780
793
  end
781
794
 
782
- readmode = klass.public_instance_methods.any?{|m| m.to_sym == :notify_readable }
783
- writemode = klass.public_instance_methods.any?{|m| m.to_sym == :notify_writable }
795
+ s = attach_fd fd, watch_mode
796
+ c = klass.new s, *args
784
797
 
785
- s = attach_fd io.respond_to?(:fileno) ? io.fileno : io, readmode, writemode
798
+ c.instance_variable_set(:@io, io)
799
+ c.instance_variable_set(:@fd, fd)
786
800
 
787
- c = klass.new s, *args
788
801
  @conns[s] = c
789
802
  block_given? and yield c
790
803
  c
@@ -793,8 +806,6 @@ module EventMachine
793
806
 
794
807
  # Connect to a given host/port and re-use the provided EventMachine::Connection instance
795
808
  #--
796
- # EXPERIMENTAL. DO NOT RELY ON THIS METHOD TO BE HERE IN THIS FORM, OR AT ALL.
797
- # (03Nov06)
798
809
  # Observe, the test for already-connected FAILS if we call a reconnect inside post_init,
799
810
  # because we haven't set up the connection in @conns by that point.
800
811
  # RESIST THE TEMPTATION to "fix" this problem by redefining the behavior of post_init.
@@ -900,19 +911,7 @@ module EventMachine
900
911
  # out that this originally did not take a class but only a module.
901
912
  #
902
913
  def self.open_datagram_socket address, port, handler=nil, *args
903
- klass = if (handler and handler.is_a?(Class))
904
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
905
- handler
906
- else
907
- Class.new( Connection ) {handler and include handler}
908
- end
909
-
910
- arity = klass.instance_method(:initialize).arity
911
- expected = arity >= 0 ? arity : -(arity + 1)
912
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
913
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
914
- end
915
-
914
+ klass = klass_from_handler(Connection, handler, *args)
916
915
  s = open_udp_socket address, port.to_i
917
916
  c = klass.new s, *args
918
917
  @conns[s] = c
@@ -990,26 +989,11 @@ module EventMachine
990
989
  cback.call result if cback
991
990
  end
992
991
 
993
- @next_tick_queue ||= []
994
- if (l = @next_tick_queue.length) > 0
995
- l.times {|i| @next_tick_queue[i].call}
996
- @next_tick_queue.slice!( 0...l )
992
+ jobs = @next_tick_mutex.synchronize do
993
+ jobs, @next_tick_queue = @next_tick_queue, []
994
+ jobs
997
995
  end
998
-
999
- =begin
1000
- (@next_tick_queue ||= []).length.times {
1001
- cback=@next_tick_queue.pop and cback.call
1002
- }
1003
- =end
1004
- =begin
1005
- if (@next_tick_queue ||= []) and @next_tick_queue.length > 0
1006
- ary = @next_tick_queue.dup
1007
- @next_tick_queue.clear
1008
- until ary.empty?
1009
- cback=ary.pop and cback.call
1010
- end
1011
- end
1012
- =end
996
+ jobs.each { |j| j.call }
1013
997
  end
1014
998
 
1015
999
 
@@ -1069,7 +1053,7 @@ module EventMachine
1069
1053
  end
1070
1054
 
1071
1055
  def self.spawn_threadpool # :nodoc:
1072
- until @threadpool.size == @threadpool_size
1056
+ until @threadpool.size == @threadpool_size.to_i
1073
1057
  thread = Thread.new do
1074
1058
  while true
1075
1059
  op, cback = *@threadqueue.pop
@@ -1106,18 +1090,11 @@ module EventMachine
1106
1090
  # extremely expensive even if they're just sleeping.
1107
1091
  #
1108
1092
  def self.next_tick pr=nil, &block
1109
- raise "no argument or block given" unless ((pr && pr.respond_to?(:call)) or block)
1110
- (@next_tick_queue ||= []) << ( pr || block )
1111
- signal_loopbreak if reactor_running?
1112
- =begin
1113
- (@next_tick_procs ||= []) << (pr || block)
1114
- if @next_tick_procs.length == 1
1115
- add_timer(0) {
1116
- @next_tick_procs.each {|t| t.call}
1117
- @next_tick_procs.clear
1118
- }
1093
+ raise ArgumentError, "no proc or block given" unless ((pr && pr.respond_to?(:call)) or block)
1094
+ @next_tick_mutex.synchronize do
1095
+ (@next_tick_queue ||= []) << ( pr || block )
1119
1096
  end
1120
- =end
1097
+ signal_loopbreak if reactor_running?
1121
1098
  end
1122
1099
 
1123
1100
  # A wrapper over the setuid system call. Particularly useful when opening a network
@@ -1182,13 +1159,7 @@ module EventMachine
1182
1159
  # Perhaps misnamed since the underlying function uses socketpair and is full-duplex.
1183
1160
  #
1184
1161
  def self.popen cmd, handler=nil, *args
1185
- klass = if (handler and handler.is_a?(Class))
1186
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
1187
- handler
1188
- else
1189
- Class.new( Connection ) {handler and include handler}
1190
- end
1191
-
1162
+ klass = klass_from_handler(Connection, handler, *args)
1192
1163
  w = Shellwords::shellwords( cmd )
1193
1164
  w.unshift( w.first ) if w.first
1194
1165
  s = invoke_popen( w )
@@ -1218,18 +1189,7 @@ module EventMachine
1218
1189
  #
1219
1190
  #
1220
1191
  def self.open_keyboard handler=nil, *args
1221
- klass = if (handler and handler.is_a?(Class))
1222
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
1223
- handler
1224
- else
1225
- Class.new( Connection ) {handler and include handler}
1226
- end
1227
-
1228
- arity = klass.instance_method(:initialize).arity
1229
- expected = arity >= 0 ? arity : -(arity + 1)
1230
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
1231
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
1232
- end
1192
+ klass = klass_from_handler(Connection, handler, *args)
1233
1193
 
1234
1194
  s = read_keyboard
1235
1195
  c = klass.new s, *args
@@ -1286,6 +1246,8 @@ module EventMachine
1286
1246
  # end
1287
1247
  # end
1288
1248
  #
1249
+ # EM.kqueue = true if EM.kqueue? # file watching requires kqueue on OSX
1250
+ #
1289
1251
  # EM.run {
1290
1252
  # EM.watch_file("/tmp/foo", Handler)
1291
1253
  # }
@@ -1299,18 +1261,7 @@ module EventMachine
1299
1261
  # Calling #path will always return the filename you originally used.
1300
1262
  #
1301
1263
  def self.watch_file(filename, handler=nil, *args)
1302
- klass = if (handler and handler.is_a?(Class))
1303
- raise ArgumentError, 'must provide module or subclass of EventMachine::FileWatch' unless FileWatch > handler
1304
- handler
1305
- else
1306
- Class.new( FileWatch ) {handler and include handler}
1307
- end
1308
-
1309
- arity = klass.instance_method(:initialize).arity
1310
- expected = arity >= 0 ? arity : -(arity + 1)
1311
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
1312
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
1313
- end
1264
+ klass = klass_from_handler(FileWatch, handler, *args)
1314
1265
 
1315
1266
  s = EM::watch_filename(filename)
1316
1267
  c = klass.new s, *args
@@ -1341,18 +1292,7 @@ module EventMachine
1341
1292
  def self.watch_process(pid, handler=nil, *args)
1342
1293
  pid = pid.to_i
1343
1294
 
1344
- klass = if (handler and handler.is_a?(Class))
1345
- raise ArgumentError, 'must provide module or subclass of EventMachine::ProcessWatch' unless ProcessWatch > handler
1346
- handler
1347
- else
1348
- Class.new( ProcessWatch ) {handler and include handler}
1349
- end
1350
-
1351
- arity = klass.instance_method(:initialize).arity
1352
- expected = arity >= 0 ? arity : -(arity + 1)
1353
- if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
1354
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
1355
- end
1295
+ klass = klass_from_handler(ProcessWatch, handler, *args)
1356
1296
 
1357
1297
  s = EM::watch_pid(pid)
1358
1298
  c = klass.new s, *args
@@ -1429,8 +1369,8 @@ module EventMachine
1429
1369
  # EM.run {
1430
1370
  # EM.start_server("127.0.0.1", 8080, ProxyServer)
1431
1371
  # }
1432
- def self.enable_proxy(from, to)
1433
- EM::start_proxy(from.signature, to.signature)
1372
+ def self.enable_proxy(from, to, bufsize=0)
1373
+ EM::start_proxy(from.signature, to.signature, bufsize)
1434
1374
  end
1435
1375
 
1436
1376
  # disable_proxy takes just one argument, a Connection that has proxying enabled via enable_proxy.
@@ -1495,7 +1435,8 @@ module EventMachine
1495
1435
  c = @conns[conn_binding] or raise ConnectionNotBound, "received ConnectionCompleted for unknown signature: #{conn_binding}"
1496
1436
  c.connection_completed
1497
1437
  ##
1498
- # The remaining code is a fallback for the pure ruby reactor. Usually these events are handled in the C event_callback() in rubymain.cpp
1438
+ # The remaining code is a fallback for the pure ruby and java reactors.
1439
+ # In the C++ reactor, these events are handled in the C event_callback() in rubymain.cpp
1499
1440
  elsif opcode == TimerFired
1500
1441
  t = @timers.delete( data )
1501
1442
  return if t == false # timer cancelled
@@ -1616,12 +1557,7 @@ module EventMachine
1616
1557
  # This is a provisional implementation of a stream-oriented file access object.
1617
1558
  # We also experiment with wrapping up some better exception reporting.
1618
1559
  def self._open_file_for_writing filename, handler=nil # :nodoc:
1619
- klass = if (handler and handler.is_a?(Class))
1620
- raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
1621
- handler
1622
- else
1623
- Class.new( Connection ) {handler and include handler}
1624
- end
1560
+ klass = klass_from_handler(Connection, handler)
1625
1561
 
1626
1562
  s = _write_file filename
1627
1563
  c = klass.new s
@@ -1629,6 +1565,26 @@ module EventMachine
1629
1565
  block_given? and yield c
1630
1566
  c
1631
1567
  end
1568
+
1569
+ private
1570
+ def self.klass_from_handler(klass = Connection, handler = nil, *args)
1571
+ klass = if handler and handler.is_a?(Class)
1572
+ raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
1573
+ handler
1574
+ elsif handler
1575
+ Class.new(klass){ include handler }
1576
+ else
1577
+ klass
1578
+ end
1579
+
1580
+ arity = klass.instance_method(:initialize).arity
1581
+ expected = arity >= 0 ? arity : -(arity + 1)
1582
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
1583
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
1584
+ end
1585
+
1586
+ klass
1587
+ end
1632
1588
  end # module EventMachine
1633
1589
 
1634
1590
  # Save everyone some typing.