childprocess 4.1.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![
|
10
|
-
|
11
|
-
[![Gem Version](https://badge.fury.io/rb/childprocess.svg)](http://badge.fury.io/rb/childprocess)
|
9
|
+
[![CI](https://github.com/enkessler/childprocess/actions/workflows/ci.yml/badge.svg)](https://github.com/enkessler/childprocess/actions/workflows/ci.yml)
|
10
|
+
![Gem Version](https://img.shields.io/gem/v/childprocess)
|
12
11
|
[![Code Climate](https://codeclimate.com/github/enkessler/childprocess.svg)](https://codeclimate.com/github/enkessler/childprocess)
|
13
12
|
[![Coverage Status](https://coveralls.io/repos/enkessler/childprocess/badge.svg?branch=master)](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"
|