module System.Posix.Waitpid where
import Control.Monad
import Data.List
import Foreign
import Foreign.C
import System.Posix.Signals (Signal)
import System.Posix.Types (CPid)
foreign import ccall unsafe "SystemPosixWaitpid_waitpid" c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid
data Flag = NoHang | IncludeUntraced | IncludeContinued deriving Show
data Status = Exited Int | Signaled Signal | Stopped Signal | Continued deriving (Show, Eq)
waitpid :: CPid -> [Flag] -> IO (Maybe (CPid, Status))
waitpid pid flags = alloca $ \status -> do
child <- throwErrnoIfMinus1 "waitpid" $ c_waitpid pid status options
stat <- peek status
return $ guard (child /= 0) >> return (child, extractStatus stat)
where
options = foldl' (.|.) 0 (map flagValue flags)
flagValue NoHang = 1
flagValue IncludeUntraced = 2
flagValue IncludeContinued = 4
extractStatus stat | stat < 0x10000 = Exited (fromIntegral stat)
| stat < 0x20000 = Signaled (stat 0x10000)
| stat < 0x30000 = Stopped (stat 0x20000)
| stat == 0x30000 = Continued
| otherwise = error $ "waitpid: unexpected status " ++ show stat