cool.io 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +26 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +4 -0
  4. data/{CHANGES → CHANGES.md} +43 -79
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +32 -0
  7. data/{README.markdown → README.md} +0 -4
  8. data/Rakefile +31 -67
  9. data/cool.io.gemspec +25 -133
  10. data/ext/cool.io/extconf.rb +3 -0
  11. data/ext/cool.io/stat_watcher.c +99 -23
  12. data/ext/libev/Changes +24 -0
  13. data/ext/libev/ev.c +78 -32
  14. data/ext/libev/ev.h +11 -8
  15. data/ext/libev/ev_epoll.c +39 -7
  16. data/ext/libev/ev_kqueue.c +5 -5
  17. data/ext/libev/ev_poll.c +5 -5
  18. data/ext/libev/ev_port.c +26 -11
  19. data/ext/libev/ev_select.c +11 -8
  20. data/ext/libev/ev_vars.h +10 -4
  21. data/ext/libev/ev_win32.c +6 -6
  22. data/ext/libev/ev_wrap.h +10 -0
  23. data/lib/cool.io.rb +3 -3
  24. data/lib/cool.io/async_watcher.rb +1 -1
  25. data/lib/cool.io/dns_resolver.rb +14 -12
  26. data/lib/cool.io/dsl.rb +26 -26
  27. data/lib/cool.io/eventmachine.rb +18 -18
  28. data/lib/cool.io/http_client.rb +29 -22
  29. data/lib/cool.io/io.rb +18 -18
  30. data/lib/cool.io/iowatcher.rb +1 -1
  31. data/lib/cool.io/listener.rb +2 -2
  32. data/lib/cool.io/loop.rb +12 -12
  33. data/lib/cool.io/meta.rb +4 -4
  34. data/lib/cool.io/server.rb +3 -3
  35. data/lib/cool.io/socket.rb +36 -28
  36. data/lib/cool.io/timer_watcher.rb +1 -1
  37. data/lib/cool.io/version.rb +5 -0
  38. data/lib/coolio.rb +1 -1
  39. data/spec/stat_watcher_spec.rb +77 -0
  40. metadata +47 -56
  41. data/VERSION +0 -1
  42. data/lib/rev.rb +0 -4
  43. data/spec/possible_tests/schedules_other_threads.rb +0 -48
  44. data/spec/possible_tests/test_on_resolve_failed.rb +0 -9
  45. data/spec/possible_tests/test_resolves.rb +0 -27
  46. data/spec/possible_tests/test_write_during_resolve.rb +0 -27
  47. data/spec/possible_tests/works_straight.rb +0 -71
@@ -15,7 +15,7 @@ module Coolio
15
15
  # Socket class and its associated subclasses.
16
16
  class IO
17
17
  extend Meta
18
-
18
+
19
19
  # Maximum number of bytes to consume at once
20
20
  INPUT_SIZE = 16384
21
21
 
@@ -29,32 +29,32 @@ module Coolio
29
29
  #
30
30
  # Watcher methods, delegated to @_read_watcher
31
31
  #
32
-
32
+
33
33
  # Attach to the event loop
34
34
  def attach(loop); @_read_watcher.attach loop; schedule_write if !@_write_buffer.empty?; self; end
35
-
35
+
36
36
  # Detach from the event loop
37
37
  def detach; @_read_watcher.detach; self; end # TODO should these detect write buffers, as well?
38
-
38
+
39
39
  # Enable the watcher
40
40
  def enable; @_read_watcher.enable; self; end
41
-
41
+
42
42
  # Disable the watcher
43
43
  def disable; @_read_watcher.disable; self; end
44
-
44
+
45
45
  # Is the watcher attached?
46
46
  def attached?; @_read_watcher.attached?; end
47
-
47
+
48
48
  # Is the watcher enabled?
49
49
  def enabled?; @_read_watcher.enabled?; end
50
-
50
+
51
51
  # Obtain the event loop associated with this object
52
52
  def evloop; @_read_watcher.evloop; end
53
-
53
+
54
54
  #
55
55
  # Callbacks for asynchronous events
56
56
  #
57
-
57
+
58
58
  # Called whenever the IO object receives data
59
59
  def on_read(data); end
60
60
  event_callback :on_read
@@ -114,7 +114,7 @@ module Coolio
114
114
  close
115
115
  end
116
116
  end
117
-
117
+
118
118
  # Write the contents of the output buffer
119
119
  def on_writable
120
120
  begin
@@ -126,23 +126,23 @@ module Coolio
126
126
  rescue SystemCallError, IOError, SocketError
