libuv 0.10.0 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +17 -17
  2. data/.gitmodules +3 -3
  3. data/.rspec +1 -1
  4. data/.travis.yml +16 -16
  5. data/Gemfile +2 -2
  6. data/LICENSE +23 -23
  7. data/README.md +82 -73
  8. data/Rakefile +31 -31
  9. data/lib/libuv.rb +53 -34
  10. data/lib/libuv/async.rb +47 -33
  11. data/lib/libuv/check.rb +55 -48
  12. data/lib/libuv/error.rb +70 -70
  13. data/lib/libuv/ext/ext.rb +264 -256
  14. data/lib/libuv/ext/platform/darwin_x64.rb +12 -12
  15. data/lib/libuv/ext/platform/linux.rb +7 -7
  16. data/lib/libuv/ext/platform/unix.rb +13 -13
  17. data/lib/libuv/ext/platform/windows.rb +26 -26
  18. data/lib/libuv/ext/tasks.rb +27 -27
  19. data/lib/libuv/ext/tasks/mac.rb +23 -23
  20. data/lib/libuv/ext/tasks/unix.rb +23 -23
  21. data/lib/libuv/ext/tasks/win.rb +11 -11
  22. data/lib/libuv/ext/types.rb +234 -229
  23. data/lib/libuv/file.rb +192 -0
  24. data/lib/libuv/filesystem.rb +233 -0
  25. data/lib/libuv/fs_event.rb +31 -31
  26. data/lib/libuv/handle.rb +85 -81
  27. data/lib/libuv/idle.rb +56 -49
  28. data/lib/libuv/loop.rb +338 -310
  29. data/lib/libuv/{assertions.rb → mixins/assertions.rb} +23 -23
  30. data/lib/libuv/mixins/fs_checks.rb +55 -0
  31. data/lib/libuv/{listener.rb → mixins/listener.rb} +34 -34
  32. data/lib/libuv/{net.rb → mixins/net.rb} +37 -37
  33. data/lib/libuv/{resource.rb → mixins/resource.rb} +27 -27
  34. data/lib/libuv/{stream.rb → mixins/stream.rb} +143 -123
  35. data/lib/libuv/pipe.rb +197 -97
  36. data/lib/libuv/prepare.rb +56 -49
  37. data/lib/libuv/q.rb +1 -1
  38. data/lib/libuv/signal.rb +51 -0
  39. data/lib/libuv/tcp.rb +204 -193
  40. data/lib/libuv/timer.rb +88 -75
  41. data/lib/libuv/tty.rb +37 -34
  42. data/lib/libuv/udp.rb +273 -255
  43. data/lib/libuv/version.rb +3 -3
  44. data/lib/libuv/work.rb +63 -61
  45. data/libuv.gemspec +54 -54
  46. data/spec/async_spec.rb +60 -60
  47. data/spec/cpu_spec.rb +10 -0
  48. data/spec/defer_spec.rb +980 -980
  49. data/spec/filesystem_spec.rb +119 -0
  50. data/spec/idle_spec.rb +56 -56
  51. data/spec/pipe_spec.rb +153 -148
  52. data/spec/tcp_spec.rb +203 -188
  53. metadata +73 -49
  54. checksums.yaml +0 -15
  55. data/lib/libuv/simple_async.rb +0 -28
