libuv 3.1.9 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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