127
127
  return close
128
128
  end
129
-
129
+
130
130
  if @_write_buffer.empty?
131
131
  disable_write_watcher
132
132
  on_write_complete
133
133
  end
134
134
  end
135
135
 
136
- # Schedule a write to be performed when the IO object becomes writable
136
+ # Schedule a write to be performed when the IO object becomes writable
137
137
  def schedule_write
138
138
  return unless @_io # this would mean 'we are still pre DNS here'
139
139
  return unless attached? # this would mean 'currently unattached' -- ie still pre DNS, or just plain not attached, which is ok
140
140
  begin
141
- enable_write_watcher
141
+ enable_write_watcher
142
142
  rescue IOError
143
143
  end
144
144
  end
145
-
145
+
146
146
  def enable_write_watcher
147
147
  if @_write_watcher.attached?
148
148
  @_write_watcher.enable unless @_write_watcher.enabled?
@@ -150,15 +150,15 @@ module Coolio
150
150
  @_write_watcher.attach(evloop)
151
151
  end
152
152
  end
153
-
153
+
154
154
  def disable_write_watcher
155
155
  @_write_watcher.disable if @_write_watcher and @_write_watcher.enabled?
156
156
  end
157
-
157
+
158
158
  def detach_write_watcher
159
159
  @_write_watcher.detach if @_write_watcher and @_write_watcher.attached?
160
160
  end
161
-
161
+
162
162
  # Internal class implementing watchers used by Coolio::IO
163
163
  class Watcher < IOWatcher
164
164
  def initialize(ruby_io, coolio_io, flags)
@@ -5,7 +5,7 @@
5
5
  #++
6
6
 
7
7
  module Coolio
8
- class IOWatcher
8
+ class IOWatcher
9
9
  # The actual implementation of this class resides in the C extension
10
10
  # Here we metaprogram proper event_callbacks for the callback methods
11
11
  # These can take a block and store it to be called when the event
@@ -55,7 +55,7 @@ module Coolio
55
55
 
56
56
  class TCPListener < Listener
57
57
  DEFAULT_BACKLOG = 1024
58
-
58
+
59
59
  # Create a new Coolio::TCPListener on the specified address and port.
60
60
  # Accepts the following options:
61
61
  #
@@ -68,7 +68,7 @@ module Coolio
68
68
  def initialize(addr, port = nil, options = {})
69
69
  BasicSocket.do_not_reverse_lookup = true unless options[:reverse_lookup]
70
70
  options[:backlog] ||= DEFAULT_BACKLOG
71
-
71
+
72
72
  listen_socket = if ::TCPServer === addr
73
73
  addr
74
74
  else
@@ -35,7 +35,7 @@ module Coolio
35
35
  # :skip_environment (boolean)
36
36
  # Ignore the $LIBEV_FLAGS environment variable
37
37
  #
38
- # :fork_check (boolean)
38
+ # :fork_check (boolean)
39
39
  # Enable autodetection of forks
40
40
  #
41
41
  # :backend
@@ -49,7 +49,7 @@ module Coolio
49
49
  def initialize(options = {})
50
50
  @watchers = {}
51
51
  @active_watchers = 0
52
-
52
+
53
53
  flags = 0
54
54
 
55
55
  options.each do |option, value|
@@ -76,7 +76,7 @@ module Coolio
76
76
 
77
77
  @loop = ev_loop_new(flags)
78
78
  end
79
-
79
+
80
80
  # Attach a watcher to the loop
81
81
  def attach(watcher)
82
82
  watcher.attach self
@@ -86,7 +86,7 @@ module Coolio
86
86
  # are no watchers associated with the event loop it will return
87
87
  # immediately. Otherwise, run will continue blocking and making
88
88
  # event callbacks to watchers until all watchers associated with
89
- # the loop have been disabled or detached. The loop may be
89
+ # the loop have been disabled or detached. The loop may be
90
90
  # explicitly stopped by calling the stop method on the loop object.
91
91
  def run
92
92
  raise RuntimeError, "no watchers for this loop" if @watchers.empty?
@@ -103,28 +103,28 @@ module Coolio
103
103
  raise RuntimeError, "loop not running" unless @running
104
104
  @running = false
105
105
  end
106
-
106
+
107
107
  # Does the loop have any active watchers?
108
108
  def has_active_watchers?
109
109
  @active_watchers > 0
110
110
  end
111
-
111
+
112
112
  # All watchers attached to the current loop
113
113
  def watchers
114
114
  @watchers.keys
115
115
  end
116
-
116
+
117
117
  #######
