eventmachine 1.0.0.beta.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.gitignore +16 -0
  2. data/Gemfile +1 -0
  3. data/README +81 -0
  4. data/Rakefile +11 -0
  5. data/docs/COPYING +60 -0
  6. data/docs/ChangeLog +211 -0
  7. data/docs/DEFERRABLES +246 -0
  8. data/docs/EPOLL +141 -0
  9. data/docs/GNU +281 -0
  10. data/docs/INSTALL +13 -0
  11. data/docs/KEYBOARD +42 -0
  12. data/docs/LEGAL +25 -0
  13. data/docs/LIGHTWEIGHT_CONCURRENCY +130 -0
  14. data/docs/PURE_RUBY +75 -0
  15. data/docs/RELEASE_NOTES +94 -0
  16. data/docs/SMTP +4 -0
  17. data/docs/SPAWNED_PROCESSES +148 -0
  18. data/docs/TODO +8 -0
  19. data/eventmachine.gemspec +33 -0
  20. data/examples/ex_channel.rb +43 -0
  21. data/examples/ex_queue.rb +2 -0
  22. data/examples/ex_tick_loop_array.rb +15 -0
  23. data/examples/ex_tick_loop_counter.rb +32 -0
  24. data/examples/helper.rb +2 -0
  25. data/ext/binder.cpp +124 -0
  26. data/ext/binder.h +46 -0
  27. data/ext/cmain.cpp +838 -0
  28. data/ext/ed.cpp +1884 -0
  29. data/ext/ed.h +418 -0
  30. data/ext/em.cpp +2348 -0
  31. data/ext/em.h +228 -0
  32. data/ext/eventmachine.h +123 -0
  33. data/ext/extconf.rb +157 -0
  34. data/ext/fastfilereader/extconf.rb +85 -0
  35. data/ext/fastfilereader/mapper.cpp +214 -0
  36. data/ext/fastfilereader/mapper.h +59 -0
  37. data/ext/fastfilereader/rubymain.cpp +127 -0
  38. data/ext/kb.cpp +79 -0
  39. data/ext/page.cpp +107 -0
  40. data/ext/page.h +51 -0
  41. data/ext/pipe.cpp +347 -0
  42. data/ext/project.h +155 -0
  43. data/ext/rubymain.cpp +1200 -0
  44. data/ext/ssl.cpp +460 -0
  45. data/ext/ssl.h +94 -0
  46. data/java/.classpath +8 -0
  47. data/java/.project +17 -0
  48. data/java/src/com/rubyeventmachine/EmReactor.java +571 -0
  49. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  50. data/java/src/com/rubyeventmachine/EventableChannel.java +69 -0
  51. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +189 -0
  52. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +364 -0
  53. data/lib/em/buftok.rb +138 -0
  54. data/lib/em/callback.rb +26 -0
  55. data/lib/em/channel.rb +57 -0
  56. data/lib/em/connection.rb +569 -0
  57. data/lib/em/deferrable.rb +206 -0
  58. data/lib/em/file_watch.rb +54 -0
  59. data/lib/em/future.rb +61 -0
  60. data/lib/em/iterator.rb +270 -0
  61. data/lib/em/messages.rb +66 -0
  62. data/lib/em/process_watch.rb +44 -0
  63. data/lib/em/processes.rb +119 -0
  64. data/lib/em/protocols.rb +36 -0
  65. data/lib/em/protocols/header_and_content.rb +138 -0
  66. data/lib/em/protocols/httpclient.rb +268 -0
  67. data/lib/em/protocols/httpclient2.rb +590 -0
  68. data/lib/em/protocols/line_and_text.rb +125 -0
  69. data/lib/em/protocols/line_protocol.rb +28 -0
  70. data/lib/em/protocols/linetext2.rb +161 -0
  71. data/lib/em/protocols/memcache.rb +323 -0
  72. data/lib/em/protocols/object_protocol.rb +45 -0
  73. data/lib/em/protocols/postgres3.rb +247 -0
  74. data/lib/em/protocols/saslauth.rb +175 -0
  75. data/lib/em/protocols/smtpclient.rb +357 -0
  76. data/lib/em/protocols/smtpserver.rb +640 -0
  77. data/lib/em/protocols/socks4.rb +66 -0
  78. data/lib/em/protocols/stomp.rb +200 -0
  79. data/lib/em/protocols/tcptest.rb +53 -0
  80. data/lib/em/pure_ruby.rb +1013 -0
  81. data/lib/em/queue.rb +62 -0
  82. data/lib/em/spawnable.rb +85 -0
  83. data/lib/em/streamer.rb +130 -0
  84. data/lib/em/tick_loop.rb +85 -0
  85. data/lib/em/timers.rb +57 -0
  86. data/lib/em/version.rb +3 -0
  87. data/lib/eventmachine.rb +1548 -0
  88. data/lib/jeventmachine.rb +258 -0
  89. data/lib/rubyeventmachine.rb +2 -0
  90. data/setup.rb +1585 -0
  91. data/tasks/cpp.rake_example +77 -0
  92. data/tasks/doc.rake +30 -0
  93. data/tasks/package.rake +85 -0
  94. data/tasks/test.rake +6 -0
  95. data/tests/client.crt +31 -0
  96. data/tests/client.key +51 -0
  97. data/tests/test_attach.rb +136 -0
  98. data/tests/test_basic.rb +249 -0
  99. data/tests/test_channel.rb +64 -0
  100. data/tests/test_connection_count.rb +35 -0
  101. data/tests/test_defer.rb +49 -0
  102. data/tests/test_deferrable.rb +35 -0
  103. data/tests/test_epoll.rb +160 -0
  104. data/tests/test_error_handler.rb +35 -0
  105. data/tests/test_errors.rb +82 -0
  106. data/tests/test_exc.rb +55 -0
  107. data/tests/test_file_watch.rb +49 -0
  108. data/tests/test_futures.rb +198 -0
  109. data/tests/test_get_sock_opt.rb +30 -0
  110. data/tests/test_handler_check.rb +37 -0
  111. data/tests/test_hc.rb +190 -0
  112. data/tests/test_httpclient.rb +227 -0
  113. data/tests/test_httpclient2.rb +154 -0
  114. data/tests/test_inactivity_timeout.rb +50 -0
  115. data/tests/test_kb.rb +60 -0
  116. data/tests/test_ltp.rb +190 -0
  117. data/tests/test_ltp2.rb +317 -0
  118. data/tests/test_next_tick.rb +133 -0
  119. data/tests/test_object_protocol.rb +37 -0
  120. data/tests/test_pause.rb +70 -0
  121. data/tests/test_pending_connect_timeout.rb +48 -0
  122. data/tests/test_process_watch.rb +50 -0
  123. data/tests/test_processes.rb +128 -0
  124. data/tests/test_proxy_connection.rb +144 -0
  125. data/tests/test_pure.rb +134 -0
  126. data/tests/test_queue.rb +44 -0
  127. data/tests/test_running.rb +42 -0
  128. data/tests/test_sasl.rb +72 -0
  129. data/tests/test_send_file.rb +251 -0
  130. data/tests/test_servers.rb +76 -0
  131. data/tests/test_smtpclient.rb +83 -0
  132. data/tests/test_smtpserver.rb +85 -0
  133. data/tests/test_spawn.rb +322 -0
  134. data/tests/test_ssl_args.rb +79 -0
  135. data/tests/test_ssl_methods.rb +50 -0
  136. data/tests/test_ssl_verify.rb +82 -0
  137. data/tests/test_tick_loop.rb +59 -0
  138. data/tests/test_timers.rb +160 -0
  139. data/tests/test_ud.rb +36 -0
  140. data/tests/testem.rb +31 -0
  141. metadata +240 -0
