cool.io 1.0.0 → 1.1.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.
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