118
118
  private
119
119
  #######
120
-
120
+
121
121
  EVFLAG_NOENV = 0x1000000 # do NOT consult environment
122
122
  EVFLAG_FORKCHECK = 0x2000000 # check for a fork in each iteration
123
123
 
124
- EVBACKEND_SELECT = 0x00000001 # supported about anywhere
125
- EVBACKEND_POLL = 0x00000002 # !win
126
- EVBACKEND_EPOLL = 0x00000004 # linux
127
- EVBACKEND_KQUEUE = 0x00000008 # bsd
124
+ EVBACKEND_SELECT = 0x00000001 # supported about anywhere
125
+ EVBACKEND_POLL = 0x00000002 # !win
126
+ EVBACKEND_EPOLL = 0x00000004 # linux
127
+ EVBACKEND_KQUEUE = 0x00000008 # bsd
128
128
  EVBACKEND_PORT = 0x00000020 # solaris 10
129
129
  end
130
130
  end
@@ -14,7 +14,7 @@ module Coolio
14
14
  %w{attach detach enable disable}.each do |method|
15
15
  module_eval <<-EOD
16
16
  def #{method}(*args)
17
- if #{proxy_var}
17
+ if defined? #{proxy_var} and #{proxy_var}
18
18
  #{proxy_var}.#{method}(*args)
19
19
  return self
20
20
  end
@@ -37,9 +37,9 @@ module Coolio
37
37
  @#{method}_callback = block
38
38
  return
39
39
  end
40
-
41
- if @#{method}_callback
42
- instance_exec(*args, &@#{method}_callback)
40
+
41
+ if defined? @#{method}_callback and @#{method}_callback
42
+ instance_exec(*args, &@#{method}_callback)
43
43
  end
44
44
  end
45
45
  EOD
@@ -20,9 +20,9 @@ module Coolio
20
20
  expected = arity >= 0 ? arity : -(arity + 1)
21
21
 
22
22
  if (arity >= 0 and args.size + 1 != expected) or (arity < 0 and args.size + 1 < expected)
23
- raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size+1} for #{expected})"
23
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size+1} for #{expected})"
24
24
  end
25
-
25
+
26
26
  @klass, @args, @block = klass, args, block
27
27
  super(listen_socket)
28
28
  end
@@ -35,7 +35,7 @@ module Coolio
35
35
  #########
36
36
  protected
37
37
  #########
38
-
38
+
39
39
  def on_connection(socket)
40
40
  connection = @klass.new(socket, *@args).attach(evloop)
41
41
  connection.__send__(:on_connect)
@@ -8,7 +8,7 @@ require 'socket'
8
8
  require 'resolv'
9
9
 
10
10
  module Coolio
11
- class Socket < IO
11
+ class Socket < IO
12
12
  def self.connect(socket, *args)
13
13
 
14
14
  new(socket, *args).instance_eval do
@@ -16,42 +16,50 @@ module Coolio
16
16
  self
17
17
  end
18
18
  end
19
-
19
+
20
+ # Just initializes some instance variables to avoid
21
+ # warnings and calls super().
22
+ def initialize *args
23
+ @_failed = nil
24
+ @_connector = nil
25
+ super
26
+ end
27
+
20
28
  watcher_delegate :@_connector
21
29
 
22
30
  def attach(evloop)
23
31
  raise RuntimeError, "connection failed" if @_failed
24
-
32
+
25
33
  if @_connector
26
34
  @_connector.attach(evloop)
27
35
  return self
28
36
  end
29
-
37
+
30
38
  super
31
39
  end
32
40
 
33
41
  # Called upon completion of a socket connection
34
42
  def on_connect; end
35
43
  event_callback :on_connect
36
-
44
+
37
45
  # Called if a socket connection failed to complete
38
46
  def on_connect_failed; end
39
47
  event_callback :on_connect_failed
40
-
48
+
41
49
  # Called if a hostname failed to resolve when connecting
42
50
  # Defaults to calling on_connect_failed
43
51
  alias_method :on_resolve_failed, :on_connect_failed
44
-
52
+
45
53
  #########
46
54
  protected
47
55
  #########
48
-
56
+
49
57
  class Connector < IOWatcher
50
58
  def initialize(coolio_socket, ruby_socket)
51
59
  @coolio_socket, @ruby_socket = coolio_socket, ruby_socket
52
60
  super(ruby_socket, :w)
53
61
  end
54
-
62
+
55
63
  def on_writable
56
64
  evl = evloop
57
65
  detach