@@ -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
@@ -0,0 +1,200 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 15 November 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ # Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol).
31
+ #
32
+ # == Usage example
33
+ #
34
+ # module StompClient
35
+ # include EM::Protocols::Stomp
36
+ #
37
+ # def connection_completed
38
+ # connect :login => 'guest', :passcode => 'guest'
39
+ # end
40
+ #
41
+ # def receive_msg msg
42
+ # if msg.command == "CONNECTED"
43
+ # subscribe '/some/topic'
44
+ # else
45
+ # p ['got a message', msg]
46
+ # puts msg.body
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # EM.run{
52
+ # EM.connect 'localhost', 61613, StompClient
53
+ # }
54
+ #
55
+ module Stomp
56
+ include LineText2
57
+
58
+ class Message
59
+ # The command associated with the message, usually 'CONNECTED' or 'MESSAGE'
60
+ attr_accessor :command
61
+ # Hash containing headers such as destination and message-id
62
+ attr_accessor :header
63
+ alias :headers :header
64
+ # Body of the message
65
+ attr_accessor :body
66
+
67
+ def initialize # :nodoc:
68
+ @header = {}
69
+ @state = :precommand
70
+ @content_length = nil
71
+ end
72
+ def consume_line line # :nodoc:
73
+ if @state == :precommand
74
+ unless line =~ /\A\s*\Z/
75
+ @command = line
76
+ @state = :headers
77
+ end
78
+ elsif @state == :headers
79
+ if line == ""
80
+ if @content_length
81
+ yield( [:sized_text, @content_length+1] )
82
+ else
83
+ @state = :body
84
+ yield( [:unsized_text] )
85
+ end
86
+ elsif line =~ /\A([^:]+):(.+)\Z/
87
+ k = $1.dup.strip
88
+ v = $2.dup.strip
89
+ @header[k] = v
90
+ if k == "content-length"
91
+ @content_length = v.to_i
92
+ end
93
+ else
94
+ # This is a protocol error. How to signal it?
95
+ end
96
+ elsif @state == :body
97
+ @body = line
98
+ yield( [:dispatch] )
99
+ end
100
+ end
101
+ end
102
+
103
+ # :stopdoc:
104
+
105
+ def send_frame verb, headers={}, body=""
106
+ ary = [verb, "\n"]
107
+ headers.each {|k,v| ary << "#{k}:#{v}\n" }
108
+ ary << "content-length: #{body.to_s.length}\n"
109
+ ary << "content-type: text/plain; charset=UTF-8\n" unless headers.has_key? 'content-type'
110
+ ary << "\n"
111
+ ary << body.to_s
112
+ ary << "\0"
113
+ send_data ary.join
114
+ end
115
+
116
+ def receive_line line
117
+ @stomp_initialized || init_message_reader
118
+ @stomp_message.consume_line(line) {|outcome|
119
+ if outcome.first == :sized_text
120
+ set_text_mode outcome[1]
121
+ elsif outcome.first == :unsized_text
122
+ set_delimiter "\0"
123
+ elsif outcome.first == :dispatch
124
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
125
+ init_message_reader
126
+ end
127
+ }
128
+ end
129
+
130
+ def receive_binary_data data
131
+ @stomp_message.body = data[0..-2]
132
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
133
+ init_message_reader
134
+ end
135
+
136
+ def init_message_reader
137
+ @stomp_initialized = true
138
+ set_delimiter "\n"
139
+ set_line_mode
140
+ @stomp_message = Message.new
141
+ end
142
+
143
+ # :startdoc:
144
+
145
+ # Invoked with an incoming Stomp::Message received from the STOMP server
146
+ def receive_msg msg
147
+ # stub, overwrite this in your handler
148
+ end
149
+
150
+ # CONNECT command, for authentication
151
+ #
152
+ # connect :login => 'guest', :passcode => 'guest'
153
+ #
154
+ def connect parms={}
155
+ send_frame "CONNECT", parms
156
+ end
157
+
158
+ # SEND command, for publishing messages to a topic
159
+ #
160
+ # send '/topic/name', 'some message here'
161
+ #
162
+ def send destination, body, parms={}
163
+ send_frame "SEND", parms.merge( :destination=>destination ), body.to_s
164
+ end
165
+
166
+ # SUBSCRIBE command, for subscribing to topics
167
+ #
168
+ # subscribe '/topic/name', false
169
+ #
170
+ def subscribe dest, ack=false
171
+ send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")}
172
+ end
173
+
174
+ # ACK command, for acknowledging receipt of messages
175
+ #
176
+ # module StompClient
177
+ # include EM::P::Stomp
178
+ #
179
+ # def connection_completed
180
+ # connect :login => 'guest', :passcode => 'guest'
181
+ # # subscribe with ack mode
182
+ # subscribe '/some/topic', true
183
+ # end
184
+ #
185
+ # def receive_msg msg
186
+ # if msg.command == "MESSAGE"
187
+ # ack msg.headers['message-id']
188
+ # puts msg.body
189
+ # end
190
+ # end
191
+ # end
192
+ #
193
+ def ack msgid
194
+ send_frame "ACK", 'message-id'=> msgid
195
+ end
196
+
197
+ end
198
+ end
199
+ end
200
+
@@ -0,0 +1,53 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ class TcpConnectTester < Connection # :nodoc:
31
+ include EventMachine::Deferrable
32
+
33
+ def self.test( host, port )
34
+ EventMachine.connect( host, port, self )
35
+ end
36
+
37
+ def post_init
38
+ @start_time = Time.now
39
+ end
40
+
41
+ def connection_completed
42
+ @completed = true
43
+ set_deferred_status :succeeded, (Time.now - @start_time)
44
+ close_connection
45
+ end
46
+
47
+ def unbind
48
+ set_deferred_status :failed, (Time.now - @start_time) unless @completed
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,1013 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 Apr 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #-------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ # TODO List:
27
+ # TCP-connects currently assume non-blocking connect is available- need to
28
+ # degrade automatically on versions of Ruby prior to June 2006.
29
+ #
30
+
31
+ require 'singleton'
32
+ require 'forwardable'
33
+ require 'socket'
34
+ require 'fcntl'
35
+ require 'set'
36
+
37
+ module EventMachine
38
+ class << self
39
+ # This is mostly useful for automated tests.
40
+ # Return a distinctive symbol so the caller knows whether he's dealing
41
+ # with an extension or with a pure-Ruby library.
42
+ def library_type
43
+ :pure_ruby
44
+ end
45
+
46
+ # #initialize_event_machine
47
+ def initialize_event_machine
48
+ Reactor.instance.initialize_for_run
49
+ end
50
+
51
+ # #add_oneshot_timer
52
+ #--
53
+ # Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby
54
+ # processor still wants them in seconds.
55
+ def add_oneshot_timer interval
56
+ Reactor.instance.install_oneshot_timer(interval / 1000)
57
+ end
58
+
59
+ # run_machine
60
+ def run_machine
61
+ Reactor.instance.run
62
+ end
63
+
64
+ # release_machine. Probably a no-op.
65
+ def release_machine
66
+ end
67
+
68
+ # #stop
69
+ def stop
70
+ Reactor.instance.stop
71
+ end
72
+
73
+ # #connect_server. Return a connection descriptor to the caller.
74
+ # TODO, what do we return here if we can't connect?
75
+ def connect_server host, port
76
+ bind_connect_server nil, nil, host, port
77
+ end
78
+
79
+ def bind_connect_server bind_addr, bind_port, host, port
80
+ EvmaTCPClient.connect(bind_addr, bind_port, host, port).uuid
81
+ end
82
+
83
+ # #send_data
84
+ def send_data target, data, datalength
85
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
86
+ selectable.send_data data
87
+ end
88
+
89
+ # #close_connection
90
+ # The extension version does NOT raise any kind of an error if an attempt is made
91
+ # to close a non-existent connection. Not sure whether we should. For now, we'll
92
+ # raise an error here in that case.
93
+ def close_connection target, after_writing
94
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown close_connection target"
95
+ selectable.schedule_close after_writing
96
+ end
97
+
98
+ # #start_tcp_server
99
+ def start_tcp_server host, port
100
+ (s = EvmaTCPServer.start_server host, port) or raise "no acceptor"
101
+ s.uuid
102
+ end
103
+
104
+ # #stop_tcp_server
105
+ def stop_tcp_server sig
106
+ s = Reactor.instance.get_selectable(sig)
107
+ s.schedule_close
108
+ end
109
+
110
+ # #start_unix_server
111
+ def start_unix_server chain
112
+ (s = EvmaUNIXServer.start_server chain) or raise "no acceptor"
113
+ s.uuid
114
+ end
115
+
116
+ # #connect_unix_server
117
+ def connect_unix_server chain
118
+ EvmaUNIXClient.connect(chain).uuid
119
+ end
120
+
121
+ # #signal_loopbreak
122
+ def signal_loopbreak
123
+ Reactor.instance.signal_loopbreak
124
+ end
125
+
126
+ # #get_peername
127
+ def get_peername sig
128
+ selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target"
129
+ selectable.get_peername
130
+ end
131
+
132
+ # #open_udp_socket
133
+ def open_udp_socket host, port
134
+ EvmaUDPSocket.create(host, port).uuid
135
+ end
136
+
137
+ # #send_datagram. This is currently only for UDP!
138
+ # We need to make it work with unix-domain sockets as well.
139
+ def send_datagram target, data, datalength, host, port
140
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
141
+ selectable.send_datagram data, Socket::pack_sockaddr_in(port, host)
142
+ end
143
+
144
+
145
+ # #set_timer_quantum in milliseconds. The underlying Reactor function wants a (possibly
146
+ # fractional) number of seconds.
147
+ def set_timer_quantum interval
148
+ Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
149
+ end
150
+
151
+ # #epoll is a harmless no-op in the pure-Ruby implementation. This is intended to ensure
152
+ # that user code behaves properly across different EM implementations.
153
+ def epoll
154
+ end
155
+
156
+ # #ssl? is not implemented for pure-Ruby implementation
157
+ def ssl?
158
+ false
159
+ end
160
+
161
+ # #set_rlimit_nofile is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
162
+ # per-process file-descriptor limit.
163
+ def set_rlimit_nofile n
164
+ 1024
165
+ end
166
+
167
+ # #set_max_timer_count is a harmless no-op in pure Ruby, which doesn't have a built-in limit
168
+ # on the number of available timers.
169
+ def set_max_timer_count n
170
+ end
171
+
172
+ # #send_file_data
173
+ def send_file_data sig, filename
174
+ sz = File.size(filename)
175
+ raise "file too large" if sz > 32*1024
176
+ data =
177
+ begin
178
+ File.read filename
179
+ rescue
180
+ ""
181
+ end
182
+ send_data sig, data, data.length
183
+ end
184
+
185
+ # #get_outbound_data_size
186
+ #
187
+ def get_outbound_data_size sig
188
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target"
189
+ r.get_outbound_data_size
190
+ end
191
+
192
+ # #read_keyboard
193
+ #
194
+ def read_keyboard
195
+ EvmaKeyboard.open.uuid
196
+ end
197
+
198
+ # #set_comm_inactivity_timeout
199
+ #
200
+ def set_comm_inactivity_timeout sig, tm
201
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
202
+ r.set_inactivity_timeout tm
203
+ end
204
+ end
205
+
206
+ end
207
+
208
+
209
+ #-----------------------------------------------------------------
210
+
211
+ module EventMachine
212
+
213
+ class Error < Exception; end
214
+
215
+ end
216
+
217
+ #-----------------------------------------------------------------
218
+
219
+ module EventMachine
220
+ class Connection
221
+ def get_outbound_data_size
222
+ EventMachine::get_outbound_data_size @signature
223
+ end
224
+ end
225
+ end
226
+
227
+ #-----------------------------------------------------------------
228
+
229
+ module EventMachine
230
+
231
+ # Factored out so we can substitute other implementations
232
+ # here if desired, such as the one in ActiveRBAC.
233
+ module UuidGenerator
234
+
235
+ def self.generate
236
+ @ix ||= 0
237
+ @ix += 1
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ #-----------------------------------------------------------------
245
+
246
+ module EventMachine
247
+
248
+ TimerFired = 100
249
+ ConnectionData = 101
250
+ ConnectionUnbound = 102
251
+ ConnectionAccepted = 103
252
+ ConnectionCompleted = 104
253
+ LoopbreakSignalled = 105
254
+
255
+ end
256
+
257
+ #-----------------------------------------------------------------
258
+
259
+ module EventMachine
260
+ class Reactor
261
+ include Singleton
262
+
263
+ HeartbeatInterval = 2
264
+
265
+ attr_reader :current_loop_time
266
+
267
+ def initialize
268
+ initialize_for_run
269
+ end
270
+
271
+ #--
272
+ # Replaced original implementation 05Dec07, was way too slow because of the sort.
273
+ def install_oneshot_timer interval
274
+ uuid = UuidGenerator::generate
275
+ #@timers << [Time.now + interval, uuid]
276
+ #@timers.sort! {|a,b| a.first <=> b.first}
277
+ @timers.add([Time.now + interval, uuid])
278
+ uuid
279
+ end
280
+
281
+ # Called before run, this is a good place to clear out arrays
282
+ # with cruft that may be left over from a previous run.
283
+ def initialize_for_run
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
292
+
293
+ def add_selectable io
294
+ @selectables[io.uuid] = io
295
+ end
296
+
297
+ def get_selectable uuid
298
+ @selectables[uuid]
299
+ end
300
+
301
+ def run
302
+ raise Error.new( "already running" ) if @running
303
+ @running = true
304
+
305
+ begin
306
+ open_loopbreaker
307
+
308
+ loop {
309
+ @current_loop_time = Time.now
310
+
311
+ break if @stop_scheduled
312
+ run_timers
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
322
+
323
+ @running = false
324
+ end
325
+
326
+ end
327
+
328
+ def run_timers
329
+ @timers.each {|t|
330
+ if t.first <= @current_loop_time
331
+ @timers.delete t
332
+ EventMachine::event_callback "", TimerFired, t.last
333
+ else
334
+ break
335
+ 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
+ end
348
+ end
349
+
350
+ def crank_selectables
351
+ #$stderr.write 'R'
352
+
353
+ readers = @selectables.values.select {|io| io.select_for_reading?}
354
+ writers = @selectables.values.select {|io| io.select_for_writing?}
355
+
356
+ s = select( readers, writers, nil, @timer_quantum)
357
+
358
+ s and s[1] and s[1].each {|w| w.eventable_write }
359
+ s and s[0] and s[0].each {|r| r.eventable_read }
360
+
361
+ @selectables.delete_if {|k,io|
362
+ if io.close_scheduled?
363
+ io.close
364
+ true
365
+ end
366
+ }
367
+ end
368
+
369
+ # #stop
370
+ def stop
371
+ raise Error.new( "not running") unless @running
372
+ @stop_scheduled = true
373
+ end
374
+
375
+ def open_loopbreaker
376
+ # Can't use an IO.pipe because they can't be set nonselectable in Windows.
377
+ # Pick a random localhost UDP port.
378
+ #@loopbreak_writer.close if @loopbreak_writer
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
395
+
396
+ def close_loopbreaker
397
+ @loopbreak_writer.close
398
+ @loopbreak_writer = nil
399
+ end
400
+
401
+ def signal_loopbreak
402
+ #@loopbreak_writer.write '+' if @loopbreak_writer
403
+ @loopbreak_writer.send('+',0,"localhost",@loopbreak_port) if @loopbreak_writer
404
+ end
405
+
406
+ def set_timer_quantum interval_in_seconds
407
+ @timer_quantum = interval_in_seconds
408
+ end
409
+
410
+ end
411
+
412
+ end
413
+
414
+
415
+ #--------------------------------------------------------------
416
+
417
+ class IO
418
+ extend Forwardable
419
+ def_delegator :@my_selectable, :close_scheduled?
420
+ def_delegator :@my_selectable, :select_for_reading?
421
+ def_delegator :@my_selectable, :select_for_writing?
422
+ def_delegator :@my_selectable, :eventable_read
423
+ def_delegator :@my_selectable, :eventable_write
424
+ def_delegator :@my_selectable, :uuid
425
+ def_delegator :@my_selectable, :send_data
426
+ def_delegator :@my_selectable, :schedule_close
427
+ def_delegator :@my_selectable, :get_peername
428
+ def_delegator :@my_selectable, :send_datagram
429
+ def_delegator :@my_selectable, :get_outbound_data_size
430
+ def_delegator :@my_selectable, :set_inactivity_timeout
431
+ def_delegator :@my_selectable, :heartbeat
432
+ end
433
+
434
+ #--------------------------------------------------------------
435
+
436
+ module EventMachine
437
+ class Selectable
438
+
439
+ attr_reader :io, :uuid
440
+
441
+ def initialize io
442
+ @uuid = UuidGenerator.generate
443
+ @io = io
444
+ @last_activity = Reactor.instance.current_loop_time
445
+
446
+ if defined?(Fcntl::F_GETFL)
447
+ m = @io.fcntl(Fcntl::F_GETFL, 0)
448
+ @io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m)
449
+ else
450
+ # Windows doesn't define F_GETFL.
451
+ # It's not very reliable about setting descriptors nonblocking either.
452
+ begin
453
+ s = Socket.for_fd(@io.fileno)
454
+ s.fcntl( Fcntl::F_SETFL, Fcntl::O_NONBLOCK )
455
+ rescue Errno::EINVAL, Errno::EBADF
456
+ STDERR.puts "Serious error: unable to set descriptor non-blocking"
457
+ end
458
+ end
459
+ # TODO, should set CLOEXEC on Unix?
460
+
461
+ @close_scheduled = false
462
+ @close_requested = false
463
+
464
+ se = self; @io.instance_eval { @my_selectable = se }
465
+ Reactor.instance.add_selectable @io
466
+ end
467
+
468
+ def close_scheduled?
469
+ @close_scheduled
470
+ end
471
+
472
+ def select_for_reading?
473
+ false
474
+ end
475
+
476
+ def select_for_writing?
477
+ false
478
+ end
479
+
480
+ def get_peername
481
+ nil
482
+ end
483
+
484
+ def set_inactivity_timeout tm
485
+ @inactivity_timeout = tm
486
+ end
487
+
488
+ def heartbeat
489
+ end
490
+ end
491
+
492
+ end
493
+
494
+ #--------------------------------------------------------------
495
+
496
+
497
+ module EventMachine
498
+
499
+ class StreamObject < Selectable
500
+ def initialize io
501
+ super io
502
+ @outbound_q = []
503
+ end
504
+
505
+ # If we have to close, or a close-after-writing has been requested,
506
+ # then don't read any more data.
507
+ def select_for_reading?
508
+ true unless (@close_scheduled || @close_requested)
509
+ end
510
+
511
+ # If we have to close, don't select for writing.
512
+ # Otherwise, see if the protocol is ready to close.
513
+ # If not, see if he has data to send.
514
+ # If a close-after-writing has been requested and the outbound queue
515
+ # is empty, convert the status to close_scheduled.
516
+ def select_for_writing?
517
+ unless @close_scheduled
518
+ if @outbound_q.empty?
519
+ @close_scheduled = true if @close_requested
520
+ false
521
+ else
522
+ true
523
+ end
524
+ end
525
+ end
526
+
527
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
528
+ # If we have it, then we can read multiple times safely to improve
529
+ # performance.
530
+ # The last-activity clock ASSUMES that we only come here when we
531
+ # have selected readable.
532
+ # TODO, coalesce multiple reads into a single event.
533
+ # TODO, do the function check somewhere else and cache it.
534
+ def eventable_read
535
+ @last_activity = Reactor.instance.current_loop_time
536
+ begin
537
+ if io.respond_to?(:read_nonblock)
538
+ 10.times {
539
+ data = io.read_nonblock(4096)
540
+ EventMachine::event_callback uuid, ConnectionData, data
541
+ }
542
+ else
543
+ data = io.sysread(4096)
544
+ EventMachine::event_callback uuid, ConnectionData, data
545
+ end
546
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
547
+ # no-op
548
+ rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError
549
+ @close_scheduled = true
550
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
551
+ end
552
+
553
+ end
554
+
555
+ # Provisional implementation. Will be re-implemented in subclasses.
556
+ # TODO: Complete this implementation. As it stands, this only writes
557
+ # a single packet per cycle. Highly inefficient, but required unless
558
+ # we're running on a Ruby with proper nonblocking I/O (Ruby 1.8.4
559
+ # built from sources from May 25, 2006 or newer).
560
+ # We need to improve the loop so it writes multiple times, however
561
+ # not more than a certain number of bytes per cycle, otherwise
562
+ # one busy connection could hog output buffers and slow down other
563
+ # connections. Also we should coalesce small writes.
564
+ # URGENT TODO: Coalesce small writes. They are a performance killer.
565
+ # The last-activity recorder ASSUMES we'll only come here if we've
566
+ # selected writable.
567
+ def eventable_write
568
+ # coalesce the outbound array here, perhaps
569
+ @last_activity = Reactor.instance.current_loop_time
570
+ while data = @outbound_q.shift do
571
+ begin
572
+ data = data.to_s
573
+ w = if io.respond_to?(:write_nonblock)
574
+ io.write_nonblock data
575
+ else
576
+ io.syswrite data
577
+ end
578
+
579
+ if w < data.length
580
+ @outbound_q.unshift data[w..-1]
581
+ break
582
+ end
583
+ rescue Errno::EAGAIN
584
+ @outbound_q.unshift data
585
+ rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED
586
+ @close_scheduled = true
587
+ @outbound_q.clear
588
+ end
589
+ end
590
+
591
+ end
592
+
593
+ # #send_data
594
+ def send_data data
595
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
596
+ unless @close_scheduled or @close_requested or !data or data.length <= 0
597
+ @outbound_q << data.to_s
598
+ end
599
+ end
600
+
601
+ # #schedule_close
602
+ # The application wants to close the connection.
603
+ def schedule_close after_writing
604
+ if after_writing
605
+ @close_requested = true
606
+ else
607
+ @close_scheduled = true
608
+ end
609
+ end
610
+
611
+ # #get_peername
612
+ # This is defined in the normal way on connected stream objects.
613
+ # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
614
+ # We could also use a convenience method that did the unpacking automatically.
615
+ def get_peername
616
+ io.getpeername
617
+ end
618
+
619
+ # #get_outbound_data_size
620
+ def get_outbound_data_size
621
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
622
+ end
623
+
624
+ def heartbeat
625
+ if @inactivity_timeout and @inactivity_timeout > 0 and (@last_activity + @inactivity_timeout) < Reactor.instance.current_loop_time
626
+ schedule_close true
627
+ end
628
+ end
629
+ end
630
+
631
+
632
+ end
633
+
634
+
635
+ #--------------------------------------------------------------
636
+
637
+
638
+
639
+ module EventMachine
640
+ class EvmaTCPClient < StreamObject
641
+
642
+ def self.connect bind_addr, bind_port, host, port
643
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
644
+ sd.bind( Socket.pack_sockaddr_in( bind_port, bind_addr )) if bind_addr
645
+
646
+ begin
647
+ # TODO, this assumes a current Ruby snapshot.
648
+ # We need to degrade to a nonblocking connect otherwise.
649
+ sd.connect_nonblock( Socket.pack_sockaddr_in( port, host ))
650
+ rescue Errno::EINPROGRESS
651
+ end
652
+ EvmaTCPClient.new sd
653
+ end
654
+
655
+
656
+ def initialize io
657
+ super
658
+ @pending = true
659
+ end
660
+
661
+
662
+ def select_for_writing?
663
+ @pending ? true : super
664
+ end
665
+
666
+ def select_for_reading?
667
+ @pending ? false : super
668
+ end
669
+
670
+ def eventable_write
671
+ if @pending
672
+ @pending = false
673
+ if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
674
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
675
+ end
676
+ else
677
+ super
678
+ end
679
+ end
680
+
681
+
682
+
683
+ end
684
+ end
685
+
686
+ #--------------------------------------------------------------
687
+
688
+
689
+
690
+ module EventMachine
691
+ class EvmaKeyboard < StreamObject
692
+
693
+ def self.open
694
+ EvmaKeyboard.new STDIN
695
+ end
696
+
697
+
698
+ def initialize io
699
+ super
700
+ end
701
+
702
+
703
+ def select_for_writing?
704
+ false
705
+ end
706
+
707
+ def select_for_reading?
708
+ true
709
+ end
710
+
711
+
712
+ end
713
+ end
714
+
715
+
716
+ #--------------------------------------------------------------
717
+
718
+
719
+
720
+ module EventMachine
721
+ class EvmaUNIXClient < StreamObject
722
+
723
+ def self.connect chain
724
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
725
+ begin
726
+ # TODO, this assumes a current Ruby snapshot.
727
+ # We need to degrade to a nonblocking connect otherwise.
728
+ sd.connect_nonblock( Socket.pack_sockaddr_un( chain ))
729
+ rescue Errno::EINPROGRESS
730
+ end
731
+ EvmaUNIXClient.new sd
732
+ end
733
+
734
+
735
+ def initialize io
736
+ super
737
+ @pending = true
738
+ end
739
+
740
+
741
+ def select_for_writing?
742
+ @pending ? true : super
743
+ end
744
+
745
+ def select_for_reading?
746
+ @pending ? false : super
747
+ end
748
+
749
+ def eventable_write
750
+ if @pending
751
+ @pending = false
752
+ if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
753
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
754
+ end
755
+ else
756
+ super
757
+ end
758
+ end
759
+
760
+
761
+
762
+ end
763
+ end
764
+
765
+
766
+ #--------------------------------------------------------------
767
+
768
+ module EventMachine
769
+ class EvmaTCPServer < Selectable
770
+
771
+ # TODO, refactor and unify with EvmaUNIXServer.
772
+
773
+ class << self
774
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
775
+ # with an object of type TCPServer. Prior versions won't so we
776
+ # play it safe and just build a socket.
777
+ #
778
+ def start_server host, port
779
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
780
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
781
+ sd.bind( Socket.pack_sockaddr_in( port, host ))
782
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
783
+ EvmaTCPServer.new sd
784
+ end
785
+ end
786
+
787
+ def initialize io
788
+ super io
789
+ end
790
+
791
+
792
+ def select_for_reading?
793
+ true
794
+ end
795
+
796
+ #--
797
+ # accept_nonblock returns an array consisting of the accepted
798
+ # socket and a sockaddr_in which names the peer.
799
+ # Don't accept more than 10 at a time.
800
+ def eventable_read
801
+ begin
802
+ 10.times {
803
+ descriptor,peername = io.accept_nonblock
804
+ sd = StreamObject.new descriptor
805
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
806
+ }
807
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
808
+ end
809
+ end
810
+
811
+ #--
812
+ #
813
+ def schedule_close
814
+ @close_scheduled = true
815
+ end
816
+
817
+ end
818
+ end
819
+
820
+
821
+ #--------------------------------------------------------------
822
+
823
+ module EventMachine
824
+ class EvmaUNIXServer < Selectable
825
+
826
+ # TODO, refactor and unify with EvmaTCPServer.
827
+
828
+ class << self
829
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
830
+ # with an object of type TCPServer. Prior versions won't so we
831
+ # play it safe and just build a socket.
832
+ #
833
+ def start_server chain
834
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
835
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
836
+ sd.bind( Socket.pack_sockaddr_un( chain ))
837
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
838
+ EvmaUNIXServer.new sd
839
+ end
840
+ end
841
+
842
+ def initialize io
843
+ super io
844
+ end
845
+
846
+
847
+ def select_for_reading?
848
+ true
849
+ end
850
+
851
+ #--
852
+ # accept_nonblock returns an array consisting of the accepted
853
+ # socket and a sockaddr_in which names the peer.
854
+ # Don't accept more than 10 at a time.
855
+ def eventable_read
856
+ begin
857
+ 10.times {
858
+ descriptor,peername = io.accept_nonblock
859
+ sd = StreamObject.new descriptor
860
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
861
+ }
862
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
863
+ end
864
+ end
865
+
866
+ #--
867
+ #
868
+ def schedule_close
869
+ @close_scheduled = true
870
+ end
871
+
872
+ end
873
+ end
874
+
875
+
876
+
877
+ #--------------------------------------------------------------
878
+
879
+ module EventMachine
880
+ class LoopbreakReader < Selectable
881
+
882
+ def select_for_reading?
883
+ true
884
+ end
885
+
886
+ def eventable_read
887
+ io.sysread(128)
888
+ EventMachine::event_callback "", LoopbreakSignalled, ""
889
+ end
890
+
891
+ end
892
+ end
893
+
894
+ #--------------------------------------------------------------
895
+
896
+
897
+ module EventMachine
898
+
899
+ class DatagramObject < Selectable
900
+ def initialize io
901
+ super io
902
+ @outbound_q = []
903
+ end
904
+
905
+ # #send_datagram
906
+ def send_datagram data, target
907
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
908
+ unless @close_scheduled or @close_requested
909
+ @outbound_q << [data.to_s, target]
910
+ end
911
+ end
912
+
913
+ # #select_for_writing?
914
+ def select_for_writing?
915
+ unless @close_scheduled
916
+ if @outbound_q.empty?
917
+ @close_scheduled = true if @close_requested
918
+ false
919
+ else
920
+ true
921
+ end
922
+ end
923
+ end
924
+
925
+ # #select_for_reading?
926
+ def select_for_reading?
927
+ true
928
+ end
929
+
930
+ # #get_outbound_data_size
931
+ def get_outbound_data_size
932
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
933
+ end
934
+
935
+
936
+ end
937
+
938
+
939
+ end
940
+
941
+
942
+ #--------------------------------------------------------------
943
+
944
+ module EventMachine
945
+ class EvmaUDPSocket < DatagramObject
946
+
947
+ class << self
948
+ def create host, port
949
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
950
+ sd.bind Socket::pack_sockaddr_in( port, host )
951
+ EvmaUDPSocket.new sd
952
+ end
953
+ end
954
+
955
+ # #eventable_write
956
+ # This really belongs in DatagramObject, but there is some UDP-specific stuff.
957
+ def eventable_write
958
+ 40.times {
959
+ break if @outbound_q.empty?
960
+ begin
961
+ data,target = @outbound_q.first
962
+
963
+ # This damn better be nonblocking.
964
+ io.send data.to_s, 0, target
965
+
966
+ @outbound_q.shift
967
+ rescue Errno::EAGAIN
968
+ # It's not been observed in testing that we ever get here.
969
+ # True to the definition, packets will be accepted and quietly dropped
970
+ # if the system is under pressure.
971
+ break
972
+ rescue EOFError, Errno::ECONNRESET
973
+ @close_scheduled = true
974
+ @outbound_q.clear
975
+ end
976
+ }
977
+ end
978
+
979
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
980
+ # If we have it, then we can read multiple times safely to improve
981
+ # performance.
982
+ def eventable_read
983
+ begin
984
+ if io.respond_to?(:recvfrom_nonblock)
985
+ 40.times {
986
+ data,@return_address = io.recvfrom_nonblock(16384)
987
+ EventMachine::event_callback uuid, ConnectionData, data
988
+ @return_address = nil
989
+ }
990
+ else
991
+ raise "unimplemented datagram-read operation on this Ruby"
992
+ end
993
+ rescue Errno::EAGAIN
994
+ # no-op
995
+ rescue Errno::ECONNRESET, EOFError
996
+ @close_scheduled = true
997
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
998
+ end
999
+
1000
+ end
1001
+
1002
+
1003
+ def send_data data
1004
+ send_datagram data, @return_address
1005
+ end
1006
+
1007
+ end
1008
+ end
1009
+
1010
+ # load base EM api on top, now that we have the underlying pure ruby
1011
+ # implementation defined
1012
+ require 'eventmachine'
1013
+