File: //usr/lib/ruby/vendor_ruby/childprocess/windows/process.rb
module ChildProcess
module Windows
class Process < AbstractProcess
attr_reader :pid
def io
@io ||= Windows::IO.new
end
def stop(timeout = 3)
assert_started
log "sending KILL"
@handle.send(WIN_SIGKILL)
poll_for_exit(timeout)
ensure
close_handle
close_job_if_necessary
end
def wait
if exited?
exit_code
else
@handle.wait
@exit_code = @handle.exit_code
close_handle
close_job_if_necessary
@exit_code
end
end
def exited?
return true if @exit_code
assert_started
code = @handle.exit_code
exited = code != PROCESS_STILL_ACTIVE
log(:exited? => exited, :code => code)
if exited
@exit_code = code
close_handle
close_job_if_necessary
end
exited
end
private
def launch_process
builder = ProcessBuilder.new(@args)
builder.leader = leader?
builder.detach = detach?
builder.duplex = duplex?
builder.environment = @environment unless @environment.empty?
builder.cwd = @cwd
if @io
builder.stdout = @io.stdout
builder.stderr = @io.stderr
end
@pid = builder.start
@handle = Handle.open @pid
if leader?
@job = Job.new(detach?, true)
@job << @handle
end
if duplex?
raise Error, "no stdin stream" unless builder.stdin
io._stdin = builder.stdin
end
self
end
def close_handle
@handle.close
end
def close_job_if_necessary
@job.close if leader?
end
class Job
def initialize(detach, leader)
@pointer = Lib.create_job_object(nil, nil)
if @pointer.nil? || @pointer.null?
raise Error, "unable to create job object"
end
basic = JobObjectBasicLimitInformation.new
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE if !detach
basic[:LimitFlags] |= JOB_OBJECT_LIMIT_BREAKAWAY_OK if leader
extended = JobObjectExtendedLimitInformation.new
extended[:BasicLimitInformation] = basic
ret = Lib.set_information_job_object(
@pointer,
JOB_OBJECT_EXTENDED_LIMIT_INFORMATION,
extended,
extended.size
)
Lib.check_error ret
end
def <<(handle)
Lib.check_error Lib.assign_process_to_job_object(@pointer, handle.pointer)
end
def close
Lib.close_handle @pointer
end
end
end # Process
end # Windows
end # ChildProcess