data/lib/libuv/handle.rb CHANGED
@@ -1,82 +1,86 @@
1
- module Libuv
2
- class Handle < Q::DeferredPromise
3
- include Assertions, Resource, Listener
4
-
5
-
6
- def initialize(pointer, error)
7
- @pointer = pointer
8
-
9
- # Initialise the promise
10
- super(loop, loop.defer)
11
-
12
- # clean up on init error (always raise here)
13
- if error
14
- ::Libuv::Ext.free(pointer)
15
- defer.reject(error)
16
- @closed = true
17
- raise error
18
- end
19
- end
20
-
21
- # Public: Increment internal ref counter for the handle on the loop. Useful for
22
- # extending the loop with custom watchers that need to make loop not stop
23
- #
24
- # Returns self
25
- def ref
26
- return if @closed
27
- ::Libuv::Ext.ref(handle)
28
- end
29
-
30
- # Public: Decrement internal ref counter for the handle on the loop, useful to stop
31
- # loop even when there are outstanding open handles
32
- #
33
- # Returns self
34
- def unref
35
- return if @closed
36
- ::Libuv::Ext.unref(handle)
37
- end
38
-
39
- def close
40
- return if @closed
41
- @closed = true
42
- Libuv::Ext.close(handle, callback(:on_close))
43
- end
44
-
45
- def active?
46
- ::Libuv::Ext.is_active(handle) > 0
47
- end
48
-
49
- def closing?
50
- ::Libuv::Ext.is_closing(handle) > 0
51
- end
52
-
53
-
54
- protected
55
-
56
-
57
- def loop; @loop; end
58
- def handle; @pointer; end
59
- def defer; @defer; end
60
-
61
-
62
- private
63
-
64
-
65
- # Clean up and throw an error
66
- def reject(reason)
67
- @close_error = reason
68
- close
69
- end
70
-
71
- def on_close(pointer)
72
- ::Libuv::Ext.free(pointer)
73
- clear_callbacks
74
-
75
- if @close_error
76
- defer.reject(@close_error)
77
- else
78
- defer.resolve(nil)
79
- end
80
- end
81
- end
1
+ module Libuv
2
+ class Handle < Q::DeferredPromise
3
+ include Assertions, Resource, Listener
4
+
5
+
6
+ attr_accessor :storage # A place for general storage
7
+ attr_reader :closed
8
+
9
+
10
+ def initialize(pointer, error)
11
+ @pointer = pointer
12
+
13
+ # Initialise the promise
14
+ super(loop, loop.defer)
15
+
16
+ # clean up on init error (always raise here)
17
+ if error
18
+ ::Libuv::Ext.free(pointer)
19
+ defer.reject(error)
20
+ @closed = true
21
+ raise error
22
+ end
23
+ end
24
+
25
+ # Public: Increment internal ref counter for the handle on the loop. Useful for
26
+ # extending the loop with custom watchers that need to make loop not stop
27
+ #
28
+ # Returns self
29
+ def ref
30
+ return if @closed
31
+ ::Libuv::Ext.ref(handle)
32
+ end
33
+
34
+ # Public: Decrement internal ref counter for the handle on the loop, useful to stop
35
+ # loop even when there are outstanding open handles
36
+ #
37
+ # Returns self
38
+ def unref
39
+ return if @closed
40
+ ::Libuv::Ext.unref(handle)
41
+ end
42
+
43
+ def close
44
+ return if @closed
45
+ @closed = true
46
+ Libuv::Ext.close(handle, callback(:on_close))
47
+ end
48
+
49
+ def active?
50
+ ::Libuv::Ext.is_active(handle) > 0
51
+ end
52
+
53
+ def closing?
54
+ ::Libuv::Ext.is_closing(handle) > 0
55
+ end
56
+
57
+
58
+ protected
59
+
60
+
61
+ def loop; @loop; end
62
+ def handle; @pointer; end
63
+ def defer; @defer; end
64
+
65
+
66
+ private
67
+
68
+
69
+ # Clean up and throw an error
70
+ def reject(reason)
71
+ @close_error = reason
72
+ close
73
+ end
74
+
75
+ def on_close(pointer)
76
+ ::Libuv::Ext.free(pointer)
77
+ clear_callbacks
78
+
79
+ if @close_error
80
+ defer.reject(@close_error)
81
+ else
82
+ defer.resolve(nil)
83
+ end
84
+ end
85
+ end
82
86
  end
