1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
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
|