@@ -67,7 +75,7 @@ module Coolio
67
75
  @coolio_socket.instance_eval { @_failed = true }
68
76
  @coolio_socket.__send__(:on_connect_failed)
69
77
  end
70
- end
78
+ end
71
79
 
72
80
  #######
73
81
  private
@@ -80,11 +88,11 @@ module Coolio
80
88
  end
81
89
  end
82
90
  end
83
-
91
+
84
92
  class TCPSocket < Socket
85
93
  attr_reader :remote_host, :remote_addr, :remote_port, :address_family
86
94
  watcher_delegate :@_resolver
87
-
95
+
88
96
  # Similar to .new, but used in cases where the resulting object is in a
89
97
  # "half-open" state. This is primarily used for when asynchronous
90
98
  # DNS resolution is taking place. We don't actually have a handle to
@@ -95,7 +103,7 @@ module Coolio
95
103
  obj.__send__(:preinitialize, *args, &block)
96
104
  obj
97
105
  end
98
-
106
+
99
107
  # Perform a non-blocking connect to the given host and port
100
108
  # see examples/echo_client.rb
101
109
  # addr is a string, can be an IP address or a hostname.
@@ -107,7 +115,7 @@ module Coolio
107
115
  elsif(Resolv::IPv6.create(addr) rescue nil)
108
116
  family = ::Socket::AF_INET6
109
117
  end
110
-
118
+
111
119
  if family
112
120
  return super(TCPConnectSocket.new(family, addr, port), *args) # this creates a 'real' write buffer so we're ok there with regards to already having a write buffer from the get go
113
121
  end
@@ -118,37 +126,37 @@ module Coolio
118
126
 
119
127
  precreate(addr, port, *args)
120
128
  end
121
-
129
+
122
130
  # Called by precreate during asyncronous DNS resolution
123
131
  def preinitialize(addr, port, *args)
124
132
  @_write_buffer = ::IO::Buffer.new # allow for writing BEFORE DNS has resolved
125
133
  @remote_host, @remote_addr, @remote_port = addr, addr, port
126
134
  @_resolver = TCPConnectResolver.new(self, addr, port, *args)
127
135
  end
128
-
136
+
129
137
  private :preinitialize
130
-
138
+
131
139
  def initialize(socket)
132
140
  unless socket.is_a?(::TCPSocket) or socket.is_a?(TCPConnectSocket)
133
141
  raise TypeError, "socket must be a TCPSocket"
134
142
  end
135
-
143
+
136
144
  super
137
-
145
+
138
146
  @address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
139
147
  end
140
-
148
+
141
149
  def peeraddr
142
150
  [@address_family, @remote_port, @remote_host, @remote_addr]
143
151
  end
144
-
152
+
145
153
  #########
146
154
  protected
147
155
  #########
148
156
 
149
157
  class TCPConnectSocket < ::Socket
150
158
  def initialize(family, addr, port, host = addr)
151
- @host, addr, @port = host, addr, port
159
+ @host, @addr, @port = host, addr, port
152
160
  @address_family = nil
153
161
 
154
162
  super(family, ::Socket::SOCK_STREAM, 0)
@@ -195,26 +203,26 @@ module Coolio
195
203
 
196
204
  def on_failure
197
205
  @sock.__send__(:on_resolve_failed)
198
- @sock.instance_eval do
199
- @_resolver = nil
206
+ @sock.instance_eval do
207
+ @_resolver = nil
200
208
  @_failed = true
201
209
  end
202
210
  return
203
211
  end
204
212
  end
205
213
  end
206
-
214
+
207
215
  class UNIXSocket < Socket
208
216
  attr_reader :path, :address_family
209
-
217
+
210
218
  # Connect to the given UNIX domain socket
211
219
  def self.connect(path, *args)
212
220
  new(::UNIXSocket.new(path), *args)
213
221
  end
214
-
222
+
215
223
  def initialize(socket)
216
224
  raise ArgumentError, "socket must be a UNIXSocket" unless socket.is_a? ::UNIXSocket
217
-
225
+
218
226
  super
219
227
  @address_family, @path = socket.peeraddr
220
228
  end
@@ -10,7 +10,7 @@ module Coolio
10
10
  # Here we metaprogram proper event_callbacks for the callback methods
11
11
  # These can take a block and store it to be called when the event
12
12
  # is actually fired.
13
-
13
+
14
14
  extend Meta
15
15
  event_callback :on_timer
16
16
  end
@@ -0,0 +1,5 @@
1
+ module Coolio
2
+ VERSION = "1.1.0"
3
+
4
+ def self.version; VERSION; end
5
+ end