childprocess 4.1.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +32 -0
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile +3 -2
  5. data/README.md +5 -23
  6. data/childprocess.gemspec +2 -0
  7. data/lib/childprocess/abstract_process.rb +1 -1
  8. data/lib/childprocess/errors.rb +0 -21
  9. data/lib/childprocess/process_spawn_process.rb +127 -0
  10. data/lib/childprocess/unix/process.rb +3 -64
  11. data/lib/childprocess/unix.rb +2 -4
  12. data/lib/childprocess/version.rb +1 -1
  13. data/lib/childprocess/windows/process.rb +13 -116
  14. data/lib/childprocess/windows.rb +0 -29
  15. data/lib/childprocess.rb +16 -53
  16. data/spec/childprocess_spec.rb +39 -15
  17. data/spec/io_spec.rb +1 -1
  18. data/spec/spec_helper.rb +5 -20
  19. data/spec/unix_spec.rb +3 -7
  20. metadata +19 -24
  21. data/.travis.yml +0 -37
  22. data/appveyor.yml +0 -36
  23. data/lib/childprocess/jruby/io.rb +0 -16
  24. data/lib/childprocess/jruby/process.rb +0 -184
  25. data/lib/childprocess/jruby/pump.rb +0 -53
  26. data/lib/childprocess/jruby.rb +0 -56
  27. data/lib/childprocess/tools/generator.rb +0 -146
  28. data/lib/childprocess/unix/fork_exec_process.rb +0 -78
  29. data/lib/childprocess/unix/lib.rb +0 -186
  30. data/lib/childprocess/unix/platform/arm64-macosx.rb +0 -11
  31. data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
  32. data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
  33. data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
  34. data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
  35. data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
  36. data/lib/childprocess/windows/handle.rb +0 -91
  37. data/lib/childprocess/windows/lib.rb +0 -416
  38. data/lib/childprocess/windows/process_builder.rb +0 -178
  39. data/lib/childprocess/windows/structs.rb +0 -149
  40. data/spec/jruby_spec.rb +0 -24
