childprocess 4.1.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +32 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -2
- data/README.md +5 -23
- data/childprocess.gemspec +2 -0
- data/lib/childprocess/abstract_process.rb +1 -1
- data/lib/childprocess/errors.rb +0 -21
- data/lib/childprocess/process_spawn_process.rb +127 -0
- data/lib/childprocess/unix/process.rb +3 -64
- data/lib/childprocess/unix.rb +2 -4
- data/lib/childprocess/version.rb +1 -1
- data/lib/childprocess/windows/process.rb +13 -116
- data/lib/childprocess/windows.rb +0 -29
- data/lib/childprocess.rb +16 -53
- data/spec/childprocess_spec.rb +39 -15
- data/spec/io_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -20
- data/spec/unix_spec.rb +3 -7
- metadata +19 -24
- data/.travis.yml +0 -37
- data/appveyor.yml +0 -36
- data/lib/childprocess/jruby/io.rb +0 -16
- data/lib/childprocess/jruby/process.rb +0 -184
- data/lib/childprocess/jruby/pump.rb +0 -53
- data/lib/childprocess/jruby.rb +0 -56
- data/lib/childprocess/tools/generator.rb +0 -146
- data/lib/childprocess/unix/fork_exec_process.rb +0 -78
- data/lib/childprocess/unix/lib.rb +0 -186
- data/lib/childprocess/unix/platform/arm64-macosx.rb +0 -11
- data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
- data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
- data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
- data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
- data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
- data/lib/childprocess/windows/handle.rb +0 -91
- data/lib/childprocess/windows/lib.rb +0 -416
- data/lib/childprocess/windows/process_builder.rb +0 -178
- data/lib/childprocess/windows/structs.rb +0 -149
- data/spec/jruby_spec.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9af8db7e1ea6ba4571c4b26bf7631147d9dc3e9d1b96bf602534a054621d44dd
|
4
|
+
data.tar.gz: fcb40387f9f29e29019663fdea7c1fa94a531c80ee125f6b207194f76617b7cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8eec57e14538d054468f8582802596cc6ecafcc88660bc2242b90c9da2ba6ec9d5e053d39c8d6338aa9486ff8eb942942e6eae2216c52bde3cac53128192b796
|
7
|
+
data.tar.gz: 9e5335a82ab47954fff0d7781cd666f20742ab5c48b670bb8adb567466f22d20a96500b581ac750e9e91ea36d63f7a9a01d05a89a21a6eef20134c66891510f3
|
@@ -0,0 +1,32 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
strategy:
|
6
|
+
fail-fast: false
|
7
|
+
matrix:
|
8
|
+
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
9
|
+
ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', head, jruby, truffleruby ]
|
10
|
+
# CRuby < 2.6 does not support macos-arm64, so test those on amd64 instead
|
11
|
+
# JRuby 9.4.7.0 does not have native console support on macos-arm64: https://github.com/jruby/jruby/issues/8271
|
12
|
+
include:
|
13
|
+
- { os: macos-13, ruby: '2.4' }
|
14
|
+
- { os: macos-13, ruby: '2.5' }
|
15
|
+
- { os: macos-13, ruby: jruby }
|
16
|
+
exclude:
|
17
|
+
- { os: macos-latest, ruby: '2.4' }
|
18
|
+
- { os: macos-latest, ruby: '2.5' }
|
19
|
+
- { os: macos-latest, ruby: jruby }
|
20
|
+
- { os: windows-latest, ruby: truffleruby }
|
21
|
+
# fails to load rspec: RuntimeError: CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before false -> after true
|
22
|
+
- { os: windows-latest, ruby: jruby }
|
23
|
+
runs-on: ${{ matrix.os }}
|
24
|
+
env:
|
25
|
+
CHILDPROCESS_UNSET: should-be-unset
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v2
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
31
|
+
bundler-cache: true
|
32
|
+
- run: bundle exec rake spec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
### Version 5.1.0 / 2024-01-06
|
2
|
+
|
3
|
+
* [#196](https://github.com/enkessler/childprocess/pull/196): Remove `ostruct` dependency to fix deprecation warning on Ruby 3.4
|
4
|
+
* [#199](https://github.com/enkessler/childprocess/pull/199): Add `logger` dependency to fix deprecation warning on Ruby 3.4
|
5
|
+
|
6
|
+
### Version 5.0.0 / 2024-01-06
|
7
|
+
|
8
|
+
* [#175](https://github.com/enkessler/childprocess/pull/175): Replace all backends by `Process.spawn` for portability, reliability and simplicity.
|
9
|
+
* [#185](https://github.com/enkessler/childprocess/pull/185): Add support for Ruby 3.x
|
10
|
+
|
1
11
|
### Version 4.1.0 / 2021-06-08
|
2
12
|
|
3
13
|
* [#170](https://github.com/enkessler/childprocess/pull/170): Update gem homepage to use `https://`
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source '
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in child_process.gemspec
|
4
4
|
gemspec
|
@@ -6,4 +6,5 @@ gemspec
|
|
6
6
|
# Used for local development/testing only
|
7
7
|
gem 'rake'
|
8
8
|
|
9
|
-
|
9
|
+
# Newer versions of term-ansicolor (used by coveralls) do not work on Ruby 2.4
|
10
|
+
gem 'term-ansicolor', '< 1.8.0' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5')
|
data/README.md
CHANGED
@@ -6,9 +6,8 @@ external programs running in the background on any Ruby / OS combination.
|
|
6
6
|
The code originated in the [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver) gem, but should prove useful as
|
7
7
|
a standalone library.
|
8
8
|
|
9
|
-
[](http://badge.fury.io/rb/childprocess)
|
9
|
+
[](https://github.com/enkessler/childprocess/actions/workflows/ci.yml)
|
10
|
+

|
12
11
|
[](https://codeclimate.com/github/enkessler/childprocess)
|
13
12
|
[](https://coveralls.io/r/enkessler/childprocess?branch=master)
|
14
13
|
|
@@ -16,8 +15,6 @@ a standalone library.
|
|
16
15
|
|
17
16
|
* Ruby 2.4+, JRuby 9+
|
18
17
|
|
19
|
-
Windows users **must** ensure the `ffi` gem (`>= 1.0.11`) is installed in order to use ChildProcess.
|
20
|
-
|
21
18
|
# Usage
|
22
19
|
|
23
20
|
The object returned from `ChildProcess.build` will implement `ChildProcess::AbstractProcess`.
|
@@ -73,9 +70,9 @@ begin
|
|
73
70
|
process = ChildProcess.build("sh" , "-c",
|
74
71
|
"for i in {1..3}; do echo $i; sleep 1; done")
|
75
72
|
process.io.stdout = w
|
76
|
-
process.start # This results in a
|
73
|
+
process.start # This results in a subprocess inheriting the write end of the pipe.
|
77
74
|
|
78
|
-
# Close parent's copy of the write end of the pipe so when the
|
75
|
+
# Close parent's copy of the write end of the pipe so when the child
|
79
76
|
# process closes its write end of the pipe the parent receives EOF when
|
80
77
|
# attempting to read from it. If the parent leaves its write end open, it
|
81
78
|
# will not detect EOF.
|
@@ -138,17 +135,6 @@ search.io.stdin.close
|
|
138
135
|
search.wait
|
139
136
|
```
|
140
137
|
|
141
|
-
#### Prefer posix_spawn on *nix
|
142
|
-
|
143
|
-
If the parent process is using a lot of memory, `fork+exec` can be very expensive. The `posix_spawn()` API removes this overhead.
|
144
|
-
|
145
|
-
```ruby
|
146
|
-
ChildProcess.posix_spawn = true
|
147
|
-
process = ChildProcess.build(*args)
|
148
|
-
```
|
149
|
-
|
150
|
-
To be able to use this, please make sure that you have the `ffi` gem installed.
|
151
|
-
|
152
138
|
### Ensure entire process tree dies
|
153
139
|
|
154
140
|
By default, the child process does not create a new process group. This means there's no guarantee that the entire process tree will die when the child process is killed. To solve this:
|
@@ -195,11 +181,7 @@ ChildProcess.logger = logger
|
|
195
181
|
|
196
182
|
# Implementation
|
197
183
|
|
198
|
-
|
199
|
-
|
200
|
-
* Unix : `fork + exec` (or `posix_spawn` if enabled)
|
201
|
-
* Windows : `CreateProcess()` and friends
|
202
|
-
* JRuby : `java.lang.{Process,ProcessBuilder}`
|
184
|
+
ChildProcess 5+ uses `Process.spawn` from the Ruby core library for maximum portability.
|
203
185
|
|
204
186
|
# Note on Patches/Pull Requests
|
205
187
|
|
data/childprocess.gemspec
CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.required_ruby_version = '>= 2.4.0'
|
22
22
|
|
23
|
+
s.add_dependency "logger", "~> 1.5"
|
24
|
+
|
23
25
|
s.add_development_dependency "rspec", "~> 3.0"
|
24
26
|
s.add_development_dependency "yard", "~> 0.0"
|
25
27
|
s.add_development_dependency 'coveralls', '< 1.0'
|
data/lib/childprocess/errors.rb
CHANGED
@@ -13,25 +13,4 @@ module ChildProcess
|
|
13
13
|
|
14
14
|
class LaunchError < Error
|
15
15
|
end
|
16
|
-
|
17
|
-
class MissingFFIError < Error
|
18
|
-
def initialize
|
19
|
-
message = "FFI is a required pre-requisite for Windows or posix_spawn support in the ChildProcess gem. " +
|
20
|
-
"Ensure the `ffi` gem is installed. " +
|
21
|
-
"If you believe this is an error, please file a bug at http://github.com/enkessler/childprocess/issues"
|
22
|
-
|
23
|
-
super(message)
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
class MissingPlatformError < Error
|
29
|
-
def initialize
|
30
|
-
message = "posix_spawn is not yet supported on #{ChildProcess.platform_name} (#{RUBY_PLATFORM}), falling back to default implementation. " +
|
31
|
-
"If you believe this is an error, please file a bug at http://github.com/enkessler/childprocess/issues"
|
32
|
-
|
33
|
-
super(message)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
16
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require_relative 'abstract_process'
|
2
|
+
|
3
|
+
module ChildProcess
|
4
|
+
class ProcessSpawnProcess < AbstractProcess
|
5
|
+
attr_reader :pid
|
6
|
+
|
7
|
+
def exited?
|
8
|
+
return true if @exit_code
|
9
|
+
|
10
|
+
assert_started
|
11
|
+
pid, status = ::Process.waitpid2(@pid, ::Process::WNOHANG | ::Process::WUNTRACED)
|
12
|
+
pid = nil if pid == 0 # may happen on jruby
|
13
|
+
|
14
|
+
log(:pid => pid, :status => status)
|
15
|
+
|
16
|
+
if pid
|
17
|
+
set_exit_code(status)
|
18
|
+
end
|
19
|
+
|
20
|
+
!!pid
|
21
|
+
rescue Errno::ECHILD
|
22
|
+
# may be thrown for detached processes
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait
|
27
|
+
assert_started
|
28
|
+
|
29
|
+
if exited?
|
30
|
+
exit_code
|
31
|
+
else
|
32
|
+
_, status = ::Process.waitpid2(@pid)
|
33
|
+
|
34
|
+
set_exit_code(status)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def launch_process
|
41
|
+
environment = {}
|
42
|
+
@environment.each_pair do |key, value|
|
43
|
+
key = key.to_s
|
44
|
+
value = value.nil? ? nil : value.to_s
|
45
|
+
|
46
|
+
if key.include?("\0") || key.include?("=") || value.to_s.include?("\0")
|
47
|
+
raise InvalidEnvironmentVariable, "#{key.inspect} => #{value.to_s.inspect}"
|
48
|
+
end
|
49
|
+
environment[key] = value
|
50
|
+
end
|
51
|
+
|
52
|
+
options = {}
|
53
|
+
|
54
|
+
options[:out] = io.stdout ? io.stdout.fileno : File::NULL
|
55
|
+
options[:err] = io.stderr ? io.stderr.fileno : File::NULL
|
56
|
+
|
57
|
+
if duplex?
|
58
|
+
reader, writer = ::IO.pipe
|
59
|
+
options[:in] = reader.fileno
|
60
|
+
unless ChildProcess.windows?
|
61
|
+
options[writer.fileno] = :close
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if leader?
|
66
|
+
if ChildProcess.windows?
|
67
|
+
options[:new_pgroup] = true
|
68
|
+
else
|
69
|
+
options[:pgroup] = true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
options[:chdir] = @cwd if @cwd
|
74
|
+
|
75
|
+
if @args.size == 1
|
76
|
+
# When given a single String, Process.spawn would think it should use the shell
|
77
|
+
# if there is any special character in it. However, ChildProcess should never
|
78
|
+
# use the shell. So we use the [cmdname, argv0] form to force no shell.
|
79
|
+
arg = @args[0]
|
80
|
+
args = [[arg, arg]]
|
81
|
+
else
|
82
|
+
args = @args
|
83
|
+
end
|
84
|
+
|
85
|
+
begin
|
86
|
+
@pid = ::Process.spawn(environment, *args, options)
|
87
|
+
rescue SystemCallError => e
|
88
|
+
raise LaunchError, e.message
|
89
|
+
end
|
90
|
+
|
91
|
+
if duplex?
|
92
|
+
io._stdin = writer
|
93
|
+
reader.close
|
94
|
+
end
|
95
|
+
|
96
|
+
::Process.detach(@pid) if detach?
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_exit_code(status)
|
100
|
+
@exit_code = status.exitstatus || status.termsig
|
101
|
+
end
|
102
|
+
|
103
|
+
def send_term
|
104
|
+
send_signal 'TERM'
|
105
|
+
end
|
106
|
+
|
107
|
+
def send_kill
|
108
|
+
send_signal 'KILL'
|
109
|
+
end
|
110
|
+
|
111
|
+
def send_signal(sig)
|
112
|
+
assert_started
|
113
|
+
|
114
|
+
log "sending #{sig}"
|
115
|
+
if leader?
|
116
|
+
if ChildProcess.unix?
|
117
|
+
::Process.kill sig, -@pid # negative pid == process group
|
118
|
+
else
|
119
|
+
output = `taskkill /F /T /PID #{@pid}`
|
120
|
+
log output
|
121
|
+
end
|
122
|
+
else
|
123
|
+
::Process.kill sig, @pid
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
+
require_relative '../process_spawn_process'
|
2
|
+
|
1
3
|
module ChildProcess
|
2
4
|
module Unix
|
3
|
-
class Process <
|
4
|
-
attr_reader :pid
|
5
|
-
|
5
|
+
class Process < ProcessSpawnProcess
|
6
6
|
def io
|
7
7
|
@io ||= Unix::IO.new
|
8
8
|
end
|
@@ -24,67 +24,6 @@ module ChildProcess
|
|
24
24
|
# and send_kill
|
25
25
|
true
|
26
26
|
end
|
27
|
-
|
28
|
-
def exited?
|
29
|
-
return true if @exit_code
|
30
|
-
|
31
|
-
assert_started
|
32
|
-
pid, status = ::Process.waitpid2(@pid, ::Process::WNOHANG | ::Process::WUNTRACED)
|
33
|
-
pid = nil if pid == 0 # may happen on jruby
|
34
|
-
|
35
|
-
log(:pid => pid, :status => status)
|
36
|
-
|
37
|
-
if pid
|
38
|
-
set_exit_code(status)
|
39
|
-
end
|
40
|
-
|
41
|
-
!!pid
|
42
|
-
rescue Errno::ECHILD
|
43
|
-
# may be thrown for detached processes
|
44
|
-
true
|
45
|
-
end
|
46
|
-
|
47
|
-
def wait
|
48
|
-
assert_started
|
49
|
-
|
50
|
-
if exited?
|
51
|
-
exit_code
|
52
|
-
else
|
53
|
-
_, status = ::Process.waitpid2(@pid)
|
54
|
-
|
55
|
-
set_exit_code(status)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def send_term
|
62
|
-
send_signal 'TERM'
|
63
|
-
end
|
64
|
-
|
65
|
-
def send_kill
|
66
|
-
send_signal 'KILL'
|
67
|
-
end
|
68
|
-
|
69
|
-
def send_signal(sig)
|
70
|
-
assert_started
|
71
|
-
|
72
|
-
log "sending #{sig}"
|
73
|
-
::Process.kill sig, _pid
|
74
|
-
end
|
75
|
-
|
76
|
-
def set_exit_code(status)
|
77
|
-
@exit_code = status.exitstatus || status.termsig
|
78
|
-
end
|
79
|
-
|
80
|
-
def _pid
|
81
|
-
if leader?
|
82
|
-
-@pid # negative pid == process group
|
83
|
-
else
|
84
|
-
@pid
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
27
|
end # Process
|
89
28
|
end # Unix
|
90
29
|
end # ChildProcess
|
data/lib/childprocess/unix.rb
CHANGED
@@ -3,7 +3,5 @@ module ChildProcess
|
|
3
3
|
end
|
4
4
|
end
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
require "childprocess/unix/fork_exec_process"
|
9
|
-
# PosixSpawnProcess + ffi is required on demand.
|
6
|
+
require_relative "unix/io"
|
7
|
+
require_relative "unix/process"
|
data/lib/childprocess/version.rb
CHANGED
@@ -1,131 +1,28 @@
|
|
1
|
+
require_relative '../process_spawn_process'
|
2
|
+
|
1
3
|
module ChildProcess
|
2
4
|
module Windows
|
3
|
-
class Process <
|
4
|
-
|
5
|
-
attr_reader :pid
|
6
|
-
|
5
|
+
class Process < ProcessSpawnProcess
|
7
6
|
def io
|
8
7
|
@io ||= Windows::IO.new
|
9
8
|
end
|
10
9
|
|
11
10
|
def stop(timeout = 3)
|
12
11
|
assert_started
|
12
|
+
send_kill
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
ensure
|
19
|
-
close_handle
|
20
|
-
close_job_if_necessary
|
21
|
-
end
|
22
|
-
|
23
|
-
def wait
|
24
|
-
if exited?
|
25
|
-
exit_code
|
26
|
-
else
|
27
|
-
@handle.wait
|
28
|
-
@exit_code = @handle.exit_code
|
29
|
-
|
30
|
-
close_handle
|
31
|
-
close_job_if_necessary
|
32
|
-
|
33
|
-
@exit_code
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def exited?
|
38
|
-
return true if @exit_code
|
39
|
-
assert_started
|
40
|
-
|
41
|
-
code = @handle.exit_code
|
42
|
-
exited = code != PROCESS_STILL_ACTIVE
|
43
|
-
|
44
|
-
log(:exited? => exited, :code => code)
|
45
|
-
|
46
|
-
if exited
|
47
|
-
@exit_code = code
|
48
|
-
close_handle
|
49
|
-
close_job_if_necessary
|
50
|
-
end
|
51
|
-
|
52
|
-
exited
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def launch_process
|
58
|
-
builder = ProcessBuilder.new(@args)
|
59
|
-
builder.leader = leader?
|
60
|
-
builder.detach = detach?
|
61
|
-
builder.duplex = duplex?
|
62
|
-
builder.environment = @environment unless @environment.empty?
|
63
|
-
builder.cwd = @cwd
|
64
|
-
|
65
|
-
if @io
|
66
|
-
builder.stdout = @io.stdout
|
67
|
-
builder.stderr = @io.stderr
|
68
|
-
end
|
69
|
-
|
70
|
-
@pid = builder.start
|
71
|
-
@handle = Handle.open @pid
|
72
|
-
|
73
|
-
if leader?
|
74
|
-
@job = Job.new(detach?, true)
|
75
|
-
@job << @handle
|
76
|
-
end
|
77
|
-
|
78
|
-
if duplex?
|
79
|
-
raise Error, "no stdin stream" unless builder.stdin
|
80
|
-
io._stdin = builder.stdin
|
81
|
-
end
|
82
|
-
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def close_handle
|
87
|
-
@handle.close
|
88
|
-
end
|
89
|
-
|
90
|
-
def close_job_if_necessary
|
91
|
-
@job.close if leader?
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
class Job
|
96
|
-
def initialize(detach, leader)
|
97
|
-
@pointer = Lib.create_job_object(nil, nil)
|
98
|
-
|
99
|
-
if @pointer.nil? || @pointer.null?
|
100
|
-
raise Error, "unable to create job object"
|
101
|
-
end
|
102
|
-
|
103
|
-
basic = JobObjectBasicLimitInformation.new
|
104
|
-
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE if !detach
|
105
|
-
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_BREAKAWAY_OK if leader
|
106
|
-
|
107
|
-
extended = JobObjectExtendedLimitInformation.new
|
108
|
-
extended[:BasicLimitInformation] = basic
|
109
|
-
|
110
|
-
ret = Lib.set_information_job_object(
|
111
|
-
@pointer,
|
112
|
-
JOB_OBJECT_EXTENDED_LIMIT_INFORMATION,
|
113
|
-
extended,
|
114
|
-
extended.size
|
115
|
-
)
|
116
|
-
|
117
|
-
Lib.check_error ret
|
118
|
-
end
|
119
|
-
|
120
|
-
def <<(handle)
|
121
|
-
Lib.check_error Lib.assign_process_to_job_object(@pointer, handle.pointer)
|
14
|
+
begin
|
15
|
+
return poll_for_exit(timeout)
|
16
|
+
rescue TimeoutError
|
17
|
+
# try next
|
122
18
|
end
|
123
19
|
|
124
|
-
|
125
|
-
|
126
|
-
|
20
|
+
wait
|
21
|
+
rescue Errno::ECHILD, Errno::ESRCH
|
22
|
+
# handle race condition where process dies between timeout
|
23
|
+
# and send_kill
|
24
|
+
true
|
127
25
|
end
|
128
|
-
|
129
26
|
end # Process
|
130
27
|
end # Windows
|
131
28
|
end # ChildProcess
|
data/lib/childprocess/windows.rb
CHANGED
@@ -1,38 +1,9 @@
|
|
1
1
|
require "rbconfig"
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'ffi'
|
5
|
-
rescue LoadError
|
6
|
-
raise ChildProcess::MissingFFIError
|
7
|
-
end
|
8
|
-
|
9
3
|
module ChildProcess
|
10
4
|
module Windows
|
11
|
-
module Lib
|
12
|
-
extend FFI::Library
|
13
|
-
|
14
|
-
def self.msvcrt_name
|
15
|
-
host_part = RbConfig::CONFIG['host_os'].split("_")[1]
|
16
|
-
manifest = File.join(RbConfig::CONFIG['bindir'], 'ruby.exe.manifest')
|
17
|
-
|
18
|
-
if host_part && host_part.to_i > 80 && File.exists?(manifest)
|
19
|
-
"msvcr#{host_part}"
|
20
|
-
else
|
21
|
-
"msvcrt"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
ffi_lib "kernel32", msvcrt_name
|
26
|
-
ffi_convention :stdcall
|
27
|
-
|
28
|
-
|
29
|
-
end # Library
|
30
5
|
end # Windows
|
31
6
|
end # ChildProcess
|
32
7
|
|
33
|
-
require "childprocess/windows/lib"
|
34
|
-
require "childprocess/windows/structs"
|
35
|
-
require "childprocess/windows/handle"
|
36
8
|
require "childprocess/windows/io"
|
37
|
-
require "childprocess/windows/process_builder"
|
38
9
|
require "childprocess/windows/process"
|