diff options
author | alaviss <alaviss@users.noreply.github.com> | 2020-04-10 07:34:52 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-10 09:34:52 +0200 |
commit | 5f6962337de94b524afbb4f41b79eae362af67c8 (patch) | |
tree | 32c61462e7fb3b7072a7c0c30c699c372b2cfb97 | |
parent | cc3f5d21b249fe8f96f61369e53e794bf34e65a5 (diff) | |
download | Nim-5f6962337de94b524afbb4f41b79eae362af67c8.tar.gz |
osproc: added a better version of waitForExit for Haiku (#13938)
Also modified tosprocterminate to verify waitForExit implementations.
-rw-r--r-- | lib/pure/osproc.nim | 61 | ||||
-rw-r--r-- | tests/stdlib/tosprocterminate.nim | 28 |
2 files changed, 83 insertions, 6 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 1472d4e3d..ed5ab7b97 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1167,6 +1167,67 @@ elif not defined(useNimRtl): discard posix.close(kqFD) result = exitStatusLikeShell(p.exitStatus) + elif defined(haiku): + const + B_OBJECT_TYPE_THREAD = 3 + B_EVENT_INVALID = 0x1000 + B_RELATIVE_TIMEOUT = 0x8 + + type + ObjectWaitInfo {.importc: "object_wait_info", header: "OS.h".} = object + obj {.importc: "object".}: int32 + typ {.importc: "type".}: uint16 + events: uint16 + + proc waitForObjects(infos: ptr ObjectWaitInfo, numInfos: cint, flags: uint32, + timeout: int64): clong + {.importc: "wait_for_objects_etc", header: "OS.h".} + + proc waitForExit(p: Process, timeout: int = -1): int = + if p.exitFlag: + return exitStatusLikeShell(p.exitStatus) + + if timeout == -1: + var status: cint = 1 + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + else: + var info = ObjectWaitInfo( + obj: p.id, # Haiku's PID is actually the main thread ID. + typ: B_OBJECT_TYPE_THREAD, + events: B_EVENT_INVALID # notify when the thread die. + ) + + while true: + var status: cint = 1 + let count = waitForObjects(addr info, 1, B_RELATIVE_TIMEOUT, timeout) + + if count < 0: + let err = count.cint + if err == ETIMEDOUT: + # timeout expired, so we try to kill the process + if posix.kill(p.id, SIGKILL) == -1: + raiseOSError(osLastError()) + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + break + elif err != EINTR: + raiseOSError(err.OSErrorCode) + elif count > 0: + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + break + else: + doAssert false, "unreachable!" + + result = exitStatusLikeShell(p.exitStatus) + else: import times diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index a46d91d68..d487b5e60 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -1,8 +1,10 @@ discard """ -outputsub: "SUCCESS" + cmd: "nim $target $options -r $file" + targets: "c cpp" + matrix: "--threads:on; " """ -import os, osproc +import os, osproc, times, std / monotimes when defined(Windows): const ProgramWhichDoesNotEnd = "notepad" @@ -19,7 +21,21 @@ while process.running() and TimeToWait > 0: sleep(100) TimeToWait = TimeToWait - 100 -if process.running(): - echo("FAILED") -else: - echo("SUCCESS") +doAssert not process.running() +echo("stopped process") + +process.close() + +echo("starting " & ProgramWhichDoesNotEnd) +process = startProcess(ProgramWhichDoesNotEnd) +echo("process should be stopped after 2s") + +let start = getMonoTime() +discard process.waitForExit(2000) +let took = getMonoTime() - start + +doAssert not process.running() +# some additional time to account for overhead +doAssert took < initDuration(seconds = 3) + +echo("stopped process after ", took) |