data/lib/libuv/idle.rb CHANGED
@@ -1,49 +1,56 @@
1
- module Libuv
2
- class Idle < Handle
3
-
4
-
5
- def initialize(loop, callback = nil, &blk)
6
- @loop = loop
7
- @callback = callback || blk
8
-
9
- idle_ptr = ::Libuv::Ext.create_handle(:uv_idle)
10
- error = check_result(::Libuv::Ext.idle_init(loop.handle, idle_ptr))
11
-
12
- super(idle_ptr, error)
13
- end
14
-
15
- def start
16
- return if @closed
17
- error = check_result ::Libuv::Ext.idle_start(handle, callback(:on_idle))
18
- reject(error) if error
19
- end
20
-
21
- def stop
22
- return if @closed
23
- error = check_result ::Libuv::Ext.idle_stop(handle)
24
- reject(error) if error
25
- end
26
-
27
- def progress(callback = nil, &blk)
28
- @callback = callback || blk
29
- end
30
-
31
-
32
- private
33
-
34
-
35
- def on_idle(handle, status)
36
- e = check_result(status)
37
-
38
- if e
39
- reject(e)
40
- else
41
- begin
42
- @callback.call
43
- rescue Exception => e
44
- @loop.log :error, :idle_cb, e
45
- end
46
- end
47
- end
48
- end
49
- end
1
+ module Libuv
2
+ class Idle < Handle
3
+
4
+
5
+ # @param loop [::Libuv::Loop] loop this idle handler will be associated
6
+ # @param callback [Proc] callback to be called when the loop is idle
7
+ def initialize(loop, callback = nil, &blk)
8
+ @loop = loop
9
+ @callback = callback || blk
10
+
11
+ idle_ptr = ::Libuv::Ext.create_handle(:uv_idle)
12
+ error = check_result(::Libuv::Ext.idle_init(loop.handle, idle_ptr))
13
+
14
+ super(idle_ptr, error)
15
+ end
16
+
17
+ # Enables the idle handler.
18
+ def start
19
+ return if @closed
20
+ error = check_result ::Libuv::Ext.idle_start(handle, callback(:on_idle))
21
+ reject(error) if error
22
+ end
23
+
24
+ # Disables the idle handler.
25
+ def stop
26
+ return if @closed
27
+ error = check_result ::Libuv::Ext.idle_stop(handle)
28
+ reject(error) if error
29
+ end
30
+
31
+ # Used to update the callback that will be triggered on idle
32
+ #
33
+ # @param callback [Proc] the callback to be called on idle trigger
34
+ def progress(callback = nil, &blk)
35
+ @callback = callback || blk
36
+ end
37
+
38
+
39
+ private
40
+
41
+
42
+ def on_idle(handle, status)
43
+ e = check_result(status)
44
+
45
+ if e
46
+ reject(e)
47
+ else
48
+ begin
49
+ @callback.call
50
+ rescue Exception => e
51
+ @loop.log :error, :idle_cb, e
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/libuv/loop.rb CHANGED
@@ -1,310 +1,338 @@
1
- require 'thread'
2
-
3
- module Libuv
4
- class Loop
5
- include Resource, Assertions
6
-
7
-
8
- module ClassMethods
9
- # Get default loop
10
- #
11
- # @return [::Libuv::Loop]
12
- def default
13
- create(::Libuv::Ext.default_loop)
14
- end
15
-
16
- # Create new loop
17
- #
18
- # @return [::Libuv::Loop]
19
- def new
20
- create(::Libuv::Ext.loop_new)
21
- end
22
-
23
- # Create custom loop from pointer
24
- #
25
- # @return [::Libuv::Loop]
26
- def create(pointer)
27
- allocate.tap { |i| i.send(:initialize, FFI::AutoPointer.new(pointer, ::Libuv::Ext.method(:loop_delete))) }
28
- end
29
- end
30
- extend ClassMethods
31
-
32
-
33
- # Initialize a loop using an FFI::Pointer
34
- #
35
- # @return [::Libuv::Loop]
36
- def initialize(pointer) # :notnew:
37
- @pointer = pointer
38
- @loop = self
39
-
40
- # Create an async call for scheduling work from other threads
41
- @run_queue = Queue.new
42
- @queue_proc = proc do
43
- # Rubinius fix for promises
44
- # Anything calling schedule will
45
- # be delayed a tick outside of promise callbacks on rubinius (see https://github.com/ffi/ffi/issues/279)
46
- #@reactor_thread = Thread.current # Should work in rubinius 2.0
47
-
48
- # ensure we only execute what was required for this tick
49
- length = @run_queue.length
50
- length.times do
51
- begin
52
- run = @run_queue.pop true # pop non-block
53
- run.call
54
- rescue Exception => e
55
- @loop.log :error, :next_tick_cb, e
56
- end
57
- end
58
- end
59
- @process_queue = SimpleAsync.new(@loop, @queue_proc)
60
-
61
- # Create a next tick timer
62
- @next_tick = @loop.timer do
63
- @next_tick_scheduled = false
64
- @queue_proc.call
65
- end
66
-
67
- # Create an async call for ending the loop
68
- @stop_loop = SimpleAsync.new @loop do
69
- @process_queue.close
70
- @stop_loop.close
71
- @next_tick.close
72
-
73
- ::Libuv::Ext.stop(@pointer)
74
- end
75
- end
76
-
77
- def handle; @pointer; end
78
-
79
- # Run the actual event loop. This method will block for the duration of event loop unless
80
- # it is run inside an existing event loop, where a new thread will be created for it
81
- #
82
- # @param run_type [:UV_RUN_DEFAULT, :UV_RUN_ONCE, :UV_RUN_NOWAIT]
83
- # @yieldparam promise [::Libuv::Loop] Yields a promise that can be used for logging unhandled
84
- # exceptions on the loop.
85
- # @return [::Libuv::Q::Promise]
86
- def run(run_type = :UV_RUN_DEFAULT)
87
- @loop_notify = @loop.defer
88
-
89
- begin
90
- @reactor_thread = Thread.current
91
- yield @loop_notify.promise if block_given?
92
- ::Libuv::Ext.run(@pointer, run_type) # This is blocking
93
- ensure
94
- @reactor_thread = nil
95
- @run_queue.clear
96
- end
97
-
98
- @loop
99
- end
100
-
101
-
102
- # Creates a deferred result object for where the result of an operation may only be returned
103
- # at some point in the future or is being processed on a different thread (thread safe)
104
- #
105
- # @return [::Libuv::Q::Deferred]
106
- def defer
107
- Q.defer(@loop)
108
- end
109
-
110
- # Combines multiple promises into a single promise that is resolved when all of the input
111
- # promises are resolved. (thread safe)
112
- #
113
- # @param [*Promise] Promises a number of promises that will be combined into a single promise
114
- # @return [Promise] Returns a single promise that will be resolved with an array of values,
115
- # each value corresponding to the promise at the same index in the `promises` array. If any of
116
- # the promises is resolved with a rejection, this resulting promise will be resolved with the
117
- # same rejection.
118
- def all(*promises)
119
- Q.all(@loop, *promises)
120
- end
121
-
122
- #
123
- # Combines multiple promises into a single promise that is resolved when any of the input
124
- # promises are resolved.
125
- #
126
- # @param [*Promise] Promises a number of promises that will be combined into a single promise
127
- # @return [Promise] Returns a single promise
128
- def any(*promises)
129
- Q.any(@loop, *promises)
130
- end
131
-
132
- #
133
- # Combines multiple promises into a single promise that is resolved when all of the input
134
- # promises are resolved or rejected.
135
- #
136
- # @param [*Promise] Promises a number of promises that will be combined into a single promise
137
- # @return [Promise] Returns a single promise that will be resolved with an array of values,
138
- # each [result, wasResolved] value pair corresponding to a at the same index in the `promises` array.
139
- def finally(*promises)
140
- Q.finally(@loop, *promises)
141
- end
142
-
143
-
144
- # forces loop time update, useful for getting more granular times
145
- #
146
- # @return nil
147
- def update_time
148
- ::Libuv::Ext.update_time(@pointer)
149
- end
150
-
151
- # Get current time in microseconds
152
- #
153
- # @return [Fixnum]
154
- def now
155
- ::Libuv::Ext.now(@pointer)
156
- end
157
-
158
- # Lookup an error code and return is as an error object
159
- #
160
- # @param err [Integer] The error code to look up.
161
- # @return [::Libuv::Error]
162
- def lookup_error(err)
163
- name = ::Libuv::Ext.err_name(err)
164
- msg = ::Libuv::Ext.strerror(err)
165
-
166
- ::Libuv::Error.const_get(name.to_sym).new(msg)
167
- rescue Exception => e
168
- @loop.log :warn, :error_lookup_failed, e
169
- ::Libuv::Error::UNKNOWN.new("error lookup failed for code #{err} #{name} #{msg}")
170
- end
171
-
172
- # Get a new TCP instance
173
- #
174
- # @return [::Libuv::TCP]
175
- def tcp
176
- TCP.new(@loop)
177
- end
178
-
179
- # Get a new UDP instance
180
- #
181
- # @return [::Libuv::UDP]
182
- def udp
183
- UDP.new(@loop)
184
- end
185
-
186
- # Get a new TTY instance
187
- #
188
- # @param fileno [Integer] Integer file descriptor of a tty device
189
- # @param readable [true, false] Boolean indicating if TTY is readable
190
- # @return [::Libuv::TTY]
191
- def tty(fileno, readable = false)
192
- assert_type(Integer, fileno, "io#fileno must return an integer file descriptor, #{fileno.inspect} given")
193
-
194
- TTY.new(@loop, fileno, readable)
195
- end
196
-
197
- # Get a new Pipe instance
198
- #
199
- # @param ipc [true, false]
200
- # indicate if a handle will be used for ipc, useful for sharing tcp socket between processes
201
- # @return [::Libuv::Pipe]
202
- def pipe(ipc = false)
203
- Pipe.new(@loop, ipc)
204
- end
205
-
206
- # Get a new timer instance
207
- #
208
- # @return [::Libuv::Timer]
209
- def timer(callback = nil, &blk)
210
- Timer.new(@loop, callback || blk)
211
- end
212
-
213
- # Get a new Prepare handle
214
- #
215
- # @return [::Libuv::Prepare]
216
- def prepare
217
- Prepare.new(@loop)
218
- end
219
-
220
- # Get a new Check handle
221
- #
222
- # @return [::Libuv::Check]
223
- def check
224
- Check.new(@loop)
225
- end
226
-
227
- # Get a new Idle handle
228
- #
229
- # @return [::Libuv::Idle]
230
- def idle(callback = nil, &block)
231
- Idle.new(@loop, callback || block)
232
- end
233
-
234
- # Get a new Async handle
235
- #
236
- # @return [::Libuv::Async]
237
- def async(callback = nil, &block)
238
- callback ||= block
239
- handle = Async.new(@loop)
240
- handle.progress callback if callback
241
- handle
242
- end
243
-
244
- # Queue some work for processing in the libuv thread pool
245
- #
246
- # @return [::Libuv::Work]
247
- # @raise [ArgumentError] if block is not given
248
- def work(callback = nil, &block)
249
- Work.new(@loop, callback || block) # Work is a promise object
250
- end
251
-
252
- # Get a new FSEvent instance
253
- #
254
- # @return [::Libuv::FSEvent]
255
- def fs_event(path)
256
- assert_type(String, path)
257
- FSEvent.new(@loop, path)
258
- end
259
-
260
-
261
- # Schedule some work to be processed on the event loop (thread safe)
262
- #
263
- # @return [nil]
264
- def schedule(&block)
265
- assert_block(block)
266
-
267
- if @reactor_thread == Thread.current
268
- block.call
269
- else
270
- @run_queue << block
271
- @process_queue.call
272
- end
273
- end
274
-
275
- # Schedule some work to be processed in the next iteration of the event loop (thread safe)
276
- #
277
- # @return [nil]
278
- def next_tick(&block)
279
- assert_block(block)
280
-
281
- @run_queue << block
282
- if @reactor_thread == Thread.current
283
- # Create a next tick timer
284
- if not @next_tick_scheduled
285
- @next_tick.start(0)
286
- @next_tick_scheduled = true
287
- end
288
- else
289
- @process_queue.call
290
- end
291
- end
292
-
293
- # Notifies the loop there was an event that should be logged
294
- #
295
- # @param level [Symbol] the error level (info, warn, error etc)
296
- # @param id [Object] some kind of identifying information
297
- # @param *args [*args] any additional information
298
- # @return [nil]
299
- def log(level, id, *args)
300
- @loop_notify.notify(level, id, *args)
301
- end
302
-
303
- # Closes handles opened by the loop class and completes the current loop iteration (thread safe)
304
- #
305
- # @return [nil]
306
- def stop
307
- @stop_loop.call
308
- end
309
- end
310
- end
1
+ require 'thread'
2
+
3
+ module Libuv
4
+ class Loop
5
+ include Resource, Assertions
6
+
7
+
8
+ module ClassMethods
9
+ # Get default loop
10
+ #
11
+ # @return [::Libuv::Loop]
12
+ def default
13
+ create(::Libuv::Ext.default_loop)
14
+ end
15
+
16
+ # Create new Libuv loop
17
+ #
18
+ # @return [::Libuv::Loop]
19
+ def new
20
+ create(::Libuv::Ext.loop_new)
21
+ end
22
+
23
+ # Build a Ruby Libuv loop from an existing loop pointer
24
+ #
25
+ # @return [::Libuv::Loop]
26
+ def create(pointer)
27
+ allocate.tap { |i| i.send(:initialize, FFI::AutoPointer.new(pointer, ::Libuv::Ext.method(:loop_delete))) }
28
+ end
29
+ end
30
+ extend ClassMethods
31
+
32
+
33
+ # Initialize a loop using an FFI::Pointer to a libuv loop
34
+ def initialize(pointer) # :notnew:
35
+ @pointer = pointer
36
+ @loop = self
37
+
38
+ # Create an async call for scheduling work from other threads
39
+ @run_queue = Queue.new
40
+ @queue_proc = proc do
41
+ # ensure we only execute what was required for this tick
42
+ length = @run_queue.length
43
+ length.times do
44
+ begin
45
+ run = @run_queue.pop true # pop non-block
46
+ run.call
47
+ rescue Exception => e
48
+ @loop.log :error, :next_tick_cb, e
49
+ end
50
+ end
51
+ end
52
+ @process_queue = Async.new(@loop, @queue_proc)
53
+
54
+ # Create a next tick timer
55
+ @next_tick = @loop.timer do
56
+ @next_tick_scheduled = false
57
+ @queue_proc.call
58
+ end
59
+
60
+ # Create an async call for ending the loop
61
+ @stop_loop = Async.new @loop do
62
+ @process_queue.close
63
+ @stop_loop.close
64
+ @next_tick.close
65
+
66
+ ::Libuv::Ext.stop(@pointer)
67
+ end
68
+ end
69
+
70
+ def handle; @pointer; end
71
+
72
+ # Run the actual event loop. This method will block until the loop is stopped.
73
+ #
74
+ # @param run_type [:UV_RUN_DEFAULT, :UV_RUN_ONCE, :UV_RUN_NOWAIT]
75
+ # @yieldparam promise [::Libuv::Q::Promise] Yields a promise that can be used for logging unhandled
76
+ # exceptions on the loop.
77
+ def run(run_type = :UV_RUN_DEFAULT)
78
+ @loop_notify = @loop.defer
79
+
80
+ begin
81
+ @reactor_thread = Thread.current
82
+ yield @loop_notify.promise if block_given?
83
+ ::Libuv::Ext.run(@pointer, run_type) # This is blocking
84
+ ensure
85
+ @reactor_thread = nil
86
+ @run_queue.clear
87
+ end
88
+
89
+ @loop
90
+ end
91
+
92
+
93
+ # Creates a deferred result object for where the result of an operation may only be returned
94
+ # at some point in the future or is being processed on a different thread (thread safe)
95
+ #
96
+ # @return [::Libuv::Q::Deferred]
97
+ def defer
98
+ Q.defer(@loop)
99
+ end
100
+
101
+ # Combines multiple promises into a single promise that is resolved when all of the input
102
+ # promises are resolved. (thread safe)
103
+ #
104
+ # @param *promises [::Libuv::Q::Promise] a number of promises that will be combined into a single promise
105
+ # @return [::Libuv::Q::Promise] Returns a single promise that will be resolved with an array of values,
106
+ # each value corresponding to the promise at the same index in the `promises` array. If any of
107
+ # the promises is resolved with a rejection, this resulting promise will be resolved with the
108
+ # same rejection.
109
+ def all(*promises)
110
+ Q.all(@loop, *promises)
111
+ end
112
+
113
+ #
114
+ # Combines multiple promises into a single promise that is resolved when any of the input
115
+ # promises are resolved.
116
+ #
117
+ # @param *promises [::Libuv::Q::Promise] a number of promises that will be combined into a single promise
118
+ # @return [::Libuv::Q::Promise] Returns a single promise
119
+ def any(*promises)
120
+ Q.any(@loop, *promises)
121
+ end
122
+
123
+ #
124
+ # Combines multiple promises into a single promise that is resolved when all of the input
125
+ # promises are resolved or rejected.
126
+ #
127
+ # @param *promises [::Libuv::Q::Promise] a number of promises that will be combined into a single promise
128
+ # @return [::Libuv::Q::Promise] Returns a single promise that will be resolved with an array of values,
129
+ # each [result, wasResolved] value pair corresponding to a at the same index in the `promises` array.
130
+ def finally(*promises)
131
+ Q.finally(@loop, *promises)
132
+ end
133
+
134
+
135
+ # forces loop time update, useful for getting more granular times
136
+ #
137
+ # @return nil
138
+ def update_time
139
+ ::Libuv::Ext.update_time(@pointer)
140
+ end
141
+
142
+ # Get current time in microseconds
143
+ #
144
+ # @return [Fixnum]
145
+ def now
146
+ ::Libuv::Ext.now(@pointer)
147
+ end
148
+
149
+ # Lookup an error code and return is as an error object
150
+ #
151
+ # @param err [Integer] The error code to look up.
152
+ # @return [::Libuv::Error]
153
+ def lookup_error(err)
154
+ name = ::Libuv::Ext.err_name(err)
155
+ msg = ::Libuv::Ext.strerror(err)
156
+
157
+ ::Libuv::Error.const_get(name.to_sym).new(msg)
158
+ rescue Exception => e
159
+ @loop.log :warn, :error_lookup_failed, e
160
+ ::Libuv::Error::UNKNOWN.new("error lookup failed for code #{err} #{name} #{msg}")
161
+ end
162
+
163
+ # Get a new TCP instance
164
+ #
165
+ # @return [::Libuv::TCP]
166
+ def tcp
167
+ TCP.new(@loop)
168
+ end
169
+
170
+ # Get a new UDP instance
171
+ #
172
+ # @return [::Libuv::UDP]
173
+ def udp
174
+ UDP.new(@loop)
175
+ end
176
+
177
+ # Get a new TTY instance
178
+ #
179
+ # @param fileno [Integer] Integer file descriptor of a tty device
180
+ # @param readable [true, false] Boolean indicating if TTY is readable
181
+ # @return [::Libuv::TTY]
182
+ def tty(fileno, readable = false)
183
+ assert_type(Integer, fileno, "io#fileno must return an integer file descriptor, #{fileno.inspect} given")
184
+
185
+ TTY.new(@loop, fileno, readable)
186
+ end
187
+
188
+ # Get a new Pipe instance
189
+ #
190
+ # @param ipc [true, false] indicate if a handle will be used for ipc, useful for sharing tcp socket between processes
191
+ # @return [::Libuv::Pipe]
192
+ def pipe(ipc = false)
193
+ Pipe.new(@loop, ipc)
194
+ end
195
+
196
+ # Get a new timer instance
197
+ #
198
+ # @param callback [Proc] the callback to be called on timer trigger
199
+ # @return [::Libuv::Timer]
200
+ def timer(callback = nil, &blk)
201
+ Timer.new(@loop, callback || blk)
202
+ end
203
+
204
+ # Get a new Prepare handle
205
+ #
206
+ # @return [::Libuv::Prepare]
207
+ def prepare
208
+ Prepare.new(@loop)
209
+ end
210
+
211
+ # Get a new Check handle
212
+ #
213
+ # @return [::Libuv::Check]
214
+ def check
215
+ Check.new(@loop)
216
+ end
217
+
218
+ # Get a new Idle handle
219
+ #
220
+ # @param callback [Proc] the callback to be called on idle trigger
221
+ # @return [::Libuv::Idle]
222
+ def idle(callback = nil, &block)
223
+ Idle.new(@loop, callback || block)
224
+ end
225
+
226
+ # Get a new Async handle
227
+ #
228
+ # @return [::Libuv::Async]
229
+ def async(callback = nil, &block)
230
+ callback ||= block
231
+ handle = Async.new(@loop)
232
+ handle.progress callback if callback
233
+ handle
234
+ end
235
+
236
+ # Get a new signal handler
237
+ #
238
+ # @return [::Libuv::Signal]
239
+ def signal(signum = nil, callback = nil, &block)
240
+ callback ||= block
241
+ handle = Signal.new(@loop)
242
+ handle.progress callback if callback
243
+ handle.start(signum) if signum
244
+ handle
245
+ end
246
+
247
+ # Queue some work for processing in the libuv thread pool
248
+ #
249
+ # @param callback [Proc] the callback to be called in the thread pool
250
+ # @return [::Libuv::Work]
251
+ # @raise [ArgumentError] if block is not given
252
+ def work(callback = nil, &block)
253
+ callback ||= block
254
+ assert_block(callback)
255
+ Work.new(@loop, callback) # Work is a promise object
256
+ end
257
+
258
+ # Get a new FSEvent instance
259
+ #
260
+ # @param path [String] the path to the file or folder for watching
261
+ # @return [::Libuv::FSEvent]
262
+ # @raise [ArgumentError] if path is not a string
263
+ def fs_event(path)
264
+ assert_type(String, path)
265
+ FSEvent.new(@loop, path)
266
+ end
267
+
268
+ # Opens a file and returns an object that can be used to manipulate it
269
+ #
270
+ # @param path [String] the path to the file or folder for watching
271
+ # @param flags [Integer] see ruby File::Constants
272
+ # @param mode [Integer]
273
+ # @return [::Libuv::File]
274
+ def file(path, flags = 0, mode = 0)
275
+ assert_type(String, path, "path must be a String")
276
+ assert_type(Integer, flags, "flags must be an Integer")
277
+ assert_type(Integer, mode, "mode must be an Integer")
278
+ File.new(@loop, path, flags, mode)
279
+ end
280
+
281
+ # Returns an object for manipulating the filesystem
282
+ #
283
+ # @return [::Libuv::Filesystem]
284
+ def filesystem
285
+ Filesystem.new(@loop)
286
+ end
287
+
288
+ # Schedule some work to be processed on the event loop as soon as possible (thread safe)
289
+ #
290
+ # @param callback [Proc] the callback to be called on the reactor thread
291
+ # @raise [ArgumentError] if block is not given
292
+ def schedule(callback = nil, &block)
293
+ callback ||= block
294
+ assert_block(callback)
295
+
296
+ if @reactor_thread == Thread.current
297
+ block.call
298
+ else
299
+ @run_queue << callback
300
+ @process_queue.call
301
+ end
302
+ end
303
+
304
+ # Queue some work to be processed in the next iteration of the event loop (thread safe)
305
+ #
306
+ # @param callback [Proc] the callback to be called on the reactor thread
307
+ # @raise [ArgumentError] if block is not given
308
+ def next_tick(callback = nil, &block)
309
+ callback ||= block
310
+ assert_block(callback)
311
+
312
+ @run_queue << callback
313
+ if @reactor_thread == Thread.current
314
+ # Create a next tick timer
315
+ if not @next_tick_scheduled
316
+ @next_tick.start(0)
317
+ @next_tick_scheduled = true
318
+ end
319
+ else
320
+ @process_queue.call
321
+ end
322
+ end
323
+
324
+ # Notifies the loop there was an event that should be logged
325
+ #
326
+ # @param level [Symbol] the error level (info, warn, error etc)
327
+ # @param id [Object] some kind of identifying information
328
+ # @param *args [*args] any additional information
329
+ def log(level, id, *args)
330
+ @loop_notify.notify(level, id, *args)
331
+ end
332
+
333
+ # Closes handles opened by the loop class and completes the current loop iteration (thread safe)
334
+ def stop
335
+ @stop_loop.call
336
+ end
337
+ end
338
+ end