libuv 3.1.9 → 3.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9fa444336638ad13d76688a5cb3b497a7583b452
4
- data.tar.gz: 5873c7caef9490d06fc0a115190b2d503fbbd7b3
3
+ metadata.gz: bd16f081b56087f5fc6c17dcea3cfaa2aeca8968
4
+ data.tar.gz: 6d22b971ef7eee595abd656a0d53e80080de0130
5
5
  SHA512:
6
- metadata.gz: 6f6061acb31cd5b6621c2ce2b4f22984facb29f211523a9aa3ddea2dc21c237bb96a0eeeb1abb0f1c3893b8364a1a7fba876722d9a174306a23e0bbbd5cfda06
7
- data.tar.gz: da178e269d1724cf912fa9e4b2180b2657894a151b219fcb4638e4ad34c896f2fe852024c2595fc457a843cd4d1b3bf2b7efdbb6769ef8cde8d6839e5ec03d08
6
+ metadata.gz: 7928432c64a8b4182ef95d17979cfe81c6bed6f1a2113fed5e048f97c823badd7cbf79c437d69ad65389b0a87107dcbfa973833db6a3fbc707ef6caaf4a7c908
7
+ data.tar.gz: 746acbece27866330a475d6fb9dfff6fa2604291cc053c87a4fd3c1f4ef073c1034c46ccf2e28d632738c16088ae1061377f474b47da7c9c3744ed739d711750
@@ -1,10 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - ruby-2.3.3
3
+ - ruby-2.3.4
4
4
  - ruby-2.4.1
5
5
  - ruby-head
6
6
  - rubinius-3.76
7
- - jruby-9.1.8.0
7
+ - jruby-9.1.10.0
8
8
  - jruby-head
9
9
  branches:
10
10
  only:
data/README.md CHANGED
@@ -178,3 +178,12 @@ server.remove_host('somehost2.com')
178
178
 
179
179
  You don't have to specify any hosts at binding time.
180
180
 
