Merge branch 'cheatfate-nosproc3' into devel
This commit is contained in:
commit
d550417f8b
2 changed files with 107 additions and 61 deletions
|
|
@ -47,6 +47,7 @@ type
|
||||||
ProcessObj = object of RootObj
|
ProcessObj = object of RootObj
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
fProcessHandle: Handle
|
fProcessHandle: Handle
|
||||||
|
fThreadHandle: Handle
|
||||||
inHandle, outHandle, errHandle: FileHandle
|
inHandle, outHandle, errHandle: FileHandle
|
||||||
id: Handle
|
id: Handle
|
||||||
else:
|
else:
|
||||||
|
|
@ -54,6 +55,7 @@ type
|
||||||
inStream, outStream, errStream: Stream
|
inStream, outStream, errStream: Stream
|
||||||
id: Pid
|
id: Pid
|
||||||
exitStatus: cint
|
exitStatus: cint
|
||||||
|
exitFlag: bool
|
||||||
options: set[ProcessOption]
|
options: set[ProcessOption]
|
||||||
|
|
||||||
Process* = ref ProcessObj ## represents an operating system process
|
Process* = ref ProcessObj ## represents an operating system process
|
||||||
|
|
@ -237,11 +239,13 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
if n > 1:
|
if n > 1:
|
||||||
var i = 0
|
var i = 0
|
||||||
var q = newSeq[Process](n)
|
var q = newSeq[Process](n)
|
||||||
var m = min(n, cmds.len)
|
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var w: WOHandleArray
|
var w: WOHandleArray
|
||||||
|
var m = min(min(n, MAXIMUM_WAIT_OBJECTS), cmds.len)
|
||||||
var wcount = m
|
var wcount = m
|
||||||
|
else:
|
||||||
|
var m = min(n, cmds.len)
|
||||||
|
|
||||||
while i < m:
|
while i < m:
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
|
|
@ -253,6 +257,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
|
|
||||||
var ecount = len(cmds)
|
var ecount = len(cmds)
|
||||||
while ecount > 0:
|
while ecount > 0:
|
||||||
|
var rexit = -1
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# waiting for all children, get result if any child exits
|
# waiting for all children, get result if any child exits
|
||||||
var ret = waitForMultipleObjects(int32(wcount), addr(w), 0'i32,
|
var ret = waitForMultipleObjects(int32(wcount), addr(w), 0'i32,
|
||||||
|
|
@ -262,6 +267,15 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
discard
|
discard
|
||||||
elif ret == WAIT_FAILED:
|
elif ret == WAIT_FAILED:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
else:
|
||||||
|
var status: int32
|
||||||
|
for r in 0..m-1:
|
||||||
|
if not isNil(q[r]) and q[r].fProcessHandle == w[ret]:
|
||||||
|
discard getExitCodeProcess(q[r].fProcessHandle, status)
|
||||||
|
q[r].exitFlag = true
|
||||||
|
q[r].exitStatus = status
|
||||||
|
rexit = r
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
# waiting for all children, get result if any child exits
|
# waiting for all children, get result if any child exits
|
||||||
|
|
@ -269,15 +283,21 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
if res > 0:
|
if res > 0:
|
||||||
for r in 0..m-1:
|
for r in 0..m-1:
|
||||||
if not isNil(q[r]) and q[r].id == res:
|
if not isNil(q[r]) and q[r].id == res:
|
||||||
# we updating `exitStatus` manually, so `running()` can work.
|
|
||||||
if WIFEXITED(status) or WIFSIGNALED(status):
|
if WIFEXITED(status) or WIFSIGNALED(status):
|
||||||
|
q[r].exitFlag = true
|
||||||
q[r].exitStatus = status
|
q[r].exitStatus = status
|
||||||
|
rexit = r
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if err == OSErrorCode(ECHILD):
|
if err == OSErrorCode(ECHILD):
|
||||||
# some child exits, we need to check our childs exit codes
|
# some child exits, we need to check our childs exit codes
|
||||||
discard
|
for r in 0..m-1:
|
||||||
|
if (not isNil(q[r])) and (not running(q[r])):
|
||||||
|
q[r].exitFlag = true
|
||||||
|
q[r].exitStatus = status
|
||||||
|
rexit = r
|
||||||
|
break
|
||||||
elif err == OSErrorCode(EINTR):
|
elif err == OSErrorCode(EINTR):
|
||||||
# signal interrupted our syscall, lets repeat it
|
# signal interrupted our syscall, lets repeat it
|
||||||
continue
|
continue
|
||||||
|
|
@ -285,25 +305,26 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
# all other errors are exceptions
|
# all other errors are exceptions
|
||||||
raiseOSError(err)
|
raiseOSError(err)
|
||||||
|
|
||||||
for r in 0..m-1:
|
if rexit >= 0:
|
||||||
if not isNil(q[r]):
|
result = max(result, q[rexit].peekExitCode())
|
||||||
if not running(q[r]):
|
if afterRunEvent != nil: afterRunEvent(rexit, q[rexit])
|
||||||
result = max(result, q[r].peekExitCode())
|
close(q[rexit])
|
||||||
if afterRunEvent != nil: afterRunEvent(r, q[r])
|
|
||||||
close(q[r])
|
|
||||||
if i < len(cmds):
|
if i < len(cmds):
|
||||||
if beforeRunEvent != nil: beforeRunEvent(i)
|
if beforeRunEvent != nil: beforeRunEvent(i)
|
||||||
q[r] = startProcess(cmds[i],
|
q[rexit] = startProcess(cmds[i],
|
||||||
options = options + {poEvalCommand})
|
options = options + {poEvalCommand})
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
w[r] = q[r].fProcessHandle
|
w[rexit] = q[rexit].fProcessHandle
|
||||||
inc(i)
|
inc(i)
|
||||||
else:
|
else:
|
||||||
q[r] = nil
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
for c in r..MAXIMUM_WAIT_OBJECTS - 2:
|
for k in 0..wcount - 1:
|
||||||
w[c] = w[c + 1]
|
if w[k] == q[rexit].fProcessHandle:
|
||||||
|
w[k] = w[wcount - 1]
|
||||||
|
w[wcount - 1] = 0
|
||||||
dec(wcount)
|
dec(wcount)
|
||||||
|
break
|
||||||
|
q[rexit] = nil
|
||||||
dec(ecount)
|
dec(ecount)
|
||||||
else:
|
else:
|
||||||
for i in 0..high(cmds):
|
for i in 0..high(cmds):
|
||||||
|
|
@ -491,6 +512,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
hi, ho, he: Handle
|
hi, ho, he: Handle
|
||||||
new(result)
|
new(result)
|
||||||
result.options = options
|
result.options = options
|
||||||
|
result.exitFlag = true
|
||||||
si.cb = sizeof(si).cint
|
si.cb = sizeof(si).cint
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
|
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
|
||||||
|
|
@ -559,27 +581,30 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
"Requested command not found: '$1'. OS error:" % command)
|
"Requested command not found: '$1'. OS error:" % command)
|
||||||
else:
|
else:
|
||||||
raiseOSError(lastError, command)
|
raiseOSError(lastError, command)
|
||||||
# Close the handle now so anyone waiting is woken:
|
|
||||||
discard closeHandle(procInfo.hThread)
|
|
||||||
result.fProcessHandle = procInfo.hProcess
|
result.fProcessHandle = procInfo.hProcess
|
||||||
|
result.fThreadHandle = procInfo.hThread
|
||||||
result.id = procInfo.dwProcessId
|
result.id = procInfo.dwProcessId
|
||||||
|
result.exitFlag = false
|
||||||
|
|
||||||
proc close(p: Process) =
|
proc close(p: Process) =
|
||||||
if poInteractive in p.options:
|
if poParentStreams notin p.options:
|
||||||
# somehow this is not always required on Windows:
|
|
||||||
discard closeHandle(p.inHandle)
|
discard closeHandle(p.inHandle)
|
||||||
discard closeHandle(p.outHandle)
|
discard closeHandle(p.outHandle)
|
||||||
discard closeHandle(p.errHandle)
|
discard closeHandle(p.errHandle)
|
||||||
#discard closeHandle(p.FProcessHandle)
|
discard closeHandle(p.fThreadHandle)
|
||||||
|
discard closeHandle(p.fProcessHandle)
|
||||||
|
|
||||||
proc suspend(p: Process) =
|
proc suspend(p: Process) =
|
||||||
discard suspendThread(p.fProcessHandle)
|
discard suspendThread(p.fThreadHandle)
|
||||||
|
|
||||||
proc resume(p: Process) =
|
proc resume(p: Process) =
|
||||||
discard resumeThread(p.fProcessHandle)
|
discard resumeThread(p.fThreadHandle)
|
||||||
|
|
||||||
proc running(p: Process): bool =
|
proc running(p: Process): bool =
|
||||||
var x = waitForSingleObject(p.fProcessHandle, 50)
|
if p.exitFlag:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
var x = waitForSingleObject(p.fProcessHandle, 0)
|
||||||
return x == WAIT_TIMEOUT
|
return x == WAIT_TIMEOUT
|
||||||
|
|
||||||
proc terminate(p: Process) =
|
proc terminate(p: Process) =
|
||||||
|
|
@ -590,22 +615,37 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
terminate(p)
|
terminate(p)
|
||||||
|
|
||||||
proc waitForExit(p: Process, timeout: int = -1): int =
|
proc waitForExit(p: Process, timeout: int = -1): int =
|
||||||
discard waitForSingleObject(p.fProcessHandle, timeout.int32)
|
if p.exitFlag:
|
||||||
|
return p.exitStatus
|
||||||
|
|
||||||
var res: int32
|
let res = waitForSingleObject(p.fProcessHandle, timeout.int32)
|
||||||
discard getExitCodeProcess(p.fProcessHandle, res)
|
if res == WAIT_TIMEOUT:
|
||||||
result = res
|
terminate(p)
|
||||||
p.exitStatus = res
|
var status: int32
|
||||||
|
discard getExitCodeProcess(p.fProcessHandle, status)
|
||||||
|
if status != STILL_ACTIVE:
|
||||||
|
p.exitFlag = true
|
||||||
|
p.exitStatus = status
|
||||||
|
discard closeHandle(p.fThreadHandle)
|
||||||
discard closeHandle(p.fProcessHandle)
|
discard closeHandle(p.fProcessHandle)
|
||||||
|
result = status
|
||||||
|
else:
|
||||||
|
result = -1
|
||||||
|
|
||||||
proc peekExitCode(p: Process): int =
|
proc peekExitCode(p: Process): int =
|
||||||
var b = waitForSingleObject(p.fProcessHandle, 50) == WAIT_TIMEOUT
|
if p.exitFlag:
|
||||||
if b: result = -1
|
return p.exitStatus
|
||||||
else:
|
|
||||||
var res: int32
|
result = -1
|
||||||
discard getExitCodeProcess(p.fProcessHandle, res)
|
var b = waitForSingleObject(p.fProcessHandle, 0) == WAIT_TIMEOUT
|
||||||
if res == 0: return p.exitStatus
|
if not b:
|
||||||
return res
|
var status: int32
|
||||||
|
discard getExitCodeProcess(p.fProcessHandle, status)
|
||||||
|
p.exitFlag = true
|
||||||
|
p.exitStatus = status
|
||||||
|
discard closeHandle(p.fThreadHandle)
|
||||||
|
discard closeHandle(p.fProcessHandle)
|
||||||
|
result = status
|
||||||
|
|
||||||
proc inputStream(p: Process): Stream =
|
proc inputStream(p: Process): Stream =
|
||||||
streamAccess(p)
|
streamAccess(p)
|
||||||
|
|
@ -737,7 +777,8 @@ 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.exitStatus = -3 # for ``waitForExit``
|
result.exitFlag = true
|
||||||
|
|
||||||
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:
|
||||||
|
|
@ -792,6 +833,7 @@ elif not defined(useNimRtl):
|
||||||
if poEchoCmd in options:
|
if poEchoCmd in options:
|
||||||
echo(command, " ", join(args, " "))
|
echo(command, " ", join(args, " "))
|
||||||
result.id = pid
|
result.id = pid
|
||||||
|
result.exitFlag = false
|
||||||
|
|
||||||
if poParentStreams in options:
|
if poParentStreams in options:
|
||||||
# does not make much sense, but better than nothing:
|
# does not make much sense, but better than nothing:
|
||||||
|
|
@ -968,14 +1010,14 @@ elif not defined(useNimRtl):
|
||||||
if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError())
|
if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError())
|
||||||
|
|
||||||
proc running(p: Process): bool =
|
proc running(p: Process): bool =
|
||||||
if p.exitStatus != -3:
|
if p.exitFlag:
|
||||||
return false
|
return false
|
||||||
else:
|
else:
|
||||||
var ret : int
|
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
ret = waitpid(p.id, status, WNOHANG)
|
let ret = waitpid(p.id, status, WNOHANG)
|
||||||
if ret == int(p.id):
|
if ret == int(p.id):
|
||||||
if isExitStatus(status):
|
if isExitStatus(status):
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
return false
|
return false
|
||||||
else:
|
else:
|
||||||
|
|
@ -998,13 +1040,14 @@ 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.exitStatus != -3:
|
if p.exitFlag:
|
||||||
return exitStatus(p.exitStatus)
|
return exitStatus(p.exitStatus)
|
||||||
|
|
||||||
if timeout == -1:
|
if timeout == -1:
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
if waitpid(p.id, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
else:
|
else:
|
||||||
var kqFD = kqueue()
|
var kqFD = kqueue()
|
||||||
|
|
@ -1038,12 +1081,14 @@ elif not defined(useNimRtl):
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
if waitpid(p.id, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
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, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
@ -1083,17 +1128,14 @@ 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.exitStatus, 0) == int(p.id):
|
if p.exitFlag:
|
||||||
# ``waitPid`` fails if the process is not running anymore. But then
|
|
||||||
# ``running`` probably set ``p.exitStatus`` for us. Since ``p.exitStatus`` is
|
|
||||||
# initialized with -3, wrong success exit codes are prevented.
|
|
||||||
if p.exitStatus != -3:
|
|
||||||
return exitStatus(p.exitStatus)
|
return exitStatus(p.exitStatus)
|
||||||
|
|
||||||
if timeout == -1:
|
if timeout == -1:
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
if waitpid(p.id, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
else:
|
else:
|
||||||
var nmask, omask: Sigset
|
var nmask, omask: Sigset
|
||||||
|
|
@ -1128,6 +1170,7 @@ elif not defined(useNimRtl):
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
if waitpid(p.id, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
@ -1151,6 +1194,7 @@ elif not defined(useNimRtl):
|
||||||
var status: cint = 1
|
var status: cint = 1
|
||||||
if waitpid(p.id, status, 0) < 0:
|
if waitpid(p.id, status, 0) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
@ -1168,12 +1212,13 @@ elif not defined(useNimRtl):
|
||||||
proc peekExitCode(p: Process): int =
|
proc peekExitCode(p: Process): int =
|
||||||
var status = cint(0)
|
var status = cint(0)
|
||||||
result = -1
|
result = -1
|
||||||
if p.exitStatus != -3:
|
if p.exitFlag:
|
||||||
return exitStatus(p.exitStatus)
|
return exitStatus(p.exitStatus)
|
||||||
|
|
||||||
var ret = waitpid(p.id, status, WNOHANG)
|
var ret = waitpid(p.id, status, WNOHANG)
|
||||||
if ret > 0:
|
if ret > 0:
|
||||||
if isExitStatus(status):
|
if isExitStatus(status):
|
||||||
|
p.exitFlag = true
|
||||||
p.exitStatus = status
|
p.exitStatus = status
|
||||||
result = exitStatus(status)
|
result = exitStatus(status)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ const
|
||||||
WAIT_TIMEOUT* = 0x00000102'i32
|
WAIT_TIMEOUT* = 0x00000102'i32
|
||||||
WAIT_FAILED* = 0xFFFFFFFF'i32
|
WAIT_FAILED* = 0xFFFFFFFF'i32
|
||||||
INFINITE* = -1'i32
|
INFINITE* = -1'i32
|
||||||
|
STILL_ACTIVE* = 0x00000103'i32
|
||||||
|
|
||||||
STD_INPUT_HANDLE* = -10'i32
|
STD_INPUT_HANDLE* = -10'i32
|
||||||
STD_OUTPUT_HANDLE* = -11'i32
|
STD_OUTPUT_HANDLE* = -11'i32
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue