Merge pull request #4828 from jfhg/unify_waitpid_handling

Unify waitpid handling
This commit is contained in:
Andreas Rumpf 2016-10-09 19:03:12 +02:00 • committed by GitHub
commit f46168d654
3 changed files with 57 additions and 32 deletions

View file

@ -48,7 +48,7 @@ type
inHandle, outHandle, errHandle: FileHandle inHandle, outHandle, errHandle: FileHandle
inStream, outStream, errStream: Stream inStream, outStream, errStream: Stream
id: Pid id: Pid
exitCode: cint exitStatus: cint
options: set[ProcessOption] options: set[ProcessOption]
Process* = ref ProcessObj ## represents an operating system process Process* = ref ProcessObj ## represents an operating system process
@ -731,7 +731,7 @@ elif not defined(useNimRtl):
pStdin, pStdout, pStderr: array[0..1, cint] pStdin, pStdout, pStderr: array[0..1, cint]
new(result) new(result)
result.options = options result.options = options
result.exitCode = -3 # for ``waitForExit`` result.exitStatus = -3 # for ``waitForExit``
if poParentStreams notin options: if poParentStreams notin options:
if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
pipe(pStderr) != 0'i32: pipe(pStderr) != 0'i32:
@ -957,13 +957,10 @@ elif not defined(useNimRtl):
proc running(p: Process): bool = proc running(p: Process): bool =
var ret : int var ret : int
when not defined(freebsd): var status : cint = 1
ret = waitpid(p.id, p.exitCode, WNOHANG) ret = waitpid(p.id, status, WNOHANG)
else: if WIFEXITED(status):
var status : cint = 1 p.exitStatus = status
ret = waitpid(p.id, status, WNOHANG)
if WIFEXITED(status):
p.exitCode = status
if ret == 0: return true # Can't establish status. Assume running. if ret == 0: return true # Can't establish status. Assume running.
result = ret == int(p.id) result = ret == int(p.id)
@ -980,11 +977,12 @@ elif not defined(useNimRtl):
import kqueue, times import kqueue, times
proc waitForExit(p: Process, timeout: int = -1): int = proc waitForExit(p: Process, timeout: int = -1): int =
if p.exitCode != -3: return p.exitCode if p.exitStatus != -3: return int(p.exitStatus) shr 8
if timeout == -1: if timeout == -1:
if waitpid(p.id, p.exitCode, 0) < 0: var status : cint = 1
p.exitCode = -3 if waitpid(p.id, status, 0) < 0:
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
else: else:
var kqFD = kqueue() var kqFD = kqueue()
if kqFD == -1: if kqFD == -1:
@ -1004,6 +1002,7 @@ elif not defined(useNimRtl):
try: try:
while true: while true:
var status : cint = 1
var count = kevent(kqFD, addr(kevIn), 1, addr(kevOut), 1, var count = kevent(kqFD, addr(kevIn), 1, addr(kevOut), 1,
addr(tmspec)) addr(tmspec))
if count < 0: if count < 0:
@ -1014,22 +1013,22 @@ elif not defined(useNimRtl):
# timeout expired, so we trying to kill process # timeout expired, so we trying to kill process
if posix.kill(p.id, SIGKILL) == -1: if posix.kill(p.id, SIGKILL) == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
if waitpid(p.id, p.exitCode, 0) < 0: if waitpid(p.id, status, 0) < 0:
p.exitCode = -3
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
break break
else: else:
if kevOut.ident == p.id.uint and kevOut.filter == EVFILT_PROC: if kevOut.ident == p.id.uint and kevOut.filter == EVFILT_PROC:
if waitpid(p.id, p.exitCode, 0) < 0: if waitpid(p.id, status, 0) < 0:
p.exitCode = -3
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
break break
else: else:
raiseOSError(osLastError()) raiseOSError(osLastError())
finally: finally:
discard posix.close(kqFD) discard posix.close(kqFD)
result = int(p.exitCode) shr 8 result = int(p.exitStatus) shr 8
else: else:
import times import times
@ -1061,15 +1060,16 @@ elif not defined(useNimRtl):
s.tv_sec = b.tv_sec s.tv_sec = b.tv_sec
s.tv_nsec = b.tv_nsec s.tv_nsec = b.tv_nsec
#if waitPid(p.id, p.exitCode, 0) == int(p.id): #if waitPid(p.id, p.exitStatus, 0) == int(p.id):
# ``waitPid`` fails if the process is not running anymore. But then # ``waitPid`` fails if the process is not running anymore. But then
# ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is # ``running`` probably set ``p.exitStatus`` for us. Since ``p.exitStatus`` is
# initialized with -3, wrong success exit codes are prevented. # initialized with -3, wrong success exit codes are prevented.
if p.exitCode != -3: return p.exitCode if p.exitStatus != -3: return int(p.exitStatus) shr 8
if timeout == -1: if timeout == -1:
if waitpid(p.id, p.exitCode, 0) < 0: var status : cint = 1
p.exitCode = -3 if waitpid(p.id, status, 0) < 0:
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
else: else:
var nmask, omask: Sigset var nmask, omask: Sigset
var sinfo: SigInfo var sinfo: SigInfo
@ -1100,9 +1100,10 @@ elif not defined(useNimRtl):
let res = sigtimedwait(nmask, sinfo, tmspec) let res = sigtimedwait(nmask, sinfo, tmspec)
if res == SIGCHLD: if res == SIGCHLD:
if sinfo.si_pid == p.id: if sinfo.si_pid == p.id:
if waitpid(p.id, p.exitCode, 0) < 0: var status : cint = 1
p.exitCode = -3 if waitpid(p.id, status, 0) < 0:
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
break break
else: else:
# we have SIGCHLD, but not for process we are waiting, # we have SIGCHLD, but not for process we are waiting,
@ -1122,9 +1123,10 @@ elif not defined(useNimRtl):
# timeout expired, so we trying to kill process # timeout expired, so we trying to kill process
if posix.kill(p.id, SIGKILL) == -1: if posix.kill(p.id, SIGKILL) == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
if waitpid(p.id, p.exitCode, 0) < 0: var status : cint = 1
p.exitCode = -3 if waitpid(p.id, status, 0) < 0:
raiseOSError(osLastError()) raiseOSError(osLastError())
p.exitStatus = status
break break
else: else:
raiseOSError(err) raiseOSError(err)
@ -1136,17 +1138,19 @@ elif not defined(useNimRtl):
if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1: if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
result = int(p.exitCode) shr 8 result = int(p.exitStatus) shr 8
proc peekExitCode(p: Process): int = proc peekExitCode(p: Process): int =
if p.exitCode != -3: return p.exitCode var status : cint = 1
var ret = waitpid(p.id, p.exitCode, WNOHANG) if p.exitStatus != -3: return int(p.exitStatus) shr 8
var ret = waitpid(p.id, status, WNOHANG)
var b = ret == int(p.id) var b = ret == int(p.id)
if b: result = -1 if b: result = -1
if not WIFEXITED(p.exitCode): if WIFEXITED(status):
p.exitCode = -3 p.exitStatus = status
result = p.exitStatus.int shr 8
else:
result = -1 result = -1
else: result = p.exitCode.int shr 8
proc createStream(stream: var Stream, handle: var FileHandle, proc createStream(stream: var Stream, handle: var FileHandle,
fileMode: FileMode) = fileMode: FileMode) =

3
tests/osproc/tafalse.nim Normal file
View file

@ -0,0 +1,3 @@
# 'tafalse.nim' to ensure it is compiled before texitcode.nim
import system
quit(QuitFailure)

View file

@ -0,0 +1,18 @@
discard """
file: "texitcode.nim"
output: ""
"""
import osproc, os
const filename = when defined(Windows): "tafalse.exe" else: "tafalse"
let dir = getCurrentDir() / "tests" / "osproc"
doAssert fileExists(dir / filename)
var p = startProcess(filename, dir)
doAssert(waitForExit(p) == QuitFailure)
p = startProcess(filename, dir)
var running = true
while running:
running = running(p)
doAssert(waitForExit(p) == QuitFailure)