#include "HsUnixConfig.h"
module System.Posix.Signals (
Signal,
nullSignal,
internalAbort, sigABRT,
realTimeAlarm, sigALRM,
busError, sigBUS,
processStatusChanged, sigCHLD,
continueProcess, sigCONT,
floatingPointException, sigFPE,
lostConnection, sigHUP,
illegalInstruction, sigILL,
keyboardSignal, sigINT,
killProcess, sigKILL,
openEndedPipe, sigPIPE,
keyboardTermination, sigQUIT,
segmentationViolation, sigSEGV,
softwareStop, sigSTOP,
softwareTermination, sigTERM,
keyboardStop, sigTSTP,
backgroundRead, sigTTIN,
backgroundWrite, sigTTOU,
userDefinedSignal1, sigUSR1,
userDefinedSignal2, sigUSR2,
#if CONST_SIGPOLL != -1
pollableEvent, sigPOLL,
#endif
profilingTimerExpired, sigPROF,
badSystemCall, sigSYS,
breakpointTrap, sigTRAP,
urgentDataAvailable, sigURG,
virtualTimerExpired, sigVTALRM,
cpuTimeLimitExceeded, sigXCPU,
fileSizeLimitExceeded, sigXFSZ,
raiseSignal,
signalProcess,
signalProcessGroup,
#ifdef __GLASGOW_HASKELL__
Handler(..),
installHandler,
#endif
SignalSet,
emptySignalSet, fullSignalSet,
addSignal, deleteSignal, inSignalSet,
getSignalMask, setSignalMask, blockSignals, unblockSignals,
scheduleAlarm,
getPendingSignals,
#ifndef cygwin32_HOST_OS
awaitSignal,
#endif
#ifdef __GLASGOW_HASKELL__
setStoppedChildFlag, queryStoppedChildFlag,
#endif
) where
import Foreign
import Foreign.C
import System.IO.Unsafe
import System.Posix.Types
import System.Posix.Internals
import Control.Concurrent (withMVar)
#ifdef __GLASGOW_HASKELL__
#include "Signals.h"
import GHC.Conc ( ensureIOManagerIsRunning, signalHandlerLock )
#endif
type Signal = CInt
nullSignal :: Signal
nullSignal = 0
sigABRT :: CInt
sigABRT = CONST_SIGABRT
sigALRM :: CInt
sigALRM = CONST_SIGALRM
sigBUS :: CInt
sigBUS = CONST_SIGBUS
sigCHLD :: CInt
sigCHLD = CONST_SIGCHLD
sigCONT :: CInt
sigCONT = CONST_SIGCONT
sigFPE :: CInt
sigFPE = CONST_SIGFPE
sigHUP :: CInt
sigHUP = CONST_SIGHUP
sigILL :: CInt
sigILL = CONST_SIGILL
sigINT :: CInt
sigINT = CONST_SIGINT
sigKILL :: CInt
sigKILL = CONST_SIGKILL
sigPIPE :: CInt
sigPIPE = CONST_SIGPIPE
sigQUIT :: CInt
sigQUIT = CONST_SIGQUIT
sigSEGV :: CInt
sigSEGV = CONST_SIGSEGV
sigSTOP :: CInt
sigSTOP = CONST_SIGSTOP
sigTERM :: CInt
sigTERM = CONST_SIGTERM
sigTSTP :: CInt
sigTSTP = CONST_SIGTSTP
sigTTIN :: CInt
sigTTIN = CONST_SIGTTIN
sigTTOU :: CInt
sigTTOU = CONST_SIGTTOU
sigUSR1 :: CInt
sigUSR1 = CONST_SIGUSR1
sigUSR2 :: CInt
sigUSR2 = CONST_SIGUSR2
sigPOLL :: CInt
sigPOLL = CONST_SIGPOLL
sigPROF :: CInt
sigPROF = CONST_SIGPROF
sigSYS :: CInt
sigSYS = CONST_SIGSYS
sigTRAP :: CInt
sigTRAP = CONST_SIGTRAP
sigURG :: CInt
sigURG = CONST_SIGURG
sigVTALRM :: CInt
sigVTALRM = CONST_SIGVTALRM
sigXCPU :: CInt
sigXCPU = CONST_SIGXCPU
sigXFSZ :: CInt
sigXFSZ = CONST_SIGXFSZ
internalAbort ::Signal
internalAbort = sigABRT
realTimeAlarm :: Signal
realTimeAlarm = sigALRM
busError :: Signal
busError = sigBUS
processStatusChanged :: Signal
processStatusChanged = sigCHLD
continueProcess :: Signal
continueProcess = sigCONT
floatingPointException :: Signal
floatingPointException = sigFPE
lostConnection :: Signal
lostConnection = sigHUP
illegalInstruction :: Signal
illegalInstruction = sigILL
keyboardSignal :: Signal
keyboardSignal = sigINT
killProcess :: Signal
killProcess = sigKILL
openEndedPipe :: Signal
openEndedPipe = sigPIPE
keyboardTermination :: Signal
keyboardTermination = sigQUIT
segmentationViolation :: Signal
segmentationViolation = sigSEGV
softwareStop :: Signal
softwareStop = sigSTOP
softwareTermination :: Signal
softwareTermination = sigTERM
keyboardStop :: Signal
keyboardStop = sigTSTP
backgroundRead :: Signal
backgroundRead = sigTTIN
backgroundWrite :: Signal
backgroundWrite = sigTTOU
userDefinedSignal1 :: Signal
userDefinedSignal1 = sigUSR1
userDefinedSignal2 :: Signal
userDefinedSignal2 = sigUSR2
#if CONST_SIGPOLL != -1
pollableEvent :: Signal
pollableEvent = sigPOLL
#endif
profilingTimerExpired :: Signal
profilingTimerExpired = sigPROF
badSystemCall :: Signal
badSystemCall = sigSYS
breakpointTrap :: Signal
breakpointTrap = sigTRAP
urgentDataAvailable :: Signal
urgentDataAvailable = sigURG
virtualTimerExpired :: Signal
virtualTimerExpired = sigVTALRM
cpuTimeLimitExceeded :: Signal
cpuTimeLimitExceeded = sigXCPU
fileSizeLimitExceeded :: Signal
fileSizeLimitExceeded = sigXFSZ
signalProcess :: Signal -> ProcessID -> IO ()
signalProcess sig pid
= throwErrnoIfMinus1_ "signalProcess" (c_kill (fromIntegral pid) sig)
foreign import ccall unsafe "kill"
c_kill :: CPid -> CInt -> IO CInt
signalProcessGroup :: Signal -> ProcessGroupID -> IO ()
signalProcessGroup sig pgid
= throwErrnoIfMinus1_ "signalProcessGroup" (c_killpg (fromIntegral pgid) sig)
foreign import ccall unsafe "killpg"
c_killpg :: CPid -> CInt -> IO CInt
raiseSignal :: Signal -> IO ()
raiseSignal sig = throwErrnoIfMinus1_ "raiseSignal" (c_raise sig)
#if defined(__GLASGOW_HASKELL__) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS))
foreign import ccall unsafe "genericRaise"
c_raise :: CInt -> IO CInt
#else
foreign import ccall unsafe "raise"
c_raise :: CInt -> IO CInt
#endif
#ifdef __GLASGOW_HASKELL__
data Handler = Default
| Ignore
| Catch (IO ())
| CatchOnce (IO ())
installHandler :: Signal
-> Handler
-> Maybe SignalSet
-> IO Handler
#ifdef __PARALLEL_HASKELL__
installHandler =
error "installHandler: not available for Parallel Haskell"
#else
installHandler int handler maybe_mask = do
ensureIOManagerIsRunning
case maybe_mask of
Nothing -> install' nullPtr
Just (SignalSet x) -> withForeignPtr x $ install'
where
install' mask =
withMVar signalHandlerLock $ \_ ->
alloca $ \p_sp -> do
rc <- case handler of
Default -> stg_sig_install int STG_SIG_DFL p_sp mask
Ignore -> stg_sig_install int STG_SIG_IGN p_sp mask
Catch m -> hinstall m p_sp mask int STG_SIG_HAN
CatchOnce m -> hinstall m p_sp mask int STG_SIG_RST
case rc of
STG_SIG_DFL -> return Default
STG_SIG_IGN -> return Ignore
STG_SIG_ERR -> throwErrno "installHandler"
STG_SIG_HAN -> do
m <- peekHandler p_sp
return (Catch m)
STG_SIG_RST -> do
m <- peekHandler p_sp
return (CatchOnce m)
_other ->
error "internal error: System.Posix.Signals.installHandler"
hinstall m p_sp mask int reset = do
sptr <- newStablePtr m
poke p_sp sptr
stg_sig_install int reset p_sp mask
peekHandler p_sp = do
osptr <- peek p_sp
deRefStablePtr osptr
foreign import ccall unsafe
stg_sig_install
:: CInt
-> CInt
-> Ptr (StablePtr (IO ()))
-> Ptr CSigset
-> IO CInt
#endif /* !__PARALLEL_HASKELL__ */
#endif /* __GLASGOW_HASKELL__ */
scheduleAlarm :: Int -> IO Int
scheduleAlarm secs = do
r <- c_alarm (fromIntegral secs)
return (fromIntegral r)
foreign import ccall unsafe "alarm"
c_alarm :: CUInt -> IO CUInt
#ifdef __GLASGOW_HASKELL__
foreign import ccall "&nocldstop" nocldstop :: Ptr Int
setStoppedChildFlag :: Bool -> IO Bool
setStoppedChildFlag b = do
rc <- peek nocldstop
poke nocldstop $ fromEnum (not b)
return (rc == (0::Int))
queryStoppedChildFlag :: IO Bool
queryStoppedChildFlag = do
rc <- peek nocldstop
return (rc == (0::Int))
#endif /* __GLASGOW_HASKELL__ */
newtype SignalSet = SignalSet (ForeignPtr CSigset)
emptySignalSet :: SignalSet
emptySignalSet = unsafePerformIO $ do
fp <- mallocForeignPtrBytes sizeof_sigset_t
throwErrnoIfMinus1_ "emptySignalSet" (withForeignPtr fp $ c_sigemptyset)
return (SignalSet fp)
fullSignalSet :: SignalSet
fullSignalSet = unsafePerformIO $ do
fp <- mallocForeignPtrBytes sizeof_sigset_t
throwErrnoIfMinus1_ "fullSignalSet" (withForeignPtr fp $ c_sigfillset)
return (SignalSet fp)
infixr `addSignal`, `deleteSignal`
addSignal :: Signal -> SignalSet -> SignalSet
addSignal sig (SignalSet fp1) = unsafePerformIO $ do
fp2 <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp1 $ \p1 ->
withForeignPtr fp2 $ \p2 -> do
copyBytes p2 p1 sizeof_sigset_t
throwErrnoIfMinus1_ "addSignal" (c_sigaddset p2 sig)
return (SignalSet fp2)
deleteSignal :: Signal -> SignalSet -> SignalSet
deleteSignal sig (SignalSet fp1) = unsafePerformIO $ do
fp2 <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp1 $ \p1 ->
withForeignPtr fp2 $ \p2 -> do
copyBytes p2 p1 sizeof_sigset_t
throwErrnoIfMinus1_ "deleteSignal" (c_sigdelset p2 sig)
return (SignalSet fp2)
inSignalSet :: Signal -> SignalSet -> Bool
inSignalSet sig (SignalSet fp) = unsafePerformIO $
withForeignPtr fp $ \p -> do
r <- throwErrnoIfMinus1 "inSignalSet" (c_sigismember p sig)
return (r /= 0)
getSignalMask :: IO SignalSet
getSignalMask = do
fp <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp $ \p ->
throwErrnoIfMinus1_ "getSignalMask" (c_sigprocmask 0 nullPtr p)
return (SignalSet fp)
sigProcMask :: String -> CInt -> SignalSet -> IO ()
sigProcMask fn how (SignalSet set) =
withForeignPtr set $ \p_set ->
throwErrnoIfMinus1_ fn (c_sigprocmask how p_set nullPtr)
setSignalMask :: SignalSet -> IO ()
setSignalMask set = sigProcMask "setSignalMask" (CONST_SIG_SETMASK :: CInt) set
blockSignals :: SignalSet -> IO ()
blockSignals set = sigProcMask "blockSignals" (CONST_SIG_BLOCK :: CInt) set
unblockSignals :: SignalSet -> IO ()
unblockSignals set = sigProcMask "unblockSignals" (CONST_SIG_UNBLOCK :: CInt) set
getPendingSignals :: IO SignalSet
getPendingSignals = do
fp <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp $ \p ->
throwErrnoIfMinus1_ "getPendingSignals" (c_sigpending p)
return (SignalSet fp)
#ifndef cygwin32_HOST_OS
awaitSignal :: Maybe SignalSet -> IO ()
awaitSignal maybe_sigset = do
fp <- case maybe_sigset of
Nothing -> do SignalSet fp <- getSignalMask; return fp
Just (SignalSet fp) -> return fp
withForeignPtr fp $ \p -> do
c_sigsuspend p
return ()
foreign import ccall unsafe "sigsuspend"
c_sigsuspend :: Ptr CSigset -> IO CInt
#endif
#ifdef __HUGS__
foreign import ccall unsafe "sigdelset"
c_sigdelset :: Ptr CSigset -> CInt -> IO CInt
foreign import ccall unsafe "sigfillset"
c_sigfillset :: Ptr CSigset -> IO CInt
foreign import ccall unsafe "sigismember"
c_sigismember :: Ptr CSigset -> CInt -> IO CInt
#else
foreign import ccall unsafe "__hscore_sigdelset"
c_sigdelset :: Ptr CSigset -> CInt -> IO CInt
foreign import ccall unsafe "__hscore_sigfillset"
c_sigfillset :: Ptr CSigset -> IO CInt
foreign import ccall unsafe "__hscore_sigismember"
c_sigismember :: Ptr CSigset -> CInt -> IO CInt
#endif /* __HUGS__ */
foreign import ccall unsafe "sigpending"
c_sigpending :: Ptr CSigset -> IO CInt