sys_wait.odin 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. package posix
  2. import "core:c"
  3. when ODIN_OS == .Darwin {
  4. foreign import lib "system:System.framework"
  5. } else {
  6. foreign import lib "system:c"
  7. }
  8. // sys/wait.h - declarations for waiting
  9. foreign lib {
  10. /*
  11. Obtains status information pertaining to one of the caller's child processes.
  12. Returns: -1 (setting errno) on failure or signal on calling process, the pid of the process that caused the return otherwise
  13. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]]
  14. */
  15. wait :: proc(stat_loc: ^c.int) -> pid_t ---
  16. /*
  17. Obtains status information pertaining to the given pid specifier.
  18. If pid is -1, status is requested for any child process.
  19. If pid is greater than 0, it specifies the process ID of a single child process.
  20. If pid is 0, it specifies any child process whose process group ID is equal to that of the call.
  21. If pid is < -1, status is requested for any child whose process group ID is the absolute value of pid.
  22. Returns: -1 (setting errno) on failure or signal on calling process, 0 if NOHANG and status is not available, the pid of the process that caused the return otherwise
  23. Example:
  24. // The following example demonstrates the use of waitpid(), fork(), and the macros used to
  25. // interpret the status value returned by waitpid() (and wait()). The code segment creates a
  26. // child process which does some unspecified work. Meanwhile the parent loops performing calls
  27. // to waitpid() to monitor the status of the child. The loop terminates when child termination
  28. // is detected.
  29. child_pid := posix.fork(); switch child_pid {
  30. case -1: // `fork` failed.
  31. panic("fork failed")
  32. case 0: // This is the child.
  33. // Do some work...
  34. case:
  35. for {
  36. status: i32
  37. wpid := posix.waitpid(child_pid, &status, { .UNTRACED, .CONTINUED })
  38. if wpid == -1 {
  39. panic("waitpid failure")
  40. }
  41. switch {
  42. case posix.WIFEXITED(status):
  43. fmt.printfln("child exited, status=%v", posix.WEXITSTATUS(status))
  44. case posix.WIFSIGNALED(status):
  45. fmt.printfln("child killed (signal %v)", posix.WTERMSIG(status))
  46. case posix.WIFSTOPPED(status):
  47. fmt.printfln("child stopped (signal %v", posix.WSTOPSIG(status))
  48. case posix.WIFCONTINUED(status):
  49. fmt.println("child continued")
  50. case:
  51. // Should never happen.
  52. fmt.println("unexpected status (%x)", status)
  53. }
  54. if posix.WIFEXITED(status) || posix.WIFSIGNALED(status) {
  55. break
  56. }
  57. }
  58. }
  59. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]]
  60. */
  61. waitpid :: proc(pid: pid_t, stat_loc: ^c.int, options: Wait_Flags) -> pid_t ---
  62. /*
  63. Obtains status information pertaining to the given idtype_t and id specifier.
  64. Returns: 0 if WNOHANG and no status available, 0 if child changed state, -1 (setting errno) on failure
  65. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html ]]
  66. */
  67. waitid :: proc(idtype: idtype_t, id: id_t, infop: ^siginfo_t, options: Wait_Flags) -> c.int ---
  68. }
  69. // If terminated normally.
  70. WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
  71. return _WIFEXITED(x)
  72. }
  73. // If WIFEXITED is true, returns the exit status.
  74. WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  75. return _WEXITSTATUS(x)
  76. }
  77. // If terminated due to an uncaught signal.
  78. WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
  79. return _WIFSIGNALED(x)
  80. }
  81. // If WIFSIGNALED is true, returns the signal.
  82. WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  83. return _WTERMSIG(x)
  84. }
  85. // If status was returned for a child process that is currently stopped.
  86. WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
  87. return _WIFSTOPPED(x)
  88. }
  89. // If WIFSTOPPED, the signal that caused the child process to stop.
  90. WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  91. return _WSTOPSIG(x)
  92. }
  93. // If status was returned for a child process that has continued from a job control stop.
  94. WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
  95. return _WIFCONTINUED(x)
  96. }
  97. idtype_t :: enum c.int {
  98. // Wait for any children and `id` is ignored.
  99. P_ALL,
  100. // Wait for any child wiith a process group ID equal to `id`.
  101. P_PID,
  102. // Wait for any child with a process group ID equal to `id`.
  103. P_PGID,
  104. }
  105. Wait_Flag_Bits :: enum c.int {
  106. // Report the status of any continued child process specified by pid whose status has not been
  107. // reported since it continued from a job control stop.
  108. CONTINUED = log2(WCONTINUED),
  109. // Don't suspend execution of the calling thread if status is not immediately available for one
  110. // of the child processes specified by pid.
  111. NOHANG = log2(WNOHANG),
  112. // The status of any child process specified by pid that are stopped, and whose status has not
  113. // yet been reported since they stopped, shall also be reported to the requesting process.
  114. UNTRACED = log2(WUNTRACED),
  115. // Following are only available on `waitid`, not `waitpid`.
  116. // Wait for processes that have exited.
  117. EXITED = log2(WEXITED),
  118. // Keep the process whose status is returned in a waitable state, so it may be waited on again.
  119. NOWAIT = log2(WNOWAIT),
  120. // Children that have stopped upon receipt of a signal, and whose status either hasn't been reported
  121. // or has been reported but that report was called with NOWAIT.
  122. STOPPED = log2(WSTOPPED),
  123. }
  124. Wait_Flags :: bit_set[Wait_Flag_Bits; c.int]
  125. when ODIN_OS == .Darwin {
  126. id_t :: distinct c.uint
  127. WCONTINUED :: 0x00000010
  128. WNOHANG :: 0x00000001
  129. WUNTRACED :: 0x00000002
  130. WEXITED :: 0x00000004
  131. WNOWAIT :: 0x00000020
  132. WSTOPPED :: 0x00000008
  133. @(private)
  134. _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  135. return x & 0o177
  136. }
  137. @(private)
  138. _WSTOPPED :: 0o177
  139. @(private)
  140. _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
  141. return _WSTATUS(x) == 0
  142. }
  143. @(private)
  144. _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  145. return x >> 8
  146. }
  147. @(private)
  148. _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
  149. return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0
  150. }
  151. @(private)
  152. _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  153. return Signal(_WSTATUS(x))
  154. }
  155. @(private)
  156. _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
  157. return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) != .SIGCONT
  158. }
  159. @(private)
  160. _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  161. return Signal(x >> 8)
  162. }
  163. @(private)
  164. _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
  165. return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) == .SIGCONT
  166. }
  167. } else when ODIN_OS == .FreeBSD {
  168. id_t :: distinct c.int64_t
  169. WCONTINUED :: 4
  170. WNOHANG :: 1
  171. WUNTRACED :: 2
  172. WEXITED :: 16
  173. WNOWAIT :: 8
  174. WSTOPPED :: 2
  175. @(private)
  176. _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  177. return x & 0o177
  178. }
  179. @(private)
  180. _WSTOPPED :: 0o177
  181. @(private)
  182. _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
  183. return _WSTATUS(x) == 0
  184. }
  185. @(private)
  186. _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  187. return x >> 8
  188. }
  189. @(private)
  190. _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
  191. return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 && x != c.int(Signal.SIGCONT)
  192. }
  193. @(private)
  194. _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  195. return Signal(_WSTATUS(x))
  196. }
  197. @(private)
  198. _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
  199. return _WSTATUS(x) == _WSTOPPED
  200. }
  201. @(private)
  202. _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  203. return Signal(x >> 8)
  204. }
  205. @(private)
  206. _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
  207. return x == c.int(Signal.SIGCONT)
  208. }
  209. } else when ODIN_OS == .NetBSD {
  210. id_t :: distinct c.uint32_t
  211. WCONTINUED :: 0x00000010
  212. WNOHANG :: 0x00000001
  213. WUNTRACED :: 0x00000002
  214. WEXITED :: 0x00000020
  215. WNOWAIT :: 0x00010000
  216. WSTOPPED :: 0x00000002
  217. @(private)
  218. _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  219. return x & 0o177
  220. }
  221. @(private)
  222. _WSTOPPED :: 0o177
  223. @(private)
  224. _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
  225. return _WSTATUS(x) == 0
  226. }
  227. @(private)
  228. _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  229. return c.int((c.uint(x) >> 8) & 0xff)
  230. }
  231. @(private)
  232. _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
  233. return !WIFSTOPPED(x) && !WIFCONTINUED(x) && !WIFEXITED(x)
  234. }
  235. @(private)
  236. _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  237. return Signal(_WSTATUS(x))
  238. }
  239. @(private)
  240. _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
  241. return _WSTATUS(x) == _WSTOPPED && !WIFCONTINUED(x)
  242. }
  243. @(private)
  244. _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  245. return Signal(c.int((c.uint(x) >> 8) & 0xff))
  246. }
  247. @(private)
  248. _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
  249. return x == 0xffff
  250. }
  251. } else when ODIN_OS == .OpenBSD {
  252. id_t :: distinct c.uint32_t
  253. WCONTINUED :: 0x00000010
  254. WNOHANG :: 0x00000001
  255. WUNTRACED :: 0x00000002
  256. WEXITED :: 0x00000020
  257. WNOWAIT :: 0x00010000
  258. WSTOPPED :: 0x00000002
  259. @(private)
  260. _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  261. return x & 0o177
  262. }
  263. @(private)
  264. _WSTOPPED :: 0o177
  265. @(private)
  266. _WCONTINUED :: 0o177777
  267. @(private)
  268. _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
  269. return _WSTATUS(x) == 0
  270. }
  271. @(private)
  272. _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
  273. return (x >> 8) & 0x000000ff
  274. }
  275. @(private)
  276. _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
  277. return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0
  278. }
  279. @(private)
  280. _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  281. return Signal(_WSTATUS(x))
  282. }
  283. @(private)
  284. _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
  285. return (x & 0xff) == _WSTOPPED
  286. }
  287. @(private)
  288. _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
  289. return Signal((x >> 8) & 0xff)
  290. }
  291. @(private)
  292. _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
  293. return (x & _WCONTINUED) == _WCONTINUED
  294. }
  295. } else {
  296. #panic("posix is unimplemented for the current target")
  297. }