childprocess 4.1.0 → 5.0.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +23 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +0 -2
  5. data/README.md +3 -20
  6. data/lib/childprocess/abstract_process.rb +1 -1
  7. data/lib/childprocess/errors.rb +0 -21
  8. data/lib/childprocess/process_spawn_process.rb +127 -0
  9. data/lib/childprocess/unix/process.rb +3 -64
  10. data/lib/childprocess/unix.rb +2 -4
  11. data/lib/childprocess/version.rb +1 -1
  12. data/lib/childprocess/windows/process.rb +13 -116
  13. data/lib/childprocess/windows.rb +0 -29
  14. data/lib/childprocess.rb +16 -53
  15. data/spec/childprocess_spec.rb +39 -15
  16. data/spec/io_spec.rb +1 -1
  17. data/spec/spec_helper.rb +3 -18
  18. data/spec/unix_spec.rb +3 -7
  19. metadata +8 -27
  20. data/.travis.yml +0 -37
  21. data/appveyor.yml +0 -36
  22. data/lib/childprocess/jruby/io.rb +0 -16
  23. data/lib/childprocess/jruby/process.rb +0 -184
  24. data/lib/childprocess/jruby/pump.rb +0 -53
  25. data/lib/childprocess/jruby.rb +0 -56
  26. data/lib/childprocess/tools/generator.rb +0 -146
  27. data/lib/childprocess/unix/fork_exec_process.rb +0 -78
  28. data/lib/childprocess/unix/lib.rb +0 -186
  29. data/lib/childprocess/unix/platform/arm64-macosx.rb +0 -11
  30. data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
  31. data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
  32. data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
  33. data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
  34. data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
  35. data/lib/childprocess/windows/handle.rb +0 -91
  36. data/lib/childprocess/windows/lib.rb +0 -416
  37. data/lib/childprocess/windows/process_builder.rb +0 -178
  38. data/lib/childprocess/windows/structs.rb +0 -149
  39. data/spec/jruby_spec.rb +0 -24