181
+
182
+ ## Protocols and 3rd party plugins
183
+
184
+ * [HTTP](https://github.com/cotag/uv-rays - with SNI [server name indication] support)
185
+ * [Faraday plugin](https://github.com/cotag/uv-rays/blob/master/lib/faraday/adapter/libuv.rb)
186
+ * [HTTPI plugin](https://github.com/cotag/uv-rays/blob/master/lib/httpi/adapter/libuv.rb)
187
+ * [HTTP2](https://github.com/igrigorik/http-2)
188
+ * [SOAP](https://github.com/savonrb/savon) (using HTTPI plugin)
189
+ * [SNMP](https://github.com/acaprojects/ruby-engine/blob/master/lib/protocols/snmp.rb)
@@ -21,8 +21,9 @@ module Libuv
21
21
  require 'libuv/prepare' # Called at the end of a reactor cycle
22
22
  require 'libuv/async' # Provide a threadsafe way to signal the event reactor
23
23
  require 'libuv/timer' # High resolution timer
24
- require 'libuv/reactor' # The libuv reactor or event reactor
25
- require 'libuv/coroutines'
24
+ require 'libuv/reactor' # The libuv reactor or event reactor
25
+ require 'libuv/coroutines' # Pause program execution until a result is returned
26
+ require 'libuv/fiber_pool' # Fibers on jRuby and Rubinius are threads and expensive to re-create
26
27
  # --
27
28
 
28
29
  autoload :FsChecks, 'libuv/mixins/fs_checks' # Common code to check file system results
@@ -32,6 +33,7 @@ module Libuv
32
33
  autoload :Filesystem, 'libuv/filesystem' # Async directory manipulation
33
34
  autoload :FSEvent, 'libuv/fs_event' # Notifies of changes to files and folders as they occur
34
35
  autoload :Signal, 'libuv/signal' # Used to handle OS signals
36
+ autoload :Spawn, 'libuv/spawn' # Executes a child process
35
37
  autoload :Check, 'libuv/check' # Called before processing events on the reactor
36
38
  autoload :File, 'libuv/file' # Async file reading and writing
37
39
  autoload :Idle, 'libuv/idle' # Called when there are no events to process
@@ -40,13 +40,13 @@ module Libuv
40
40
 
41
41
 
42
42
  def on_async(handle)
43
- ::Fiber.new {
43
+ @reactor.exec do
44
44
  begin
45
45
  @callback.call
46
46
  rescue Exception => e
47
47
  @reactor.log e, 'performing async callback'
48
48
  end
49
- }.resume
49
+ end
50
50
  end
51
51
  end
52
52
  end
@@ -48,13 +48,13 @@ module Libuv
48
48
 
49
49
 
50
50
  def on_check(handle)
51
- ::Fiber.new {
51
+ @reactor.exec do
52
52
  begin
53
53
  @callback.call
54
54
  rescue Exception => e
55
55
  @reactor.log e, 'performing check callback'
56
56
  end
57
- }.resume
57
+ end
58
58
  end
59
59
  end
60
60
  end
@@ -72,7 +72,7 @@ module Libuv
72
72
 
73
73
  e = check_result(status)
74
74
 
75
- ::Fiber.new {
75
+ @reactor.exec do
76
76
  if e
77
77
  @defer.reject(e)
78
78
  else
@@ -89,7 +89,7 @@ module Libuv
89
89
  end
90
90
  ::Libuv::Ext.freeaddrinfo(addrinfo)
91
91
  end
92
- }.resume
92
+ end
93
93
 
94
94
  # Clean up references
95
95
  cleanup_callbacks
@@ -78,5 +78,11 @@ module Libuv
78
78
  class ENXIO < Error; end
79
79
  class EMLINK < Error; end
80
80
  class EHOSTDOWN < Error; end
81
+ class EREMOTEIO < Error; end
82
+
83
+ # Non-zero exit code
84
+ class ProcessExitCode < Error
85
+ attr_accessor :exit_status, :term_signal
86
+ end
81
87
  end
82
88
  end
@@ -209,7 +209,7 @@ module Libuv
209
209
  attach_function :getaddrinfo, :uv_getaddrinfo, [:uv_loop_t, :uv_getaddrinfo_t, :uv_getaddrinfo_cb, :string, :string, UvAddrinfo.by_ref], :int
210
210
  attach_function :freeaddrinfo, :uv_freeaddrinfo, [UvAddrinfo.by_ref], :void
211
211
 
212
- attach_function :spawn, :uv_spawn, [:uv_loop_t, :uv_process_t, :uv_options_t], :int, :blocking => true
212
+ attach_function :spawn, :uv_spawn, [:uv_loop_t, :uv_process_t, UvProcessOptions.by_ref], :int, :blocking => true
213
213
  attach_function :process_kill, :uv_process_kill, [:uv_process_t, :int], :int, :blocking => true
214
214
  attach_function :kill, :uv_kill, [:int, :int], :int, :blocking => true
215
215
  attach_function :queue_work, :uv_queue_work, [:uv_loop_t, :uv_work_t, :uv_work_cb, :uv_after_work_cb], :int, :blocking => true
@@ -147,6 +147,33 @@ module Libuv
147
147
  :active_handles, :uint
148
148
  end
149
149
 
150
+ enum :uv_stdio_flags, [
151
+ :UV_IGNORE, 0,
152
+ :UV_CREATE_PIPE, 1,
153
+ :UV_INHERIT_FD, 2,
154
+ :UV_INHERIT_STREAM, 4,
155
+ :UV_READABLE_PIPE, 0x10,
156
+ :CREATE_READABLE_PIPE, 0x11,
157
+ :UV_WRITABLE_PIPE, 0x20,
158
+ :CREATE_WRITABLE_PIPE, 0x21
159
+ ]
160
+
161
+ class StdioData < FFI::Union
162
+ layout :pipe_handle, :pointer,
163
+ :fd, :int
164
+ end
165
+
166
+ class UvStdioContainer < FFI::Struct
167
+ layout :flags, :uv_stdio_flags,
168
+ :data, StdioData.by_value
169
+ end
170
+
171
+ class StdioObjs < FFI::Struct
172
+ layout :stdin, UvStdioContainer.by_value,
173
+ :stdout, UvStdioContainer.by_value,
174
+ :stderr, UvStdioContainer.by_value
175
+ end
176
+
150
177
  typedef :pointer, :sockaddr_in
151
178
  typedef :pointer, :uv_handle_t
152
179
  typedef :pointer, :uv_fs_event_t
@@ -205,7 +232,7 @@ module Libuv
205
232
  callback :uv_check_cb, [:uv_check_t], :void
206
233
  callback :uv_idle_cb, [:uv_idle_t], :void
207
234
  callback :uv_getaddrinfo_cb, [:uv_getaddrinfo_t, :status, UvAddrinfo.by_ref], :void
208
- callback :uv_exit_cb, [:uv_process_t, :int, :int], :void
235
+ callback :uv_exit_cb, [:uv_process_t, :int64, :int], :void
209
236
  callback :uv_walk_cb, [:uv_handle_t, :pointer], :void
210
237
  callback :uv_work_cb, [:uv_work_t], :void
211
238
  callback :uv_after_work_cb, [:uv_work_t, :int], :void
@@ -214,5 +241,18 @@ module Libuv
214
241
  callback :uv_udp_send_cb, [:uv_udp_send_t, :int], :void
215
242
  callback :uv_udp_recv_cb, [:uv_udp_t, :ssize_t, :uv_buf_t, Sockaddr.by_ref, :uint], :void
216
243
  callback :uv_cb, [], :void
244
+
245
+ class UvProcessOptions < FFI::Struct
246
+ layout :exit_cb, :uv_exit_cb,
247
+ :file, :pointer,
248
+ :args, :pointer, # arg[0] == file
249
+ :env, :pointer, # environment array of strings
250
+ :cwd, :pointer, # working dir
251
+ :flags, :uint,
252
+ :stdio_count, :int,
253
+ :stdio, StdioObjs.by_ref,
254
+ :uid, :uint64,
255
+ :gid, :uint64
256
+ end
217
257
  end
218
258
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libuv; end
4
+
5
+ # Use of a Fiber Pool increases performance as stack allocations
6
+ # don't need to continually occur. Especially useful on JRuby and
7
+ # Rubinius where multiple kernel threads and locks emulate Fibers.
8
+ class Libuv::FiberPool
9
+ def initialize(thread)
10
+ @reactor = thread
11
+ @pool = []
12
+ @count = 0
13
+ end
14
+
15
+ def exec
16
+ if @reactor.reactor_thread?
17
+ # Execute the block in a Fiber
18
+ next_fiber do
19
+ begin
20
+ yield
21
+ rescue Exception => e
22
+ @on_error.call(e) if @on_error
23
+ end
24
+ end
25
+ else
26
+ # move the block onto the reactor thread
27
+ @reactor.schedule do
28
+ exec do
29
+ yield
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def on_error(&block)
36
+ @on_error = block
37
+ end
38
+
39
+ def available
40
+ @pool.size
41
+ end
42
+
43
+ def size
44
+ @count
45
+ end
46
+
47
+
48
+ protected
49
+
50
+
51
+ def next_fiber(&block)
52
+ fib = if @pool.empty?
53
+ new_fiber
54
+ else
55
+ @pool.pop
56
+ end
57
+
58
+ @job = block
59
+ fib.resume
60
+ end
61
+
62
+ # Fibers are never cleaned up which shouldn't be much of an issue
63
+ # This might lead to issues on Rubinius or JRuby however it should
64
+ # generally improve performance on these platforms
65
+ def new_fiber
66
+ @count += 1
67
+
68
+ Fiber.new do
69
+ loop do
70
+ job = @job
71
+ @job = nil
72
+ job.call
73
+
74
+ @pool << Fiber.current
75
+ Fiber.yield
76
+ end
77
+ end
78
+ end
79
+ end
@@ -232,7 +232,7 @@ module Libuv
232
232
  @fileno = req[:result]
233
233
  cleanup(req)
234
234
  @closed = false
235
- ::Fiber.new { @defer.notify(self) }.resume
235
+ @reactor.exec { @defer.notify(self) }
236
236
 
237
237
  if @coroutine
238
238
  @coroutine.resolve(nil)
@@ -244,7 +244,7 @@ module Libuv
244
244
  def on_close(req)
245
245
  if post_check(req, @defer)
246
246
  cleanup(req)
247
- ::Fiber.new { @defer.resolve(nil) }.resume
247
+ @reactor.exec { @defer.resolve(nil) }
248
248
  end
249
249
  end
250
250
 
@@ -253,7 +253,7 @@ module Libuv
253
253
  if post_check(req, deferred)
254
254
  data = buffer1.read_string(req[:result])
255
255
  cleanup(req)
256
- ::Fiber.new { deferred.resolve(data) }.resume
256
+ @reactor.exec { deferred.resolve(data) }
257
257
  end
258
258
  end
259
259
 
@@ -261,7 +261,7 @@ module Libuv
261
261
  deferred, buffer1 = @request_refs.delete req.to_ptr.address
262
262
  if post_check(req, deferred)
263
263
  cleanup(req)
264
- ::Fiber.new { deferred.resolve(nil) }.resume
264
+ @reactor.exec { deferred.resolve(nil) }
265
265
  end
266
266
  end
267
267
 
@@ -269,7 +269,7 @@ module Libuv
269
269
  deferred = @request_refs.delete req.to_ptr.address
270
270
  if post_check(req, deferred)
271
271
  cleanup(req)
272
- ::Fiber.new { deferred.resolve(nil) }.resume
272
+ @reactor.exec { deferred.resolve(nil) }
273
273
  end
274
274
  end
275
275
 
@@ -277,7 +277,7 @@ module Libuv
277
277
  deferred = @request_refs.delete req.to_ptr.address
278
278
  if post_check(req, deferred)
279
279
  cleanup(req)
280
- ::Fiber.new { deferred.resolve(nil) }.resume
280
+ @reactor.exec { deferred.resolve(nil) }
281
281
  end
282
282
  end
283
283
 
@@ -285,7 +285,7 @@ module Libuv
285
285
  deferred = @request_refs.delete req.to_ptr.address
286
286
  if post_check(req, deferred)
287
287
  cleanup(req)
288
- ::Fiber.new { deferred.resolve(nil) }.resume
288
+ @reactor.exec { deferred.resolve(nil) }
289
289
  end
290
290
  end
291
291
 
@@ -293,7 +293,7 @@ module Libuv
293
293
  deferred = @request_refs.delete req.to_ptr.address
294
294
  if post_check(req, deferred)
295
295
  cleanup(req)
296
- ::Fiber.new { deferred.resolve(nil) }.resume
296
+ @reactor.exec { deferred.resolve(nil) }
297
297
  end
298
298
  end
299
299
 
@@ -301,7 +301,7 @@ module Libuv
301
301
  deferred = @request_refs.delete req.to_ptr.address
302
302
  if post_check(req, deferred)
303
303
  cleanup(req)
304
- ::Fiber.new { deferred.resolve(nil) }.resume
304
+ @reactor.exec { deferred.resolve(nil) }
305
305
  end
306
306
  end
307
307
 
@@ -309,7 +309,7 @@ module Libuv
309
309
  deferred = @request_refs.delete req.to_ptr.address
310
310
  if post_check(req, deferred)
311
311
  cleanup(req)
312
- ::Fiber.new { deferred.resolve(nil) }.resume
312
+ @reactor.exec { deferred.resolve(nil) }
313
313
  end
314
314
  end
315
315
  end
@@ -152,7 +152,7 @@ module Libuv
152
152
  if post_check(req, @unlink_deferred)
153
153
  path = req[:path]
154
154
  cleanup(req)
155
- ::Fiber.new { @unlink_deferred.resolve(path) }.resume
155
+ @reactor.exec { @unlink_deferred.resolve(path) }
156
156
  end
157
157
  @unlink_deferred = nil
158
158
  end
@@ -161,7 +161,7 @@ module Libuv
161
161
  if post_check(req, @mkdir_deferred)
162
162
  path = req[:path]
163
163
  cleanup(req)
164
- ::Fiber.new { @mkdir_deferred.resolve(path) }.resume
164
+ @reactor.exec { @mkdir_deferred.resolve(path) }
165
165
  end
166
166
  @mkdir_deferred = nil
167
167
  end
@@ -170,7 +170,7 @@ module Libuv
170
170
  if post_check(req, @rmdir_deferred)
171
171
  path = req[:path]
172
172
  cleanup(req)
173
- ::Fiber.new { @rmdir_deferred.resolve(path) }.resume
173
+ @reactor.exec { @rmdir_deferred.resolve(path) }
174
174
  end
175
175
  @rmdir_deferred = nil
176
176
  end
@@ -191,7 +191,7 @@ module Libuv
191
191
  end
192
192
 
193
193
  cleanup(req)
194
- ::Fiber.new { @readdir_deferred.resolve(files) }.resume
194
+ @reactor.exec { @readdir_deferred.resolve(files) }
195
195
  end
196
196
  @readdir_deferred = nil
197
197
  end
@@ -200,7 +200,7 @@ module Libuv
200
200
  if post_check(req, @rename_deferred)
201
201
  path = req[:path]
202
202
  cleanup(req)
203
- ::Fiber.new { @rename_deferred.resolve(path) }.resume
203
+ @reactor.exec { @rename_deferred.resolve(path) }
204
204
  end
205
205
  @rename_deferred = nil
206
206
  end
@@ -209,7 +209,7 @@ module Libuv
209
209
  if post_check(req, @chmod_deferred)
210
210
  path = req[:path]
211
211
  cleanup(req)
212
- ::Fiber.new { @chmod_deferred.resolve(path) }.resume
212
+ @reactor.exec { @chmod_deferred.resolve(path) }
213
213
  end
214
214
  @chmod_deferred = nil
215
215
  end
@@ -218,7 +218,7 @@ module Libuv
218
218
  if post_check(req, @utime_deferred)
219
219
  path = req[:path]
220
220
  cleanup(req)
221
- ::Fiber.new { @utime_deferred.resolve(path) }.resume
221
+ @reactor.exec { @utime_deferred.resolve(path) }
222
222
  end
223
223
  @utime_deferred = nil
224
224
  end
@@ -227,7 +227,7 @@ module Libuv
227
227
  if post_check(req, @link_deferred)
228
228
  path = req[:path]
229
229
  cleanup(req)
230
- ::Fiber.new { @link_deferred.resolve(path) }.resume
230
+ @reactor.exec { @link_deferred.resolve(path) }
231
231
  end
232
232
  @link_deferred = nil
233
233
  end
@@ -236,7 +236,7 @@ module Libuv
236
236
  if post_check(req, @symlink_deferred)
237
237
  path = req[:path]
238
238
  cleanup(req)
239
- ::Fiber.new { @symlink_deferred.resolve(path) }.resume
239
+ @reactor.exec { @symlink_deferred.resolve(path) }
240
240
  end
241
241
  @symlink_deferred = nil
242
242
  end
@@ -246,7 +246,7 @@ module Libuv
246
246
  string_ptr = req[:ptr]
247
247
  path = string_ptr.null? ? nil : string_ptr.read_string_to_null
248
248
  cleanup(req)
249
- ::Fiber.new { @readlink_deferred.resolve(path) }.resume
249
+ @reactor.exec { @readlink_deferred.resolve(path) }
250
250
  end
251
251
  @readlink_deferred = nil
252
252
  end
@@ -255,7 +255,7 @@ module Libuv
255
255
  if post_check(req, @chown_deferred)
256
256
  path = req[:path]
257
257
  cleanup(req)
258
- ::Fiber.new { @chown_deferred.resolve(path) }.resume
258
+ @reactor.exec { @chown_deferred.resolve(path) }
259
259
  end
260
260
  @chown_deferred = nil
261
261
  end
@@ -30,7 +30,7 @@ module Libuv
30
30
  reject(e)
31
31
  else
32
32
  # notify of a change
33
- ::Fiber.new { defer.notify(filename, EVENTS[events]) }.resume
33
+ @reactor.exec { defer.notify(filename, EVENTS[events]) }
34
34
  end
35
35
  end
36
36
  end
@@ -91,7 +91,7 @@ module Libuv
91
91
  #clear_callbacks
92
92
  cleanup_callbacks
93
93
 
94
- ::Fiber.new {
94
+ @reactor.exec do
95
95
  if @close_error
96
96
  defer.reject(@close_error)
97
97
  else
@@ -102,7 +102,7 @@ module Libuv
102
102
  @coroutine.resolve(self)
103
103
  @coroutine = nil
104
104
  end
105
- }.resume
105
+ end
106
106
  end
107
107
  end
108
108
  end
@@ -48,13 +48,13 @@ module Libuv
48
48
 
49
49
 
50
50
  def on_idle(handle)
51
- ::Fiber.new {
51
+ @reactor.exec do
52
52
  begin
53
53
  @callback.call
54
54
  rescue Exception => e
55
55
  @reactor.log e, 'performing idle callback'
56
56
  end
57
- }.resume
57
+ end
58
58
  end
59
59
  end
60
60
  end
@@ -53,7 +53,7 @@ module Libuv
53
53
  end
54
54
 
55
55
  cleanup(req)
56
- ::Fiber.new { @stat_deferred.resolve(stats) }.resume
56
+ @reactor.exec { @stat_deferred.resolve(stats) }
57
57
  end
58
58
  @stat_deferred = nil
59
59
  end
@@ -80,13 +80,13 @@ module Libuv
80
80
  if error
81
81
  cleanup(req)
82
82
 
83
- ::Fiber.new {
83
+ @reactor.exec do
84
84
  deferrable.reject(error)
85
85
  if @coroutine
86
86
  @coroutine.resolve(deferrable.promise)
87
87
  @coroutine = nil
88
88
  end
89
- }.resume
89
+ end
90
90
  false
91
91
  else
92
92
  true
@@ -201,7 +201,7 @@ module Libuv
201
201
  def on_listen(server, status)
202
202
  e = check_result(status)
203
203
 
204
- ::Fiber.new {
204
+ @reactor.exec do
205
205
  if e
206
206
  reject(e) # is this cause for closing the handle?
207
207
  else
@@ -211,7 +211,7 @@ module Libuv
211
211
  @reactor.log e, 'performing stream listening callback'
212
212
  end
213
213
  end
214
- }.resume
214
+ end
215
215
  end
216
216
 
217
217
  def on_allocate(client, suggested_size, buffer)
@@ -226,10 +226,10 @@ module Libuv
226
226
  ::Libuv::Ext.free(req)
227
227
  buffer1.free
228
228
 
229
- ::Fiber.new {
229
+ @reactor.exec do
230
230
  resolve deferred, status
231
231
  check_flush_buffer if @flush_defer
232
- }.resume
232
+ end
233
233
  end
234
234
 
235
235
  def on_read(handle, nread, buf)
@@ -239,19 +239,19 @@ module Libuv
239
239
  if e
240
240
  ::Libuv::Ext.free(base)
241
241
 
242
- ::Fiber.new {
242
+ @reactor.exec do
243
243
  # I assume this is desirable behaviour
244
244
  if e.is_a? ::Libuv::Error::EOF
245
245
  close # Close gracefully
246
246
  else
247
247
  reject(e)
248
248
  end
249
- }.resume
249
+ end
250
250
  else
251
251
  data = base.read_string(nread)
252
252
  ::Libuv::Ext.free(base)
253
253
 
254
- ::Fiber.new {
254
+ @reactor.exec do
255
255
  if @tls.nil?
256
256
  begin
257
257
  @progress.call data, self
@@ -261,7 +261,7 @@ module Libuv
261
261
  else
262
262
  @tls.decrypt(data)
263
263
  end
264
- }.resume
264
+ end
265
265
  end
266
266
  end
267
267
 
@@ -270,7 +270,7 @@ module Libuv
270
270
  ::Libuv::Ext.free(req)
271
271
  @close_error = check_result(status)
272
272
 
273
- ::Fiber.new { close }.resume
273
+ @reactor.exec { close }
274
274
  end
275
275
  end
276
276
  end
@@ -165,13 +165,13 @@ module Libuv
165
165
  @reactor.log e, 'pipe accept failed'
166
166
  end
167
167
  if pipe
168
- ::Fiber.new {
168
+ @reactor.exec do
169
169
  begin
170
170
  @on_accept.call(pipe)
171
171
  rescue Exception => e
172
172
  @reactor.log e, 'performing pipe accept callback'
173
173
  end
174
- }.resume
174
+ end
175
175
  end
176
176
  end
177
177
 
@@ -180,7 +180,7 @@ module Libuv
180
180
  ::Libuv::Ext.free(req)
181
181
  e = check_result(status)
182
182
 
183
- ::Fiber.new {
183
+ @reactor.exec do
184
184
  if e
185
185
  reject(e)
186
186
  else
@@ -190,7 +190,7 @@ module Libuv
190
190
  @reactor.log e, 'performing pipe connected callback'
191
191
  end
192
192
  end
193
- }.resume
193
+ end
194
194
  end
195
195
 
196
196
  def write2_complete(req, status)
@@ -199,9 +199,9 @@ module Libuv
199
199
 
200
200
  ::Libuv::Ext.free(req)
201
201
 
202
- ::Fiber.new {
202
+ @reactor.exec do
203
203
  resolve promise, status
204
- }.resume
204
+ end
205
205
  end
206
206
 
207
207
  def windows_path(name)
@@ -48,13 +48,13 @@ module Libuv
48
48
 
49
49
 
50
50
  def on_prepare(handle)
51
- ::Fiber.new {
51
+ @reactor.exec do
52
52
  begin
53
53
  @callback.call
54
54
  rescue Exception => e
55
55
  @reactor.log e, 'performing prepare callback'
56
56
  end
57
- }.resume
57
+ end
58
58
  end
59
59
  end
60
60
  end
@@ -58,6 +58,7 @@ module Libuv
58
58
  @reactor = self
59
59
  @run_count = 0
60
60
  @ref_count = 0
61
+ @fiber_pool = FiberPool.new(self)
61
62
 
62
63
  # Create an async call for scheduling work from other threads
63
64
  @run_queue = Queue.new
@@ -91,9 +92,10 @@ module Libuv
91
92
  @reactor_notify_default = @reactor_notify = proc { |error|
92
93
  @throw_on_exit = error
93
94
  }
95
+ @fiber_pool.on_error &@reactor_notify
94
96
  end
95
97
 
96
- attr_reader :run_count
98
+ attr_reader :run_count, :fiber_pool
97
99
 
98
100
 
99
101
  protected
@@ -128,7 +130,7 @@ module Libuv
128
130
  update_time
129
131
  length.times do
130
132
  # This allows any item to pause its execution without effecting this loop
131
- ::Fiber.new { process_item }.resume
133
+ @fiber_pool.exec { process_item }
132
134
  end
133
135
  end
134
136
 
@@ -167,17 +169,8 @@ module Libuv
167
169
 
168
170
  Thread.current.thread_variable_set(:reactor, @reactor)
169
171
  @throw_on_exit = nil
170
-
171
- if block_given?
172
- update_time
173
- ::Fiber.new {
174
- begin
175
- yield @reactor
176
- rescue Exception => e
177
- log(e, 'in reactor run block')
178
- end
179
- }.resume
180
- end
172
+ update_time
173
+ @fiber_pool.exec { yield @reactor } if block_given?
181
174
  @run_count += 1
182
175
  ::Libuv::Ext.run(@pointer, run_type) # This is blocking
183
176
  ensure
@@ -201,6 +194,11 @@ module Libuv
201
194
  @reactor
202
195
  end
203
196
 
197
+ # Execute the provided block of code in a fiber from the pool
198
+ def exec
199
+ @fiber_pool.exec { yield }
200
+ end
201
+
204
202
  # Prevents the reactor loop from stopping
205
203
  def ref
206
204
  if reactor_thread? && reactor_running?
@@ -54,9 +54,9 @@ module Libuv
54
54
 
55
55
 
56
56
  def on_sig(handle, signal)
57
- ::Fiber.new {
57
+ @reactor.exec do
58
58
  defer.notify(signal) # notify of a call
59
- }.resume
59
+ end
60
60
  end
61
61
  end
62
62
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libuv
4
+ class Spawn < Handle
5
+ define_callback function: :on_exit, params: [:pointer, :int64, :int]
6
+
7
+ attr_reader :stdin, :stdout, :stderr
8
+
9
+ # @param reactor [::Libuv::Reactor] reactor this timer will be associated
10
+ # @param callback [Proc] callback to be called when the timer is triggered
11
+ def initialize(reactor, cmd, working_dir: '.', args: [], env: nil, flags: 0, mode: :capture)
12
+ @reactor = reactor
13
+
14
+ process_ptr = ::Libuv::Ext.allocate_handle_process
15
+ @options = Ext::UvProcessOptions.new
16
+
17
+ # Configure IO objects
18
+ @io_obj = Ext::StdioObjs.new
19
+ case mode.to_sym
20
+ when :capture
21
+ @stdin = @reactor.pipe
22
+ @stdout = @reactor.pipe
23
+ @stderr = @reactor.pipe
24
+ @io_obj[:stdin] = build_stdio(:CREATE_READABLE_PIPE, pipe: @stdin)
25
+ @io_obj[:stdout] = build_stdio(:CREATE_WRITABLE_PIPE, pipe: @stdout)
26
+ @io_obj[:stderr] = build_stdio(:CREATE_WRITABLE_PIPE, pipe: @stderr)
27
+ when :ignore
28
+ @io_obj[:stdin] = build_stdio(:UV_IGNORE)
29
+ @io_obj[:stdout] = build_stdio(:UV_IGNORE)
30
+ @io_obj[:stderr] = build_stdio(:UV_IGNORE)
31
+ when :inherit
32
+ @io_obj[:stdin] = build_stdio(:UV_INHERIT_FD, fd: ::STDIN.fileno)
33
+ @io_obj[:stdout] = build_stdio(:UV_INHERIT_FD, fd: ::STDOUT.fileno)
34
+ @io_obj[:stderr] = build_stdio(:UV_INHERIT_FD, fd: ::STDERR.fileno)
35
+ end
36
+
37
+ # Configure arguments
38
+ @cmd = FFI::MemoryPointer.from_string(cmd)
39
+ @args = args.map { |arg| FFI::MemoryPointer.from_string(arg) }
40
+ @args.unshift(@cmd)
41
+ @args_ptr = FFI::MemoryPointer.new(:pointer, @args.length + 1)
42
+ @args_ptr.write_array_of_pointer(@args)
43
+
44
+ # Configure environment
45
+ if env
46
+ @env = env.map { |e| FFI::MemoryPointer.from_string(e) }
47
+ @env_ptr = FFI::MemoryPointer.new(:pointer, @env.length + 1)
48
+ @env_ptr.write_array_of_pointer(@env)
49
+ end
50
+
51
+ @working_dir = FFI::MemoryPointer.from_string(working_dir)
52
+
53
+ # Apply the options
54
+ @options[:exit_cb] = callback(:on_exit, process_ptr.address)
55
+ @options[:file] = @cmd
56
+ @options[:args] = @args_ptr
57
+ @options[:env] = @env_ptr
58
+ @options[:cwd] = @working_dir
59
+ @options[:flags] = 0
60
+ @options[:stdio_count] = 3
61
+ @options[:stdio] = @io_obj
62
+
63
+ error = check_result(::Libuv::Ext.spawn(reactor.handle, process_ptr, @options))
64
+ super(process_ptr, error)
65
+ end
66
+
67
+ def kill(signal = 2)
68
+ return self if @closed
69
+ ::Libuv::Ext.process_kill(handle, signal)
70
+ self
71
+ end
72
+
73
+
74
+ private
75
+
76
+
77
+ def build_stdio(flags, pipe: nil, fd: nil)
78
+ io = Ext::UvStdioContainer.new
79
+ io[:flags] = flags
80
+ if pipe
81
+ io[:data][:pipe_handle] = pipe.handle
82
+ elsif fd
83
+ io[:data][:fd] = fd
84
+ end
85
+ io
86
+ end
87
+
88
+ def on_exit(handle, exit_status, term_signal)
89
+ @reactor.exec do
90
+ if exit_status == 0
91
+ @defer.resolve(term_signal)
92
+ else
93
+ err = ::Libuv::Error::ProcessExitCode.new "Non-zero exit code returned #{exit_status}"
94
+ err.exit_status = exit_status
95
+ err.term_signal = term_signal
96
+ @defer.reject(err)
97
+ end
98
+
99
+ if @stdin
100
+ @reactor.next_tick do
101
+ @stdin.close
102
+ @stdout.close
103
+ @stderr.close
104
+
105
+ close
106
+ end
107
+ else
108
+ close
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -12,7 +12,7 @@ module Libuv
12
12
  define_callback function: :on_connect, params: [:pointer, :int]
13
13
 
14
14
 
15
- TLS_ERROR = "TLS write failed".freeze
15
+ TLS_ERROR = "TLS write failed"
16
16
 
17
17
 
18
18
  attr_reader :connected
@@ -259,7 +259,7 @@ module Libuv
259
259
  @callback = callback || blk
260
260
  @coroutine = @reactor.defer if @callback.nil?
261
261
  end
262
- error = check_result UV.tcp_open(handle, fd)
262
+ error = check_result ::Libuv::Ext.tcp_open(handle, fd)
263
263
  reject(error) if error
264
264
  co @coroutine.promise if @coroutine
265
265
 
@@ -288,6 +288,7 @@ module Libuv
288
288
  self
289
289
  end
290
290
 
291
+ # The name of the client (local) end of the socket
291
292
  def sockname
292
293
  return [] if @closed
293
294
  sockaddr, len = get_sockaddr_and_len
@@ -295,6 +296,7 @@ module Libuv
295
296
  get_ip_and_port(::Libuv::Ext::Sockaddr.new(sockaddr), len.get_int(0))
296
297
  end
297
298
 
299
+ # The IP address of the peer (remote) end of the socket
298
300
  def peername
299
301
  return [] if @closed
300
302
  sockaddr, len = get_sockaddr_and_len
@@ -355,7 +357,7 @@ module Libuv
355
357
  ::Libuv::Ext.free(req)
356
358
  e = check_result(status)
357
359
 
358
- ::Fiber.new {
360
+ @reactor.exec do
359
361
  if e
360
362
  reject(e)
361
363
  else
@@ -375,7 +377,7 @@ module Libuv
375
377
  @reactor.log e, 'performing TCP connection callback'
376
378
  end
377
379
  end
378
- }.resume
380
+ end
379
381
  end
380
382
 
381
383
  def accept(_)
@@ -383,13 +385,13 @@ module Libuv
383
385
  raise RuntimeError, CLOSED_HANDLE_ERROR if @closed
384
386
  tcp = TCP.new(reactor, handle, **@tls_options)
385
387
 
386
- ::Fiber.new {
388
+ @reactor.exec do
387
389
  begin
388
390
  @on_accept.call(tcp)
389
391
  rescue Exception => e
390
392
  @reactor.log e, 'performing TCP accept callback'
391
393
  end
392
- }.resume
394
+ end
393
395
  rescue Exception => e
394
396
  @reactor.log e, 'failed to accept TCP connection'
395
397
  end
@@ -97,13 +97,13 @@ module Libuv
97
97
 
98
98
 
99
99
  def on_timer(handle)
100
- ::Fiber.new {
100
+ @reactor.exec do
101
101
  begin
102
102
  @callback.call
103
103
  rescue Exception => e
104
104
  @reactor.log e, 'performing timer callback'
105
105
  end
106
- }.resume
106
+ end
107
107
  end
108
108
  end
109
109
  end
@@ -47,9 +47,9 @@ module Libuv
47
47
  self
48
48
  end
49
49
 
50
- def open(fd, binding = true, callback = nil, &blk)
50
+ def open(fd, binding = true)
51
51
  return if @closed
52
- error = check_result UV.udp_open(handle, fd)
52
+ error = check_result ::Libuv::Ext.udp_open(handle, fd)
53
53
  reject(error) if error
54
54
 
55
55
  self
@@ -268,20 +268,20 @@ module Libuv
268
268
  e = check_result(nread)
269
269
 
270
270
  if e
271
- ::Fiber.new { reject(e) }.resume # Will call close
271
+ @reactor.exec { reject(e) } # Will call close
272
272
  elsif nread > 0
273
273
  data = @receive_buff.read_string(nread)
274
274
  unless sockaddr.null?
275
275
  ip, port = get_ip_and_port(sockaddr)
276
276
  end
277
277
 
278
- ::Fiber.new {
278
+ @reactor.exec do
279
279
  begin
280
280
  @progress.call data, ip, port, self
281
281
  rescue Exception => e
282
282
  @reactor.log e, 'performing UDP data received callback'
283
283
  end
284
- }.resume
284
+ end
285
285
  else
286
286
  ::Libuv::Ext.free(@receive_buff)
287
287
  @receive_buff = nil
@@ -296,7 +296,7 @@ module Libuv
296
296
  ::Libuv::Ext.free(req)
297
297
  buffer1.free
298
298
 
299
- ::Fiber.new { resolve deferred, status }.resume
299
+ @reactor.exec { resolve(deferred, status) }
300
300
  end
301
301
  end
302
302
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Libuv
4
- VERSION = '3.1.9'
4
+ VERSION = '3.2.0'
5
5
  end
@@ -58,7 +58,7 @@ module Libuv
58
58
  @complete = true
59
59
  ::Libuv::Ext.free(req)
60
60
 
61
- ::Fiber.new {
61
+ @reactor.exec do
62
62
  e = check_result(status)
63
63
  if e
64
64
  @defer.reject(e)
@@ -69,8 +69,8 @@ module Libuv
69
69
  @defer.resolve(@result)
70
70
  end
71
71
  end
72
- }.resume
73
-
72
+ end
73
+
74
74
  # Clean up references
75
75
  cleanup_callbacks @instance_id
76
76
  end
@@ -35,7 +35,7 @@ describe Libuv::Idle do
35
35
  @reactor.stop
36
36
  }.start(1000)
37
37
 
38
- expect(@reactor.active_handles).to eq(4)
38
+ expect(@reactor.active_handles).to be >= 4
39
39
  }
40
40
 
41
41
  expect(@general_failure).to eq([])
@@ -0,0 +1,119 @@
1
+ require 'libuv'
2
+
3
+ describe Libuv::Spawn do
4
+ describe 'basic spawn of external process' do
5
+ it "should accept arguments and return an termination signal code" do
6
+ @reactor = Libuv::Reactor.new
7
+ @log = []
8
+ @reactor.run { |reactor|
9
+ begin
10
+ p = Libuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
11
+ p.stdout.progress do |data|
12
+ @log << data
13
+ end
14
+ p.stdout.start_read
15
+ @log << p.value
16
+ rescue => e
17
+ @log << e
18
+ @reactor.stop
19
+ end
20
+ }
21
+
22
+ term_signal = @log.pop
23
+ expect(term_signal).to be(0)
24
+
25
+ expect(@log[0]).to eq("123\narg1\narg2\n")
26
+ end
27
+
28
+ it "should return termination signal if exit code was 0" do
29
+ @reactor = Libuv::Reactor.new
30
+ @log = []
31
+ @reactor.run { |reactor|
32
+ begin
33
+ p = Libuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
34
+ p.kill
35
+ p.stdout.progress do |data|
36
+ @log << data
37
+ end
38
+ p.stdout.start_read
39
+ @log << p.value
40
+ rescue => e
41
+ @log << e
42
+ @reactor.stop
43
+ end
44
+ }
45
+
46
+ term_signal = @log.pop
47
+ expect(term_signal).to be(2)
48
+ expect(@log[0]).to be(nil)
49
+ end
50
+
51
+ it "should fail if exit code was not 0 and read output from stderr" do
52
+ @reactor = Libuv::Reactor.new
53
+ @log = []
54
+ @reactor.run { |reactor|
55
+ begin
56
+ p = Libuv::Spawn.new(reactor, './spec/test_fail.sh')
57
+ p.stderr.progress do |data|
58
+ @log << data
59
+ end
60
+ p.stderr.start_read
61
+ @log << p.value
62
+ rescue => e
63
+ @log << e
64
+ @reactor.stop
65
+ end
66
+ }
67
+
68
+ stderr = @log[0]
69
+ e = @log[1]
70
+ expect(e.class).to be(::Libuv::Error::ProcessExitCode)
71
+ expect(e.exit_status).to be(1)
72
+ expect(e.term_signal).to be(0)
73
+ expect(stderr.length).to be > 0
74
+ end
75
+
76
+ it "should be interactive" do
77
+ @reactor = Libuv::Reactor.new
78
+ @log = []
79
+ @reactor.run { |reactor|
80
+ begin
81
+ p = Libuv::Spawn.new(reactor, './spec/test_read.sh')
82
+ p.stdout.progress do |data|
83
+ @log << data
84
+ end
85
+ p.stdout.start_read
86
+ p.stdin.write("2017\n")
87
+ @log << p.value
88
+ rescue => e
89
+ @log << e
90
+ @reactor.stop
91
+ end
92
+ }
93
+
94
+ term_signal = @log.pop
95
+ expect(term_signal).to be(0)
96
+
97
+ expect(@log[0]).to eq("you entered 2017 - sweet\n")
98
+ end
99
+
100
+ it "should support inheriting parent processes streams" do
101
+ @reactor = Libuv::Reactor.new
102
+ @log = []
103
+ @reactor.run { |reactor|
104
+ begin
105
+ p = Libuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'], mode: :inherit)
106
+ @log << p.stdout
107
+ @log << p.value
108
+ rescue => e
109
+ @log << e
110
+ @reactor.stop
111
+ end
112
+ }
113
+
114
+ term_signal = @log.pop
115
+ expect(term_signal).to be(0)
116
+ expect(@log[0]).to be(nil)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ echo $SOME_VAR
3
+ echo $1
4
+ echo $2
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ ech $SOME_VAR
3
+ exit 1
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ read year
3
+ echo "you entered $year - sweet"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libuv
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.9
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen von Takach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-01 00:00:00.000000000 Z
11
+ date: 2017-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -450,6 +450,7 @@ files:
450
450
  - ext/libuv/test/test-poll-close-doesnt-corrupt-stack.c
451
451
  - ext/libuv/test/test-poll-close.c
452
452
  - ext/libuv/test/test-poll-closesocket.c
453
+ - ext/libuv/test/test-poll-oob.c
453
454
  - ext/libuv/test/test-poll.c
454
455
  - ext/libuv/test/test-process-title.c
455
456
  - ext/libuv/test/test-queue-foreach-delete.c
@@ -517,6 +518,7 @@ files:
517
518
  - ext/libuv/test/test-walk-handles.c
518
519
  - ext/libuv/test/test-watcher-cross-stop.c
519
520
  - ext/libuv/tools/make_dist_html.py
521
+ - ext/libuv/tools/vswhere_usability_wrapper.cmd
520
522
  - ext/libuv/uv.gyp
521
523
  - ext/libuv/vcbuild.bat
522
524
  - lib/libuv.rb
@@ -534,6 +536,7 @@ files:
534
536
  - lib/libuv/ext/tasks/unix.rb
535
537
  - lib/libuv/ext/tasks/win.rb
536
538
  - lib/libuv/ext/types.rb
539
+ - lib/libuv/fiber_pool.rb
537
540
  - lib/libuv/file.rb
538
541
  - lib/libuv/filesystem.rb
539
542
  - lib/libuv/fs_event.rb
@@ -551,6 +554,7 @@ files:
551
554
  - lib/libuv/q.rb
552
555
  - lib/libuv/reactor.rb
553
556
  - lib/libuv/signal.rb
557
+ - lib/libuv/spawn.rb
554
558
  - lib/libuv/tcp.rb
555
559
  - lib/libuv/timer.rb
556
560
  - lib/libuv/tty.rb
@@ -567,7 +571,11 @@ files:
567
571
  - spec/filesystem_spec.rb
568
572
  - spec/idle_spec.rb
569
573
  - spec/pipe_spec.rb
574
+ - spec/spawn_spec.rb
570
575
  - spec/tcp_spec.rb
576
+ - spec/test.sh
577
+ - spec/test_fail.sh
578
+ - spec/test_read.sh
571
579
  - spec/timer_spec.rb
572
580
  - spec/udp_spec.rb
573
581
  - spec/zen_spec.rb
@@ -591,7 +599,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
591
599
  version: '0'
592
600
  requirements: []
593
601
  rubyforge_project:
594
- rubygems_version: 2.6.10
602
+ rubygems_version: 2.6.12
595
603
  signing_key:
596
604
  specification_version: 4
597
605
  summary: libuv bindings for Ruby
@@ -605,7 +613,11 @@ test_files:
605
613
  - spec/filesystem_spec.rb
606
614
  - spec/idle_spec.rb
607
615
  - spec/pipe_spec.rb
616
+ - spec/spawn_spec.rb
608
617
  - spec/tcp_spec.rb
618
+ - spec/test.sh
619
+ - spec/test_fail.sh
620
+ - spec/test_read.sh
609
621
  - spec/timer_spec.rb
610
622
  - spec/udp_spec.rb
611
623
  - spec/zen_spec.rb