@@ -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
@@ -1,416 +0,0 @@
1
- module ChildProcess
2
- module Windows
3
- FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
4
- FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
5
-
6
- PROCESS_ALL_ACCESS = 0x1F0FFF
7
- PROCESS_QUERY_INFORMATION = 0x0400
8
- PROCESS_VM_READ = 0x0010
9
- PROCESS_STILL_ACTIVE = 259
10
-
11
- INFINITE = 0xFFFFFFFF
12
-
13
- WIN_SIGINT = 2
14
- WIN_SIGBREAK = 3
15
- WIN_SIGKILL = 9
16
-
17
- CTRL_C_EVENT = 0
18
- CTRL_BREAK_EVENT = 1
19
-
20
- CREATE_BREAKAWAY_FROM_JOB = 0x01000000
21
- DETACHED_PROCESS = 0x00000008
22
-
23
- STARTF_USESTDHANDLES = 0x00000100
24
- INVALID_HANDLE_VALUE = -1
25
- HANDLE_FLAG_INHERIT = 0x00000001
26
-
27
- DUPLICATE_SAME_ACCESS = 0x00000002
28
- CREATE_UNICODE_ENVIRONMENT = 0x00000400
29
-
30
- JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000
31
- JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
32
- JOB_OBJECT_EXTENDED_LIMIT_INFORMATION = 9
33
- JOB_OBJECT_BASIC_LIMIT_INFORMATION = 2
34
-
35
- module Lib
36
- enum :wait_status, [
37
- :wait_object_0, 0,
38
- :wait_timeout, 0x102,
39
- :wait_abandoned, 0x80,
40
- :wait_failed, 0xFFFFFFFF
41
- ]
42
-
43
- #
44
- # BOOL WINAPI CreateProcess(
45
- # __in_opt LPCTSTR lpApplicationName,
46
- # __inout_opt LPTSTR lpCommandLine,
47
- # __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
48
- # __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
49
- # __in BOOL bInheritHandles,
50
- # __in DWORD dwCreationFlags,
51
- # __in_opt LPVOID lpEnvironment,
52
- # __in_opt LPCTSTR lpCurrentDirectory,
53
- # __in LPSTARTUPINFO lpStartupInfo,
54
- # __out LPPROCESS_INFORMATION lpProcessInformation
55
- # );
56
- #
57
-
58
- attach_function :create_process, :CreateProcessW, [
59
- :pointer,
60
- :buffer_inout,
61
- :pointer,
62
- :pointer,
63
- :bool,
64
- :ulong,
65
- :pointer,
66
- :pointer,
67
- :pointer,
68
- :pointer], :bool
69
-
70
- #
71
- # DWORD WINAPI FormatMessage(
72
- # __in DWORD dwFlags,
73
- # __in_opt LPCVOID lpSource,
74
- # __in DWORD dwMessageId,
75
- # __in DWORD dwLanguageId,
76
- # __out LPTSTR lpBuffer,
77
- # __in DWORD nSize,
78
- # __in_opt va_list *Arguments
79
- # );
80
- #
81
-
82
- attach_function :format_message, :FormatMessageA, [
83
- :ulong,
84
- :pointer,
85
- :ulong,
86
- :ulong,
87
- :pointer,
88
- :ulong,
89
- :pointer], :ulong
90
-
91
-
92
- attach_function :close_handle, :CloseHandle, [:pointer], :bool
93
-
94
- #
95
- # HANDLE WINAPI OpenProcess(
96
- # __in DWORD dwDesiredAccess,
97
- # __in BOOL bInheritHandle,
98
- # __in DWORD dwProcessId
99
- # );
100
- #
101
-
102
- attach_function :open_process, :OpenProcess, [:ulong, :bool, :ulong], :pointer
103
-
104
- #
105
- # HANDLE WINAPI CreateJobObject(
106
- # _In_opt_ LPSECURITY_ATTRIBUTES lpJobAttributes,
107
- # _In_opt_ LPCTSTR lpName
108
- # );
109
- #
110
-
111
- attach_function :create_job_object, :CreateJobObjectA, [:pointer, :pointer], :pointer
112
-
113
- #
114
- # BOOL WINAPI AssignProcessToJobObject(
115
- # _In_ HANDLE hJob,
116
- # _In_ HANDLE hProcess
117
- # );
118
-
119
- attach_function :assign_process_to_job_object, :AssignProcessToJobObject, [:pointer, :pointer], :bool
120
-
121
- #
122
- # BOOL WINAPI SetInformationJobObject(
123
- # _In_ HANDLE hJob,
124
- # _In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
125
- # _In_ LPVOID lpJobObjectInfo,
126
- # _In_ DWORD cbJobObjectInfoLength
127
- # );
128
- #
129
-
130
- attach_function :set_information_job_object, :SetInformationJobObject, [:pointer, :int, :pointer, :ulong], :bool
131
-
132
- #
133
- #
134
- # DWORD WINAPI WaitForSingleObject(
135
- # __in HANDLE hHandle,
136
- # __in DWORD dwMilliseconds
137
- # );
138
- #
139
-
140
- attach_function :wait_for_single_object, :WaitForSingleObject, [:pointer, :ulong], :wait_status, :blocking => true
141
-
142
- #
143
- # BOOL WINAPI GetExitCodeProcess(
144
- # __in HANDLE hProcess,
145
- # __out LPDWORD lpExitCode
146
- # );
147
- #
148
-
149
- attach_function :get_exit_code, :GetExitCodeProcess, [:pointer, :pointer], :bool
150
-
151
- #
152
- # BOOL WINAPI GenerateConsoleCtrlEvent(
153
- # __in DWORD dwCtrlEvent,
154
- # __in DWORD dwProcessGroupId
155
- # );
156
- #
157
-
158
- attach_function :generate_console_ctrl_event, :GenerateConsoleCtrlEvent, [:ulong, :ulong], :bool
159
-
160
- #
161
- # BOOL WINAPI TerminateProcess(
162
- # __in HANDLE hProcess,
163
- # __in UINT uExitCode
164
- # );
165
- #
166
-
167
- attach_function :terminate_process, :TerminateProcess, [:pointer, :uint], :bool
168
-
169
- #
170
- # intptr_t _get_osfhandle(
171
- # int fd
172
- # );
173
- #
174
-
175
- attach_function :get_osfhandle, :_get_osfhandle, [:int], :intptr_t
176
-
177
- #
178
- # int _open_osfhandle (
179
- # intptr_t osfhandle,
180
- # int flags
181
- # );
182
- #
183
-
184
- attach_function :open_osfhandle, :_open_osfhandle, [:pointer, :int], :int
185
-
186
- # BOOL WINAPI SetHandleInformation(
187
- # __in HANDLE hObject,
188
- # __in DWORD dwMask,
189
- # __in DWORD dwFlags
190
- # );
191
-
192
- attach_function :set_handle_information, :SetHandleInformation, [:pointer, :ulong, :ulong], :bool
193
-
194
- # BOOL WINAPI GetHandleInformation(
195
- # __in HANDLE hObject,
196
- # __out LPDWORD lpdwFlags
197
- # );
198
-
199
- attach_function :get_handle_information, :GetHandleInformation, [:pointer, :pointer], :bool
200
-
201
- # BOOL WINAPI CreatePipe(
202
- # __out PHANDLE hReadPipe,
203
- # __out PHANDLE hWritePipe,
204
- # __in_opt LPSECURITY_ATTRIBUTES lpPipeAttributes,
205
- # __in DWORD nSize
206
- # );
207
-
208
- attach_function :create_pipe, :CreatePipe, [:pointer, :pointer, :pointer, :ulong], :bool
209
-
210
- #
211
- # HANDLE WINAPI GetCurrentProcess(void);
212
- #
213
-
214
- attach_function :current_process, :GetCurrentProcess, [], :pointer
215
-
216
- #
217
- # BOOL WINAPI DuplicateHandle(
218
- # __in HANDLE hSourceProcessHandle,
219
- # __in HANDLE hSourceHandle,
220
- # __in HANDLE hTargetProcessHandle,
221
- # __out LPHANDLE lpTargetHandle,
222
- # __in DWORD dwDesiredAccess,
223
- # __in BOOL bInheritHandle,
224
- # __in DWORD dwOptions
225
- # );
226
- #
227
-
228
- attach_function :_duplicate_handle, :DuplicateHandle, [
229
- :pointer,
230
- :pointer,
231
- :pointer,
232
- :pointer,
233
- :ulong,
234
- :bool,
235
- :ulong
236
- ], :bool
237
-
238
- class << self
239
- def kill(signal, *pids)
240
- case signal
241
- when 'SIGINT', 'INT', :SIGINT, :INT
242
- signal = WIN_SIGINT
243
- when 'SIGBRK', 'BRK', :SIGBREAK, :BRK
244
- signal = WIN_SIGBREAK
245
- when 'SIGKILL', 'KILL', :SIGKILL, :KILL
246
- signal = WIN_SIGKILL
247
- when 0..9
248
- # Do nothing
249
- else
250
- raise Error, "invalid signal #{signal.inspect}"
251
- end
252
-
253
- pids.map { |pid| pid if Lib.send_signal(signal, pid) }.compact
254
- end
255
-
256
- def waitpid(pid, flags = 0)
257
- wait_for_pid(pid, no_hang?(flags))
258
- end
259
-
260
- def waitpid2(pid, flags = 0)
261
- code = wait_for_pid(pid, no_hang?(flags))
262
-
263
- [pid, code] if code
264
- end
265
-
266
- def dont_inherit(file)
267
- unless file.respond_to?(:fileno)
268
- raise ArgumentError, "expected #{file.inspect} to respond to :fileno"
269
- end
270
-
271
- set_handle_inheritance(handle_for(file.fileno), false)
272
- end
273
-
274
- def last_error_message
275
- errnum = FFI.errno
276
-
277
- buf = FFI::MemoryPointer.new :char, 512
278
-
279
- size = format_message(
280
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
281
- nil, errnum, 0, buf, buf.size, nil
282
- )
283
-
284
- str = buf.read_string(size).strip
285
- if errnum == 0
286
- "Unknown error (Windows says #{str.inspect}, but it did not.)"
287
- else
288
- "#{str} (#{errnum})"
289
- end
290
- end
291
-
292
- def each_child_of(pid, &blk)
293
- raise NotImplementedError
294
-
295
- # http://stackoverflow.com/questions/1173342/terminate-a-process-tree-c-for-windows?rq=1
296
-
297
- # for each process entry
298
- # if pe.th32ParentProcessID == pid
299
- # Handle.open(pe.pe.th32ProcessId, &blk)
300
- # end
301
- #
302
- end
303
-
304
- def handle_for(fd_or_io)
305
- if fd_or_io.kind_of?(IO) || fd_or_io.respond_to?(:fileno)
306
- if ChildProcess.jruby?
307
- handle = ChildProcess::JRuby.windows_handle_for(fd_or_io)
308
- else
309
- handle = get_osfhandle(fd_or_io.fileno)
310
- end
311
- elsif fd_or_io.kind_of?(Integer)
312
- handle = get_osfhandle(fd_or_io)
313
- elsif fd_or_io.respond_to?(:to_io)
314
- io = fd_or_io.to_io
315
-
316
- unless io.kind_of?(IO)
317
- raise TypeError, "expected #to_io to return an instance of IO"
318
- end
319
-
320
- handle = get_osfhandle(io.fileno)
321
- else
322
- raise TypeError, "invalid type: #{fd_or_io.inspect}"
323
- end
324
-
325
- if handle == INVALID_HANDLE_VALUE
326
- raise Error, last_error_message
327
- end
328
-
329
- FFI::Pointer.new handle
330
- end
331
-
332
- def io_for(handle, flags = File::RDONLY)
333
- fd = open_osfhandle(handle, flags)
334
- if fd == -1
335
- raise Error, last_error_message
336
- end
337
-
338
- FFI::IO.for_fd fd, flags
339
- end
340
-
341
- def duplicate_handle(handle)
342
- dup = FFI::MemoryPointer.new(:pointer)
343
- proc = current_process
344
-
345
- ok = Lib._duplicate_handle(
346
- proc,
347
- handle,
348
- proc,
349
- dup,
350
- 0,
351
- false,
352
- DUPLICATE_SAME_ACCESS
353
- )
354
-
355
- check_error ok
356
-
357
- dup.read_pointer
358
- ensure
359
- close_handle proc
360
- end
361
-
362
- def set_handle_inheritance(handle, bool)
363
- status = set_handle_information(
364
- handle,
365
- HANDLE_FLAG_INHERIT,
366
- bool ? HANDLE_FLAG_INHERIT : 0
367
- )
368
-
369
- check_error status
370
- end
371
-
372
- def get_handle_inheritance(handle)
373
- flags = FFI::MemoryPointer.new(:uint)
374
-
375
- status = get_handle_information(
376
- handle,
377
- flags
378
- )
379
-
380
- check_error status
381
-
382
- flags.read_uint
383
- end
384
-
385
- def check_error(bool)
386
- bool or raise Error, last_error_message
387
- end
388
-
389
- def alive?(pid)
390
- handle = Lib.open_process(PROCESS_ALL_ACCESS, false, pid)
391
- if handle.null?
392
- false
393
- else
394
- ptr = FFI::MemoryPointer.new :ulong
395
- Lib.check_error Lib.get_exit_code(handle, ptr)
396
- ptr.read_ulong == PROCESS_STILL_ACTIVE
397
- end
398
- end
399
-
400
- def no_hang?(flags)
401
- (flags & Process::WNOHANG) == Process::WNOHANG
402
- end
403
-
404
- def wait_for_pid(pid, no_hang)
405
- code = Handle.open(pid) { |handle|
406
- handle.wait unless no_hang
407
- handle.exit_code
408
- }
409
-
410
- code if code != PROCESS_STILL_ACTIVE
411
- end
412
- end
413
-
414
- end # Lib
415
- end # Windows
416
- end # ChildProcess