@@ -1,146 +0,0 @@
1
- require 'fileutils'
2
-
3
- module ChildProcess
4
- module Tools
5
- class Generator
6
- EXE_NAME = "childprocess-sizeof-generator"
7
- TMP_PROGRAM = "childprocess-sizeof-generator.c"
8
- DEFAULT_INCLUDES = %w[stdio.h stddef.h]
9
-
10
- def self.generate
11
- new.generate
12
- end
13
-
14
- def initialize
15
- @cc = ENV['CC'] || 'gcc'
16
- @out = File.expand_path("../../unix/platform/#{ChildProcess.platform_name}.rb", __FILE__)
17
- @sizeof = {}
18
- @constants = {}
19
- end
20
-
21
- def generate
22
- fetch_size 'posix_spawn_file_actions_t', :include => "spawn.h"
23
- fetch_size 'posix_spawnattr_t', :include => "spawn.h"
24
- fetch_size 'sigset_t', :include => "signal.h"
25
-
26
- fetch_constant 'POSIX_SPAWN_RESETIDS', :include => 'spawn.h'
27
- fetch_constant 'POSIX_SPAWN_SETPGROUP', :include => 'spawn.h'
28
- fetch_constant 'POSIX_SPAWN_SETSIGDEF', :include => 'spawn.h'
29
- fetch_constant 'POSIX_SPAWN_SETSIGMASK', :include => 'spawn.h'
30
-
31
- if ChildProcess.linux?
32
- fetch_constant 'POSIX_SPAWN_USEVFORK', :include => 'spawn.h', :define => {'_GNU_SOURCE' => nil}
33
- end
34
-
35
- write
36
- end
37
-
38
- def write
39
- FileUtils.mkdir_p(File.dirname(@out))
40
- File.open(@out, 'w') do |io|
41
- io.puts result
42
- end
43
-
44
- puts "wrote #{@out}"
45
- end
46
-
47
- def fetch_size(type_name, opts = {})
48
- print "sizeof(#{type_name}): "
49
- src = <<-EOF
50
- int main() {
51
- printf("%d", (unsigned int)sizeof(#{type_name}));
52
- return 0;
53
- }
54
- EOF
55
-
56
- output = execute(src, opts)
57
-
58
- if output.to_i < 1
59
- raise "sizeof(#{type_name}) == #{output.to_i} (output=#{output})"
60
- end
61
-
62
- size = output.to_i
63
- @sizeof[type_name] = size
64
-
65
- puts size
66
- end
67
-
68
- def fetch_constant(name, opts)
69
- print "#{name}: "
70
- src = <<-EOF
71
- int main() {
72
- printf("%d", (unsigned int)#{name});
73
- return 0;
74
- }
75
- EOF
76
-
77
- output = execute(src, opts)
78
- value = Integer(output)
79
- @constants[name] = value
80
-
81
- puts value
82
- end
83
-
84
-
85
- def execute(src, opts)
86
- program = Array(opts[:define]).map do |key, value|
87
- <<-SRC
88
- #ifndef #{key}
89
- #define #{key} #{value}
90
- #endif
91
- SRC
92
- end.join("\n")
93
- program << "\n"
94
-
95
- includes = Array(opts[:include]) + DEFAULT_INCLUDES
96
- program << includes.map { |include| "#include <#{include}>" }.join("\n")
97
- program << "\n#{src}"
98
-
99
- File.open(TMP_PROGRAM, 'w') do |file|
100
- file << program
101
- end
102
-
103
- cmd = "#{@cc} #{TMP_PROGRAM} -o #{EXE_NAME}"
104
- system cmd
105
- unless $?.success?
106
- raise "failed to compile program: #{cmd.inspect}\n#{program}"
107
- end
108
-
109
- output = `./#{EXE_NAME} 2>&1`
110
-
111
- unless $?.success?
112
- raise "failed to run program: #{cmd.inspect}\n#{output}"
113
- end
114
-
115
- output.chomp
116
- ensure
117
- File.delete TMP_PROGRAM if File.exist?(TMP_PROGRAM)
118
- File.delete EXE_NAME if File.exist?(EXE_NAME)
119
- end
120
-
121
- def result
122
- if @sizeof.empty? && @constants.empty?
123
- raise "no data collected, nothing to do"
124
- end
125
-
126
- out = ['module ChildProcess::Unix::Platform']
127
- out << ' SIZEOF = {'
128
-
129
- max = @sizeof.keys.map { |e| e.length }.max
130
- @sizeof.each_with_index do |(type, size), idx|
131
- out << " :#{type.ljust max} => #{size}#{',' unless idx == @sizeof.size - 1}"
132
- end
133
- out << ' }'
134
-
135
- max = @constants.keys.map { |e| e.length }.max
136
- @constants.each do |name, val|
137
- out << " #{name.ljust max} = #{val}"
138
- end
139
- out << 'end'
140
-
141
- out.join "\n"
142
- end
143
-
144
- end
145
- end
146
- end
@@ -1,78 +0,0 @@
1
- module ChildProcess
2
- module Unix
3
- class ForkExecProcess < Process
4
- private
5
-
6
- def launch_process
7
- if @io
8
- stdout = @io.stdout
9
- stderr = @io.stderr
10
- end
11
-
12
- # pipe used to detect exec() failure
13
- exec_r, exec_w = ::IO.pipe
14
- ChildProcess.close_on_exec exec_w
15
-
16
- if duplex?
17
- reader, writer = ::IO.pipe
18
- end
19
-
20
- @pid = Kernel.fork {
21
- # Children of the forked process will inherit its process group
22
- # This is to make sure that all grandchildren dies when this Process instance is killed
23
- ::Process.setpgid 0, 0 if leader?
24
-
25
- if @cwd
26
- Dir.chdir(@cwd)
27
- end
28
-
29
- exec_r.close
30
- set_env
31
-
32
- if stdout
33
- STDOUT.reopen(stdout)
34
- else
35
- STDOUT.reopen("/dev/null", "a+")
36
- end
37
- if stderr
38
- STDERR.reopen(stderr)
39
- else
40
- STDERR.reopen("/dev/null", "a+")
41
- end
42
-
43
- if duplex?
44
- STDIN.reopen(reader)
45
- writer.close
46
- end
47
-
48
- executable, *args = @args
49
-
50
- begin
51
- Kernel.exec([executable, executable], *args)
52
- rescue SystemCallError => ex
53
- exec_w << ex.message
54
- end
55
- }
56
-
57
- exec_w.close
58
-
59
- if duplex?
60
- io._stdin = writer
61
- reader.close
62
- end
63
-
64
- # if we don't eventually get EOF, exec() failed
65
- unless exec_r.eof?
66
- raise LaunchError, exec_r.read || "executing command with #{@args.inspect} failed"
67
- end
68
-
69
- ::Process.detach(@pid) if detach?
70
- end
71
-
72
- def set_env
73
- @environment.each { |k, v| ENV[k.to_s] = v.nil? ? nil : v.to_s }
74
- end
75
-
76
- end # Process
77
- end # Unix
78
- end # ChildProcess
@@ -1,186 +0,0 @@
1
- module ChildProcess
2
- module Unix
3
- module Lib
4
- extend FFI::Library
5
- ffi_lib FFI::Library::LIBC
6
-
7
- if ChildProcess.os == :macosx
8
- attach_function :_NSGetEnviron, [], :pointer
9
- def self.environ
10
- _NSGetEnviron().read_pointer
11
- end
12
- elsif respond_to? :attach_variable
13
- attach_variable :environ, :pointer
14
- end
15
-
16
- attach_function :strerror, [:int], :string
17
- attach_function :chdir, [:string], :int
18
- attach_function :fcntl, [:int, :int, :int], :int # fcntl actually takes varags, but we only need this version.
19
-
20
- # int posix_spawnp(
21
- # pid_t *restrict pid,
22
- # const char *restrict file,
23
- # const posix_spawn_file_actions_t *file_actions,
24
- # const posix_spawnattr_t *restrict attrp,
25
- # char *const argv[restrict],
26
- # char *const envp[restrict]
27
- # );
28
-
29
- attach_function :posix_spawnp, [
30
- :pointer,
31
- :string,
32
- :pointer,
33
- :pointer,
34
- :pointer,
35
- :pointer
36
- ], :int
37
-
38
- # int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
39
- attach_function :posix_spawn_file_actions_init, [:pointer], :int
40
-
41
- # int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions);
42
- attach_function :posix_spawn_file_actions_destroy, [:pointer], :int
43
-
44
- # int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int filedes);
45
- attach_function :posix_spawn_file_actions_addclose, [:pointer, :int], :int
46
-
47
- # int posix_spawn_file_actions_addopen(
48
- # posix_spawn_file_actions_t *restrict file_actions,
49
- # int filedes,
50
- # const char *restrict path,
51
- # int oflag,
52
- # mode_t mode
53
- # );
54
- attach_function :posix_spawn_file_actions_addopen, [:pointer, :int, :string, :int, :mode_t], :int
55
-
56
- # int posix_spawn_file_actions_adddup2(
57
- # posix_spawn_file_actions_t *file_actions,
58
- # int filedes,
59
- # int newfiledes
60
- # );
61
- attach_function :posix_spawn_file_actions_adddup2, [:pointer, :int, :int], :int
62
-
63
- # int posix_spawnattr_init(posix_spawnattr_t *attr);
64
- attach_function :posix_spawnattr_init, [:pointer], :int
65
-
66
- # int posix_spawnattr_destroy(posix_spawnattr_t *attr);
67
- attach_function :posix_spawnattr_destroy, [:pointer], :int
68
-
69
- # int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
70
- attach_function :posix_spawnattr_setflags, [:pointer, :short], :int
71
-
72
- # int posix_spawnattr_getflags(const posix_spawnattr_t *restrict attr, short *restrict flags);
73
- attach_function :posix_spawnattr_getflags, [:pointer, :pointer], :int
74
-
75
- # int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
76
- attach_function :posix_spawnattr_setpgroup, [:pointer, :pid_t], :int
77
-
78
- # int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict attr, pid_t *restrict pgroup);
79
- attach_function :posix_spawnattr_getpgroup, [:pointer, :pointer], :int
80
-
81
- # int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict attr, const sigset_t *restrict sigdefault);
82
- attach_function :posix_spawnattr_setsigdefault, [:pointer, :pointer], :int
83
-
84
- # int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict attr, sigset_t *restrict sigdefault);
85
- attach_function :posix_spawnattr_getsigdefault, [:pointer, :pointer], :int
86
-
87
- # int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict attr, const sigset_t *restrict sigmask);
88
- attach_function :posix_spawnattr_setsigmask, [:pointer, :pointer], :int
89
-
90
- # int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict attr, sigset_t *restrict sigmask);
91
- attach_function :posix_spawnattr_getsigmask, [:pointer, :pointer], :int
92
-
93
- def self.check(errno)
94
- if errno != 0
95
- raise Error, Lib.strerror(FFI.errno)
96
- end
97
- end
98
-
99
- class FileActions
100
- def initialize
101
- @ptr = FFI::MemoryPointer.new(1, Platform::SIZEOF.fetch(:posix_spawn_file_actions_t), false)
102
- Lib.check Lib.posix_spawn_file_actions_init(@ptr)
103
- end
104
-
105
- def add_close(fileno)
106
- Lib.check Lib.posix_spawn_file_actions_addclose(
107
- @ptr,
108
- fileno
109
- )
110
- end
111
-
112
- def add_open(fileno, path, oflag, mode)
113
- Lib.check Lib.posix_spawn_file_actions_addopen(
114
- @ptr,
115
- fileno,
116
- path,
117
- oflag,
118
- mode
119
- )
120
- end
121
-
122
- def add_dup(fileno, new_fileno)
123
- Lib.check Lib.posix_spawn_file_actions_adddup2(
124
- @ptr,
125
- fileno,
126
- new_fileno
127
- )
128
- end
129
-
130
- def free
131
- Lib.check Lib.posix_spawn_file_actions_destroy(@ptr)
132
- @ptr = nil
133
- end
134
-
135
- def to_ptr
136
- @ptr
137
- end
138
- end # FileActions
139
-
140
- class Attrs
141
- def initialize
142
- @ptr = FFI::MemoryPointer.new(1, Platform::SIZEOF.fetch(:posix_spawnattr_t), false)
143
- Lib.check Lib.posix_spawnattr_init(@ptr)
144
- end
145
-
146
- def free
147
- Lib.check Lib.posix_spawnattr_destroy(@ptr)
148
- @ptr = nil
149
- end
150
-
151
- def flags=(flags)
152
- Lib.check Lib.posix_spawnattr_setflags(@ptr, flags)
153
- end
154
-
155
- def flags
156
- ptr = FFI::MemoryPointer.new(:short)
157
- Lib.check Lib.posix_spawnattr_getflags(@ptr, ptr)
158
-
159
- ptr.read_short
160
- end
161
-
162
- def pgroup=(pid)
163
- self.flags |= Platform::POSIX_SPAWN_SETPGROUP
164
- Lib.check Lib.posix_spawnattr_setpgroup(@ptr, pid)
165
- end
166
-
167
- def to_ptr
168
- @ptr
169
- end
170
- end # Attrs
171
-
172
- end
173
- end
174
- end
175
-
176
- # missing on rubinius
177
- class FFI::MemoryPointer
178
- unless method_defined?(:from_string)
179
- def self.from_string(str)
180
- ptr = new(1, str.bytesize + 1)
181
- ptr.write_string("#{str}\0")
182
-
183
- ptr
184
- end
185
- end
186
- end
@@ -1,11 +0,0 @@
1
- module ChildProcess::Unix::Platform
2
- SIZEOF = {
3
- :posix_spawn_file_actions_t => 8,
4
- :posix_spawnattr_t => 8,
5
- :sigset_t => 4
6
- }
7
- POSIX_SPAWN_RESETIDS = 1
8
- POSIX_SPAWN_SETPGROUP = 2
9
- POSIX_SPAWN_SETSIGDEF = 4
10
- POSIX_SPAWN_SETSIGMASK = 8
11
- end
@@ -1,12 +0,0 @@
1
- module ChildProcess::Unix::Platform
2
- SIZEOF = {
3
- :posix_spawn_file_actions_t => 76,
4
- :posix_spawnattr_t => 336,
5
- :sigset_t => 128
6
- }
7
- POSIX_SPAWN_RESETIDS = 1
8
- POSIX_SPAWN_SETPGROUP = 2
9
- POSIX_SPAWN_SETSIGDEF = 4
10
- POSIX_SPAWN_SETSIGMASK = 8
11
- POSIX_SPAWN_USEVFORK = 64
12
- end
@@ -1,11 +0,0 @@
1
- module ChildProcess::Unix::Platform
2
- SIZEOF = {
3
- :posix_spawn_file_actions_t => 4,
4
- :posix_spawnattr_t => 4,
5
- :sigset_t => 16
6
- }
7
- POSIX_SPAWN_RESETIDS = 1
8
- POSIX_SPAWN_SETPGROUP = 2
9
- POSIX_SPAWN_SETSIGDEF = 4
10
- POSIX_SPAWN_SETSIGMASK = 8
11
- end
@@ -1,12 +0,0 @@
1
- module ChildProcess::Unix::Platform
2
- SIZEOF = {
3
- :posix_spawn_file_actions_t => 80,
4
- :posix_spawnattr_t => 336,
5
- :sigset_t => 128
6
- }
7
- POSIX_SPAWN_RESETIDS = 1
8
- POSIX_SPAWN_SETPGROUP = 2
9
- POSIX_SPAWN_SETSIGDEF = 4
10
- POSIX_SPAWN_SETSIGMASK = 8
11
- POSIX_SPAWN_USEVFORK = 64
12
- end
@@ -1,11 +0,0 @@
1
- module ChildProcess::Unix::Platform
2
- SIZEOF = {
3
- :posix_spawn_file_actions_t => 8,
4
- :posix_spawnattr_t => 8,
5
- :sigset_t => 4
6
- }
7
- POSIX_SPAWN_RESETIDS = 1
8
- POSIX_SPAWN_SETPGROUP = 2
9
- POSIX_SPAWN_SETSIGDEF = 4
10
- POSIX_SPAWN_SETSIGMASK = 8
11
- end
@@ -1,134 +0,0 @@
1
- require 'ffi'
2
- require 'thread'
3
-
4
- module ChildProcess
5
- module Unix
6
- class PosixSpawnProcess < Process
7
- private
8
-
9
- @@cwd_lock = Mutex.new
10
-
11
- def launch_process
12
- pid_ptr = FFI::MemoryPointer.new(:pid_t)
13
- actions = Lib::FileActions.new
14
- attrs = Lib::Attrs.new
15
-
16
- if io.stdout
17
- actions.add_dup fileno_for(io.stdout), fileno_for(STDOUT)
18
- else
19
- actions.add_open fileno_for(STDOUT), "/dev/null", File::WRONLY, 0644
20
- end
21
-
22
- if io.stderr
23
- actions.add_dup fileno_for(io.stderr), fileno_for(STDERR)
24
- else
25
- actions.add_open fileno_for(STDERR), "/dev/null", File::WRONLY, 0644
26
- end
27
-
28
- if duplex?
29
- reader, writer = ::IO.pipe
30
- actions.add_dup fileno_for(reader), fileno_for(STDIN)
31
- actions.add_close fileno_for(writer)
32
- end
33
-
34
- attrs.pgroup = 0 if leader?
35
- attrs.flags |= Platform::POSIX_SPAWN_USEVFORK if defined? Platform::POSIX_SPAWN_USEVFORK
36
-
37
- # wrap in helper classes in order to avoid GC'ed pointers
38
- argv = Argv.new(@args)
39
- envp = Envp.new(ENV.to_hash.merge(@environment))
40
-
41
- ret = 0
42
- @@cwd_lock.synchronize do
43
- Dir.chdir(@cwd || Dir.pwd) do
44
- if ChildProcess.jruby?
45
- # on JRuby, the current working directory is for some reason not inherited.
46
- # We'll work around it by making a chdir call through FFI.
47
- # TODO: report this to JRuby
48
- Lib.chdir Dir.pwd
49
- end
50
-
51
- ret = Lib.posix_spawnp(
52
- pid_ptr,
53
- @args.first, # TODO: not sure this matches exec() behaviour
54
- actions,
55
- attrs,
56
- argv,
57
- envp
58
- )
59
- end
60
- end
61
-
62
- if duplex?
63
- io._stdin = writer
64
- reader.close
65
- end
66
-
67
- actions.free
68
- attrs.free
69
-
70
- if ret != 0
71
- raise LaunchError, "#{Lib.strerror(ret)} (#{ret})"
72
- end
73
-
74
- @pid = pid_ptr.read_int
75
- ::Process.detach(@pid) if detach?
76
- end
77
-
78
- if ChildProcess.jruby?
79
- def fileno_for(obj)
80
- ChildProcess::JRuby.posix_fileno_for(obj)
81
- end
82
- else
83
- def fileno_for(obj)
84
- obj.fileno
85
- end
86
- end
87
-
88
- class Argv
89
- def initialize(args)
90
- @ptrs = args.map do |e|
91
- if e.include?("\0")
92
- raise ArgumentError, "argument cannot contain null bytes: #{e.inspect}"
93
- end
94
-
95
- FFI::MemoryPointer.from_string(e.to_s)
96
- end
97
-
98
- @ptrs << FFI::Pointer.new(0)
99
- end
100
-
101
- def to_ptr
102
- argv = FFI::MemoryPointer.new(:pointer, @ptrs.size)
103
- argv.put_array_of_pointer(0, @ptrs)
104
-
105
- argv
106
- end
107
- end # Argv
108
-
109
- class Envp
110
- def initialize(env)
111
- @ptrs = env.map do |key, val|
112
- next if val.nil?
113
-
114
- if key =~ /=|\0/ || val.to_s.include?("\0")
115
- raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.to_s.inspect}"
116
- end
117
-
118
- FFI::MemoryPointer.from_string("#{key}=#{val.to_s}")
119
- end.compact
120
-
121
- @ptrs << FFI::Pointer.new(0)
122
- end
123
-
124
- def to_ptr
125
- env = FFI::MemoryPointer.new(:pointer, @ptrs.size)
126
- env.put_array_of_pointer(0, @ptrs)
127
-
128
- env
129
- end
130
- end # Envp
131
-
132
- end
133
- end
134
- end
@@ -1,91 +0,0 @@
1
- module ChildProcess
2
- module Windows
3
- class Handle
4
-
5
- class << self
6
- private :new
7
-
8
- def open(pid, access = PROCESS_ALL_ACCESS)
9
- handle = Lib.open_process(access, false, pid)
10
-
11
- if handle.null?
12
- raise Error, Lib.last_error_message
13
- end
14
-
15
- h = new(handle, pid)
16
- return h unless block_given?
17
-
18
- begin
19
- yield h
20
- ensure
21
- h.close
22
- end
23
- end
24
- end
25
-
26
- attr_reader :pointer
27
-
28
- def initialize(pointer, pid)
29
- unless pointer.kind_of?(FFI::Pointer)
30
- raise TypeError, "invalid handle: #{pointer.inspect}"
31
- end
32
-
33
- if pointer.null?
34
- raise ArgumentError, "handle is null: #{pointer.inspect}"
35
- end
36
-
37
- @pid = pid
38
- @pointer = pointer
39
- @closed = false
40
- end
41
-
42
- def exit_code
43
- code_pointer = FFI::MemoryPointer.new :ulong
44
- ok = Lib.get_exit_code(@pointer, code_pointer)
45
-
46
- if ok
47
- code_pointer.get_ulong(0)
48
- else
49
- close
50
- raise Error, Lib.last_error_message
51
- end
52
- end
53
-
54
- def send(signal)
55
- case signal
56
- when 0
57
- exit_code == PROCESS_STILL_ALIVE
58
- when WIN_SIGINT
59
- Lib.generate_console_ctrl_event(CTRL_C_EVENT, @pid)
60
- when WIN_SIGBREAK
61
- Lib.generate_console_ctrl_event(CTRL_BREAK_EVENT, @pid)
62
- when WIN_SIGKILL
63
- ok = Lib.terminate_process(@pointer, @pid)
64
- Lib.check_error ok
65
- else
66
- thread_id = FFI::MemoryPointer.new(:ulong)
67
- module_handle = Lib.get_module_handle("kernel32")
68
- proc_address = Lib.get_proc_address(module_handle, "ExitProcess")
69
-
70
- thread = Lib.create_remote_thread(@pointer, 0, 0, proc_address, 0, 0, thread_id)
71
- check_error thread
72
-
73
- Lib.wait_for_single_object(thread, 5)
74
- true
75
- end
76
- end
77
-
78
- def close
79
- return if @closed
80
-
81
- Lib.close_handle(@pointer)
82
- @closed = true
83
- end
84
-
85
- def wait(milliseconds = nil)
86
- Lib.wait_for_single_object(@pointer, milliseconds || INFINITE)
87
- end
88
-
89
- end # Handle
90
- end # Windows
91
- end # ChildProcess