sys_wait.odin 11 KB

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