diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-12-01 02:06:51 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-12-01 02:06:51 +0100 |
commit | 8646a567384a8eb5c36be3f21eca1092b555ea73 (patch) | |
tree | 41f5717a56dc0abba625ad45eb571fb2822b34bf /lib | |
parent | 547961f71e75594ae1d9e2e26b0e54e0a63008e3 (diff) | |
parent | fbe0ae74fba5a22bbaea0cc8e68dbf9327c4ce6d (diff) | |
download | Nim-8646a567384a8eb5c36be3f21eca1092b555ea73.tar.gz |
Merge branch 'nexecProcesses' of https://github.com/cheatfate/Nim into cheatfate-nexecProcesses
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/osproc.nim | 138 |
1 files changed, 82 insertions, 56 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9865f114f..5440ceb67 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -167,8 +167,7 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, ## On posix, if the process has exited because of a signal, 128 + signal ## number will be returned. - -proc peekExitCode*(p: Process): int {.tags: [].} +proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", tags: [].} ## return -1 if the process is still running. Otherwise the process' exit code ## ## On posix, if the process has exited because of a signal, 128 + signal @@ -231,55 +230,79 @@ proc execProcesses*(cmds: openArray[string], ## executes the commands `cmds` in parallel. Creates `n` processes ## that execute in parallel. The highest return value of all processes ## is returned. Runs `beforeRunEvent` before running each command. - when false: - # poParentStreams causes problems on Posix, so we simply disable it: - var options = options - {poParentStreams} - + assert n > 0 if n > 1: - var q: seq[Process] - newSeq(q, n) + var i = 0 + var q = newSeq[Process](n) var m = min(n, cmds.len) - for i in 0..m-1: + + when defined(windows): + var w: WOHandleArray + var wcount = m + + while i < m: if beforeRunEvent != nil: beforeRunEvent(i) - q[i] = startProcess(cmds[i], options=options + {poEvalCommand}) - when defined(noBusyWaiting): - var r = 0 - for i in m..high(cmds): - when defined(debugExecProcesses): - var err = "" - var outp = outputStream(q[r]) - while running(q[r]) or not atEnd(outp): - err.add(outp.readLine()) - err.add("\n") - echo(err) - result = max(waitForExit(q[r]), result) - if afterRunEvent != nil: afterRunEvent(r, q[r]) - if q[r] != nil: close(q[r]) - if beforeRunEvent != nil: - beforeRunEvent(i) - q[r] = startProcess(cmds[i], options=options + {poEvalCommand}) - r = (r + 1) mod n - else: - var i = m - while i <= high(cmds): - sleep(50) - for r in 0..n-1: + q[i] = startProcess(cmds[i], options = options + {poEvalCommand}) + when defined(windows): + w[i] = q[i].fProcessHandle + inc(i) + + var ecount = len(cmds) + while ecount > 0: + when defined(windows): + # waiting for all children, get result if any child exits + var ret = waitForMultipleObjects(int32(wcount), addr(w), 0'i32, + INFINITE) + if ret == WAIT_TIMEOUT: + # must not be happen + discard + elif ret == WAIT_FAILED: + raiseOSError(osLastError()) + else: + var status : cint = 1 + # waiting for all children, get result if any child exits + let res = waitpid(-1, status, 0) + if res > 0: + for r in 0..m-1: + if not isNil(q[r]) and q[r].id == res: + # we updating `exitStatus` manually, so `running()` can work. + if WIFEXITED(status) or WIFSIGNALED(status): + q[r].exitStatus = status + break + else: + let err = osLastError() + if err == OSErrorCode(ECHILD): + # some child exits, we need to check our childs exit codes + discard + elif err == OSErrorCode(EINTR): + # signal interrupted our syscall, lets repeat it + continue + else: + # all other errors are exceptions + raiseOSError(err) + + for r in 0..m-1: + if not isNil(q[r]): if not running(q[r]): - #echo(outputStream(q[r]).readLine()) - result = max(waitForExit(q[r]), result) + result = max(result, q[r].peekExitCode()) if afterRunEvent != nil: afterRunEvent(r, q[r]) - if q[r] != nil: close(q[r]) - if beforeRunEvent != nil: - beforeRunEvent(i) - q[r] = startProcess(cmds[i], options=options + {poEvalCommand}) - inc(i) - if i > high(cmds): break - for j in 0..m-1: - result = max(waitForExit(q[j]), result) - if afterRunEvent != nil: afterRunEvent(j, q[j]) - if q[j] != nil: close(q[j]) + close(q[r]) + if i < len(cmds): + if beforeRunEvent != nil: beforeRunEvent(i) + q[r] = startProcess(cmds[i], + options = options + {poEvalCommand}) + when defined(windows): + w[r] = q[r].fProcessHandle + inc(i) + else: + q[r] = nil + when defined(windows): + for c in r..MAXIMUM_WAIT_OBJECTS - 2: + w[c] = w[c + 1] + dec(wcount) + dec(ecount) else: for i in 0..high(cmds): if beforeRunEvent != nil: @@ -944,19 +967,22 @@ elif not defined(useNimRtl): if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError()) proc running(p: Process): bool = - var ret : int - var status : cint = 1 - ret = waitpid(p.id, status, WNOHANG) - if ret == int(p.id): - if isExitStatus(status): - p.exitStatus = status - return false - else: - return true - elif ret == 0: - return true # Can't establish status. Assume running. - else: + if p.exitStatus != -3: return false + else: + var ret : int + var status : cint = 1 + ret = waitpid(p.id, status, WNOHANG) + if ret == int(p.id): + if isExitStatus(status): + p.exitStatus = status + return false + else: + return true + elif ret == 0: + return true # Can't establish status. Assume running. + else: + raiseOSError(osLastError()) proc terminate(p: Process) = if kill(p.id, SIGTERM) != 0'i32: |