summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authoralaviss <alaviss@users.noreply.github.com>2020-04-10 07:34:52 +0000
committerGitHub <noreply@github.com>2020-04-10 09:34:52 +0200
commit5f6962337de94b524afbb4f41b79eae362af67c8 (patch)
tree32c61462e7fb3b7072a7c0c30c699c372b2cfb97 /lib
parentcc3f5d21b249fe8f96f61369e53e794bf34e65a5 (diff)
downloadNim-5f6962337de94b524afbb4f41b79eae362af67c8.tar.gz
osproc: added a better version of waitForExit for Haiku (#13938)
Also modified tosprocterminate to verify waitForExit implementations.
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/osproc.nim61
1 files changed, 61 insertions, 0 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