{-# LINE 1 "libraries/unix/System/Posix/Signals.hsc" #-}
{-# LANGUAGE CApiFFI, CPP, DeriveDataTypeable, NondecreasingIndentation #-}
{-# OPTIONS_GHC -fno-cse #-} -- global variables
{-# LANGUAGE Trustworthy #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Posix.Signals
-- Copyright   :  (c) The University of Glasgow 2002
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  non-portable (requires POSIX)
--
-- POSIX signal support
--
-----------------------------------------------------------------------------


#include "HsUnixConfig.h"


{-# LINE 22 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 24 "libraries/unix/System/Posix/Signals.hsc" #-}

module System.Posix.Signals (
  -- * The Signal type
  Signal,

  -- * Specific signals
  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,

{-# LINE 52 "libraries/unix/System/Posix/Signals.hsc" #-}
  pollableEvent, sigPOLL,

{-# LINE 54 "libraries/unix/System/Posix/Signals.hsc" #-}
  profilingTimerExpired, sigPROF,
  badSystemCall, sigSYS,
  breakpointTrap, sigTRAP,
  urgentDataAvailable, sigURG,
  virtualTimerExpired, sigVTALRM,
  cpuTimeLimitExceeded, sigXCPU,
  fileSizeLimitExceeded, sigXFSZ,

  -- * Sending signals
  raiseSignal,
  signalProcess,
  signalProcessGroup,

  -- * Handling signals
  Handler(Default,Ignore,Catch,CatchOnce,CatchInfo,CatchInfoOnce),
  SignalInfo(..), SignalSpecificInfo(..),
  installHandler,

  -- * Signal sets
  SignalSet,
  emptySignalSet, fullSignalSet, reservedSignals,
  addSignal, deleteSignal, inSignalSet,

  -- * The process signal mask
  getSignalMask, setSignalMask, blockSignals, unblockSignals,

  -- * The alarm timer
  scheduleAlarm,

  -- * Waiting for signals
  getPendingSignals,
  awaitSignal,

  -- * The @NOCLDSTOP@ flag
  setStoppedChildFlag, queryStoppedChildFlag,

  -- MISSING FUNCTIONALITY:
  -- sigaction(), (inc. the sigaction structure + flags etc.)
  -- the siginfo structure
  -- sigaltstack()
  -- sighold, sigignore, sigpause, sigrelse, sigset
  -- siginterrupt
  ) where

import Data.Word
import Foreign.C
import Foreign.ForeignPtr
import Foreign.Marshal
import Foreign.Ptr
import Foreign.Storable

{-# LINE 108 "libraries/unix/System/Posix/Signals.hsc" #-}
import System.IO.Unsafe (unsafePerformIO)
import System.Posix.Types
import System.Posix.Internals
import System.Posix.Process
import System.Posix.Process.Internals
import Data.Dynamic


{-# LINE 124 "libraries/unix/System/Posix/Signals.hsc" #-}
#include "rts/Signals.h"

{-# LINE 126 "libraries/unix/System/Posix/Signals.hsc" #-}

import GHC.Conc hiding (Signal)


{-# LINE 132 "libraries/unix/System/Posix/Signals.hsc" #-}

-- -----------------------------------------------------------------------------
-- Specific signals

nullSignal :: Signal
nullSignal :: CInt
nullSignal = CInt
0

-- | Process abort signal.
sigABRT   :: CInt
sigABRT :: CInt
sigABRT   = CONST_SIGABRT

-- | Alarm clock.
sigALRM   :: CInt
sigALRM :: CInt
sigALRM   = CONST_SIGALRM

-- | Access to an undefined portion of a memory object.
sigBUS    :: CInt
sigBUS :: CInt
sigBUS    = CONST_SIGBUS

-- | Child process terminated, stopped, or continued.
sigCHLD   :: CInt
sigCHLD :: CInt
sigCHLD   = CONST_SIGCHLD

-- | Continue executing, if stopped.
sigCONT   :: CInt
sigCONT :: CInt
sigCONT   = CONST_SIGCONT

-- | Erroneous arithmetic operation.
sigFPE    :: CInt
sigFPE :: CInt
sigFPE    = CONST_SIGFPE

-- | Hangup.
sigHUP    :: CInt
sigHUP :: CInt
sigHUP    = CONST_SIGHUP

-- | Illegal instruction.
sigILL    :: CInt
sigILL :: CInt
sigILL    = CONST_SIGILL

-- | Terminal interrupt signal.
sigINT    :: CInt
sigINT :: CInt
sigINT    = CONST_SIGINT

-- | Kill (cannot be caught or ignored).
sigKILL   :: CInt
sigKILL :: CInt
sigKILL   = CONST_SIGKILL

-- | Write on a pipe with no one to read it.
sigPIPE   :: CInt
sigPIPE :: CInt
sigPIPE   = CONST_SIGPIPE

-- | Terminal quit signal.
sigQUIT   :: CInt
sigQUIT :: CInt
sigQUIT   = CONST_SIGQUIT

-- | Invalid memory reference.
sigSEGV   :: CInt
sigSEGV :: CInt
sigSEGV   = CONST_SIGSEGV

-- | Stop executing (cannot be caught or ignored).
sigSTOP   :: CInt
sigSTOP :: CInt
sigSTOP   = CONST_SIGSTOP

-- | Termination signal.
sigTERM   :: CInt
sigTERM :: CInt
sigTERM   = CONST_SIGTERM

-- | Terminal stop signal.
sigTSTP   :: CInt
sigTSTP :: CInt
sigTSTP   = CONST_SIGTSTP

-- | Background process attempting read.
sigTTIN   :: CInt
sigTTIN :: CInt
sigTTIN   = CONST_SIGTTIN

-- | Background process attempting write.
sigTTOU   :: CInt
sigTTOU :: CInt
sigTTOU   = CONST_SIGTTOU

-- | User-defined signal 1.
sigUSR1   :: CInt
sigUSR1 :: CInt
sigUSR1   = CONST_SIGUSR1

-- | User-defined signal 2.
sigUSR2   :: CInt
sigUSR2 :: CInt
sigUSR2   = CONST_SIGUSR2


{-# LINE 220 "libraries/unix/System/Posix/Signals.hsc" #-}
-- | Pollable event.
sigPOLL   :: CInt
sigPOLL :: CInt
sigPOLL   = CONST_SIGPOLL

{-# LINE 224 "libraries/unix/System/Posix/Signals.hsc" #-}

-- | Profiling timer expired.
sigPROF   :: CInt
sigPROF :: CInt
sigPROF   = CONST_SIGPROF

-- | Bad system call.
sigSYS    :: CInt
sigSYS :: CInt
sigSYS    = CONST_SIGSYS

-- | Trace/breakpoint trap.
sigTRAP   :: CInt
sigTRAP :: CInt
sigTRAP   = CONST_SIGTRAP

-- | High bandwidth data is available at a socket.
sigURG    :: CInt
sigURG :: CInt
sigURG    = CONST_SIGURG

-- | Virtual timer expired.
sigVTALRM :: CInt
sigVTALRM :: CInt
sigVTALRM = CONST_SIGVTALRM

-- | CPU time limit exceeded.
sigXCPU   :: CInt
sigXCPU :: CInt
sigXCPU   = CONST_SIGXCPU

-- | File size limit exceeded.
sigXFSZ   :: CInt
sigXFSZ :: CInt
sigXFSZ   = CONST_SIGXFSZ

-- | Alias for 'sigABRT'.
internalAbort ::Signal
internalAbort :: CInt
internalAbort = CInt
sigABRT

-- | Alias for 'sigALRM'.
realTimeAlarm :: Signal
realTimeAlarm :: CInt
realTimeAlarm = CInt
sigALRM

-- | Alias for 'sigBUS'.
busError :: Signal
busError :: CInt
busError = CInt
sigBUS

-- | Alias for 'sigCHLD'.
processStatusChanged :: Signal
processStatusChanged :: CInt
processStatusChanged = CInt
sigCHLD

-- | Alias for 'sigCONT'.
continueProcess :: Signal
continueProcess :: CInt
continueProcess = CInt
sigCONT

-- | Alias for 'sigFPE'.
floatingPointException :: Signal
floatingPointException :: CInt
floatingPointException = CInt
sigFPE

-- | Alias for 'sigHUP'.
lostConnection :: Signal
lostConnection :: CInt
lostConnection = CInt
sigHUP

-- | Alias for 'sigILL'.
illegalInstruction :: Signal
illegalInstruction :: CInt
illegalInstruction = CInt
sigILL

-- | Alias for 'sigINT'.
keyboardSignal :: Signal
keyboardSignal :: CInt
keyboardSignal = CInt
sigINT

-- | Alias for 'sigKILL'.
killProcess :: Signal
killProcess :: CInt
killProcess = CInt
sigKILL

-- | Alias for 'sigPIPE'.
openEndedPipe :: Signal
openEndedPipe :: CInt
openEndedPipe = CInt
sigPIPE

-- | Alias for 'sigQUIT'.
keyboardTermination :: Signal
keyboardTermination :: CInt
keyboardTermination = CInt
sigQUIT

-- | Alias for 'sigSEGV'.
segmentationViolation :: Signal
segmentationViolation :: CInt
segmentationViolation = CInt
sigSEGV

-- | Alias for 'sigSTOP'.
softwareStop :: Signal
softwareStop :: CInt
softwareStop = CInt
sigSTOP

-- | Alias for 'sigTERM'.
softwareTermination :: Signal
softwareTermination :: CInt
softwareTermination = CInt
sigTERM

-- | Alias for 'sigTSTP'.
keyboardStop :: Signal
keyboardStop :: CInt
keyboardStop = CInt
sigTSTP

-- | Alias for 'sigTTIN'.
backgroundRead :: Signal
backgroundRead :: CInt
backgroundRead = CInt
sigTTIN

-- | Alias for 'sigTTOU'.
backgroundWrite :: Signal
backgroundWrite :: CInt
backgroundWrite = CInt
sigTTOU

-- | Alias for 'sigUSR1'.
userDefinedSignal1 :: Signal
userDefinedSignal1 :: CInt
userDefinedSignal1 = CInt
sigUSR1

-- | Alias for 'sigUSR2'.
userDefinedSignal2 :: Signal
userDefinedSignal2 :: CInt
userDefinedSignal2 = CInt
sigUSR2


{-# LINE 334 "libraries/unix/System/Posix/Signals.hsc" #-}
-- | Alias for 'sigPOLL'.
pollableEvent :: Signal
pollableEvent :: CInt
pollableEvent = CInt
sigPOLL

{-# LINE 338 "libraries/unix/System/Posix/Signals.hsc" #-}

-- | Alias for 'sigPROF'.
profilingTimerExpired :: Signal
profilingTimerExpired :: CInt
profilingTimerExpired = CInt
sigPROF

-- | Alias for 'sigSYS'.
badSystemCall :: Signal
badSystemCall :: CInt
badSystemCall = CInt
sigSYS

-- | Alias for 'sigTRAP'.
breakpointTrap :: Signal
breakpointTrap :: CInt
breakpointTrap = CInt
sigTRAP

-- | Alias for 'sigURG'.
urgentDataAvailable :: Signal
urgentDataAvailable :: CInt
urgentDataAvailable = CInt
sigURG

-- | Alias for 'sigVTALRM'.
virtualTimerExpired :: Signal
virtualTimerExpired :: CInt
virtualTimerExpired = CInt
sigVTALRM

-- | Alias for 'sigXCPU'.
cpuTimeLimitExceeded :: Signal
cpuTimeLimitExceeded :: CInt
cpuTimeLimitExceeded = CInt
sigXCPU

-- | Alias for 'sigXFSZ'.
fileSizeLimitExceeded :: Signal
fileSizeLimitExceeded :: CInt
fileSizeLimitExceeded = CInt
sigXFSZ

-- -----------------------------------------------------------------------------
-- Signal-related functions

-- | @signalProcess int pid@ calls @kill@ to signal process @pid@
--   with interrupt signal @int@.
signalProcess :: Signal -> ProcessID -> IO ()

{-# LINE 380 "libraries/unix/System/Posix/Signals.hsc" #-}

signalProcess :: CInt -> ProcessID -> IO ()
signalProcess CInt
sig ProcessID
pid
 = String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"signalProcess" (ProcessID -> CInt -> IO CInt
c_kill ProcessID
pid CInt
sig)

foreign import ccall unsafe "kill"
  c_kill :: CPid -> CInt -> IO CInt


{-# LINE 388 "libraries/unix/System/Posix/Signals.hsc" #-}


-- | @signalProcessGroup int pgid@ calls @kill@ to signal
--  all processes in group @pgid@ with interrupt signal @int@.
signalProcessGroup :: Signal -> ProcessGroupID -> IO ()

{-# LINE 400 "libraries/unix/System/Posix/Signals.hsc" #-}

signalProcessGroup :: CInt -> ProcessID -> IO ()
signalProcessGroup CInt
sig ProcessID
pgid
  = String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"signalProcessGroup" (ProcessID -> CInt -> IO CInt
c_killpg ProcessID
pgid CInt
sig)

foreign import ccall unsafe "killpg"
  c_killpg :: CPid -> CInt -> IO CInt


{-# LINE 408 "libraries/unix/System/Posix/Signals.hsc" #-}

-- | @raiseSignal int@ calls @kill@ to signal the current process
--   with interrupt signal @int@.
raiseSignal :: Signal -> IO ()

{-# LINE 419 "libraries/unix/System/Posix/Signals.hsc" #-}

raiseSignal :: CInt -> IO ()
raiseSignal CInt
sig = String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"raiseSignal" (CInt -> IO CInt
c_raise CInt
sig)

-- See also note in GHC's rts/RtsUtils.c
-- This is somewhat fragile because we need to keep the
-- `#if`-conditional in sync with GHC's runtime.

{-# LINE 429 "libraries/unix/System/Posix/Signals.hsc" #-}
foreign import ccall unsafe "raise"
  c_raise :: CInt -> IO CInt

{-# LINE 432 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 434 "libraries/unix/System/Posix/Signals.hsc" #-}

type Signal = CInt

-- | The actions to perform when a signal is received.
data Handler = Default
                 -- ^ Sets the disposition of the signal to @SIG_DFL@, which
                 -- means we want the default action associated with the
                 -- signal. For example, the default action for @SIGTERM@ (and
                 -- various other signals) is to terminate the process.
             | Ignore
                 -- ^ Set the disposition of the signal to @SIG_IGN@, which
                 -- means we want to /ignore/ the signal.  Ignored signals will
                 -- not be delivered to the process, and if also /blocked/ will
                 -- not be added to the pending set for later delivery (if/when
                 -- unblocked).  Some signals (e.g. @SIGSTOP@ and @SIGKILL@)
                 -- cannot be caught or ignored.
             -- not yet: | Hold
             | Catch (IO ())
                 -- ^ signal handler is not reset
             | CatchOnce (IO ())
                 -- ^ signal handler is automatically reset (via @SA_RESETHAND@)
             | CatchInfo (SignalInfo -> IO ())     -- ^ @since 2.7.0.0
             | CatchInfoOnce (SignalInfo -> IO ()) -- ^ @since 2.7.0.0
  deriving (Typeable)

-- | Information about a received signal (derived from @siginfo_t@).
--
-- @since 2.7.0.0
data SignalInfo = SignalInfo {
      SignalInfo -> CInt
siginfoSignal   :: Signal,
      SignalInfo -> Errno
siginfoError    :: Errno,
      SignalInfo -> SignalSpecificInfo
siginfoSpecific :: SignalSpecificInfo
  }

-- | Information specific to a particular type of signal
-- (derived from @siginfo_t@).
--
-- @since 2.7.0.0
data SignalSpecificInfo
  = NoSignalSpecificInfo
  | SigChldInfo {
      SignalSpecificInfo -> ProcessID
siginfoPid    :: ProcessID,
      SignalSpecificInfo -> UserID
siginfoUid    :: UserID,
      SignalSpecificInfo -> ProcessStatus
siginfoStatus :: ProcessStatus
    }

-- | @installHandler int handler iset@ calls @sigaction@ to install an
--   interrupt handler for signal @int@.  If @handler@ is @Default@,
--   @SIG_DFL@ is installed; if @handler@ is @Ignore@, @SIG_IGN@ is
--   installed; if @handler@ is @Catch action@, a handler is installed
--   which will invoke @action@ in a new thread when (or shortly after) the
--   signal is received.
--   If @iset@ is @Just s@, then the @sa_mask@ of the @sigaction@ structure
--   is set to @s@; otherwise it is cleared.  The previously installed
--   signal handler for @int@ is returned
installHandler :: Signal
               -> Handler
               -> Maybe SignalSet       -- ^ other signals to block
               -> IO Handler            -- ^ old handler


{-# LINE 506 "libraries/unix/System/Posix/Signals.hsc" #-}

installHandler :: CInt -> Handler -> Maybe SignalSet -> IO Handler
installHandler CInt
sig Handler
handler Maybe SignalSet
_maybe_mask = do
  IO ()
ensureIOManagerIsRunning  -- for the threaded RTS

  -- if we're setting the action to DFL or IGN, we should do that *first*
  -- if we're setting a handler,
  --   if the previous action was handle, then setHandler is ok
  --   if the previous action was IGN/DFL, then setHandler followed by sig_install
  (old_action, old_handler) <-
    case Handler
handler of
      Handler
Ignore  -> do
        old_action  <- CInt -> CInt -> Ptr CSigset -> IO CInt
stg_sig_install CInt
sig STG_SIG_IGN nullPtr
        old_handler <- setHandler sig Nothing
        return (old_action, old_handler)

      Handler
Default -> do
        old_action  <- CInt -> CInt -> Ptr CSigset -> IO CInt
stg_sig_install CInt
sig STG_SIG_DFL nullPtr
        old_handler <- setHandler sig Nothing
        return (old_action, old_handler)

      Handler
_some_kind_of_catch -> do
        -- I don't think it's possible to get CatchOnce right.  If
        -- there's a signal in flight, then we might run the handler
        -- more than once.
        let dyn :: Dynamic
dyn = Handler -> Dynamic
forall a. Typeable a => a -> Dynamic
toDyn Handler
handler
        old_handler <- case Handler
handler of
            Catch         IO ()
action -> CInt
-> Maybe (HandlerFun, Dynamic) -> IO (Maybe (HandlerFun, Dynamic))
setHandler CInt
sig ((HandlerFun, Dynamic) -> Maybe (HandlerFun, Dynamic)
forall a. a -> Maybe a
Just (IO () -> HandlerFun
forall a b. a -> b -> a
const IO ()
action,Dynamic
dyn))
            CatchOnce     IO ()
action -> CInt
-> Maybe (HandlerFun, Dynamic) -> IO (Maybe (HandlerFun, Dynamic))
setHandler CInt
sig ((HandlerFun, Dynamic) -> Maybe (HandlerFun, Dynamic)
forall a. a -> Maybe a
Just (IO () -> HandlerFun
forall a b. a -> b -> a
const IO ()
action,Dynamic
dyn))
            CatchInfo     SignalInfo -> IO ()
action -> CInt
-> Maybe (HandlerFun, Dynamic) -> IO (Maybe (HandlerFun, Dynamic))
setHandler CInt
sig ((HandlerFun, Dynamic) -> Maybe (HandlerFun, Dynamic)
forall a. a -> Maybe a
Just ((SignalInfo -> IO ()) -> HandlerFun
getinfo SignalInfo -> IO ()
action,Dynamic
dyn))
            CatchInfoOnce SignalInfo -> IO ()
action -> CInt
-> Maybe (HandlerFun, Dynamic) -> IO (Maybe (HandlerFun, Dynamic))
setHandler CInt
sig ((HandlerFun, Dynamic) -> Maybe (HandlerFun, Dynamic)
forall a. a -> Maybe a
Just ((SignalInfo -> IO ()) -> HandlerFun
getinfo SignalInfo -> IO ()
action,Dynamic
dyn))

{-# LINE 539 "libraries/unix/System/Posix/Signals.hsc" #-}

        let action = case Handler
handler of
                Catch IO ()
_         -> STG_SIG_HAN
                CatchOnce IO ()
_     -> STG_SIG_RST
                CatchInfo SignalInfo -> IO ()
_     -> STG_SIG_HAN
                CatchInfoOnce SignalInfo -> IO ()
_ -> STG_SIG_RST

{-# LINE 548 "libraries/unix/System/Posix/Signals.hsc" #-}

        old_action <- stg_sig_install sig action nullPtr
                   -- mask is pointless, so leave it NULL

        return (old_action, old_handler)

  case (old_handler,old_action) of
    (Maybe (HandlerFun, Dynamic)
_,       STG_SIG_DFL) -> return $ Default
    (Maybe (HandlerFun, Dynamic)
_,       STG_SIG_IGN) -> return $ Ignore
    (Maybe (HandlerFun, Dynamic)
Nothing, CInt
_)           -> Handler -> IO Handler
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Handler -> IO Handler) -> Handler -> IO Handler
forall a b. (a -> b) -> a -> b
$ Handler
Ignore
    (Just (HandlerFun
_,Dynamic
dyn),  CInt
_)
        | Just Handler
h <- Dynamic -> Maybe Handler
forall a. Typeable a => Dynamic -> Maybe a
fromDynamic Dynamic
dyn  -> Handler -> IO Handler
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Handler
h
        | Just IO ()
io <- Dynamic -> Maybe (IO ())
forall a. Typeable a => Dynamic -> Maybe a
fromDynamic Dynamic
dyn -> Handler -> IO Handler
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (IO () -> Handler
Catch IO ()
io)
        -- handlers put there by the base package have type IO ()
        | Bool
otherwise                  -> Handler -> IO Handler
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Handler
Default

foreign import ccall unsafe
  stg_sig_install
        :: CInt                         -- sig no.
        -> CInt                         -- action code (STG_SIG_HAN etc.)
        -> Ptr CSigset                  -- (in, out) blocked
        -> IO CInt                      -- (ret) old action code

getinfo :: (SignalInfo -> IO ()) -> ForeignPtr Word8 -> IO ()
getinfo :: (SignalInfo -> IO ()) -> HandlerFun
getinfo SignalInfo -> IO ()
handler ForeignPtr Word8
fp_info = do
  si <- ForeignPtr Word8 -> IO SignalInfo
unmarshalSigInfo ForeignPtr Word8
fp_info
  handler si

unmarshalSigInfo :: ForeignPtr Word8 -> IO SignalInfo
unmarshalSigInfo :: ForeignPtr Word8 -> IO SignalInfo
unmarshalSigInfo ForeignPtr Word8
fp = do
  ForeignPtr Word8 -> (Ptr Word8 -> IO SignalInfo) -> IO SignalInfo
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO SignalInfo) -> IO SignalInfo)
-> (Ptr Word8 -> IO SignalInfo) -> IO SignalInfo
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
    sig   <- ((\Ptr Word8
hsc_ptr -> Ptr Word8 -> Int -> IO CInt
forall b. Ptr b -> Int -> IO CInt
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
hsc_ptr Int
0)) Ptr Word8
p
{-# LINE 580 "libraries/unix/System/Posix/Signals.hsc" #-}
    errno <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
{-# LINE 581 "libraries/unix/System/Posix/Signals.hsc" #-}
    extra <- case sig of
                _ | sig == sigCHLD -> do
                    pid <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) p
{-# LINE 584 "libraries/unix/System/Posix/Signals.hsc" #-}
                    uid <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) p
{-# LINE 585 "libraries/unix/System/Posix/Signals.hsc" #-}
                    wstat <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) p
{-# LINE 586 "libraries/unix/System/Posix/Signals.hsc" #-}
                    pstat <- decipherWaitStatus wstat
                    return SigChldInfo { siginfoPid = pid,
                                         siginfoUid = uid,
                                         siginfoStatus = pstat }
                _ | otherwise ->
                    return NoSignalSpecificInfo
    return
      SignalInfo {
        siginfoSignal = sig,
        siginfoError  = Errno errno,
        siginfoSpecific = extra }


{-# LINE 599 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 608 "libraries/unix/System/Posix/Signals.hsc" #-}

-- -----------------------------------------------------------------------------
-- Alarms

-- | @scheduleAlarm i@ calls @alarm@ to schedule a real time
--   alarm at least @i@ seconds in the future.
scheduleAlarm :: Int -> IO Int
scheduleAlarm :: Int -> IO Int
scheduleAlarm Int
secs = do
   r <- CUInt -> IO CUInt
c_alarm (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
secs)
   return (fromIntegral r)

foreign import ccall unsafe "alarm"
  c_alarm :: CUInt -> IO CUInt


{-# LINE 623 "libraries/unix/System/Posix/Signals.hsc" #-}

-- -----------------------------------------------------------------------------
-- The NOCLDSTOP flag


{-# LINE 638 "libraries/unix/System/Posix/Signals.hsc" #-}

foreign import ccall "&nocldstop" nocldstop :: Ptr Int

-- | Tells the system whether or not to set the @SA_NOCLDSTOP@ flag when
-- installing new signal handlers.
setStoppedChildFlag :: Bool -> IO Bool
setStoppedChildFlag :: Bool -> IO Bool
setStoppedChildFlag Bool
b = do
    rc <- Ptr Int -> IO Int
forall a. Storable a => Ptr a -> IO a
peek Ptr Int
nocldstop
    poke nocldstop $ fromEnum (not b)
    return (rc == (0::Int))

-- | Queries the current state of the stopped child flag.
queryStoppedChildFlag :: IO Bool
queryStoppedChildFlag :: IO Bool
queryStoppedChildFlag = do
    rc <- Ptr Int -> IO Int
forall a. Storable a => Ptr a -> IO a
peek Ptr Int
nocldstop
    return (rc == (0::Int))


{-# LINE 656 "libraries/unix/System/Posix/Signals.hsc" #-}

-- -----------------------------------------------------------------------------
-- Manipulating signal sets


{-# LINE 661 "libraries/unix/System/Posix/Signals.hsc" #-}

newtype SignalSet = SignalSet (ForeignPtr CSigset)


{-# LINE 669 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 704 "libraries/unix/System/Posix/Signals.hsc" #-}

emptySignalSet :: SignalSet
emptySignalSet :: SignalSet
emptySignalSet = IO SignalSet -> SignalSet
forall a. IO a -> a
unsafePerformIO (IO SignalSet -> SignalSet) -> IO SignalSet -> SignalSet
forall a b. (a -> b) -> a -> b
$ do
  fp <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  throwErrnoIfMinus1_ "emptySignalSet" (withForeignPtr fp $ c_sigemptyset)
  return (SignalSet fp)

fullSignalSet :: SignalSet
fullSignalSet :: SignalSet
fullSignalSet = IO SignalSet -> SignalSet
forall a. IO a -> a
unsafePerformIO (IO SignalSet -> SignalSet) -> IO SignalSet -> SignalSet
forall a b. (a -> b) -> a -> b
$ do
  fp <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  throwErrnoIfMinus1_ "fullSignalSet" (withForeignPtr fp $ c_sigfillset)
  return (SignalSet fp)

-- | A set of signals reserved for use by the implementation.  In GHC, this will normally
-- include either `sigVTALRM` or `sigALRM`.
reservedSignals :: SignalSet
reservedSignals :: SignalSet
reservedSignals = CInt -> SignalSet -> SignalSet
addSignal CInt
rtsTimerSignal SignalSet
emptySignalSet

foreign import ccall rtsTimerSignal :: CInt

infixr `addSignal`, `deleteSignal`
addSignal :: Signal -> SignalSet -> SignalSet
addSignal :: CInt -> SignalSet -> SignalSet
addSignal CInt
sig (SignalSet ForeignPtr CSigset
fp1) = IO SignalSet -> SignalSet
forall a. IO a -> a
unsafePerformIO (IO SignalSet -> SignalSet) -> IO SignalSet -> SignalSet
forall a b. (a -> b) -> a -> b
$ do
  fp2 <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  withForeignPtr fp1 $ \Ptr CSigset
p1 ->
    ForeignPtr CSigset -> (Ptr CSigset -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CSigset
fp2 ((Ptr CSigset -> IO ()) -> IO ())
-> (Ptr CSigset -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CSigset
p2 -> do
      Ptr CSigset -> Ptr CSigset -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr CSigset
p2 Ptr CSigset
p1 Int
sizeof_sigset_t
      String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"addSignal" (Ptr CSigset -> CInt -> IO CInt
c_sigaddset Ptr CSigset
p2 CInt
sig)
  return (SignalSet fp2)

deleteSignal :: Signal -> SignalSet -> SignalSet
deleteSignal :: CInt -> SignalSet -> SignalSet
deleteSignal CInt
sig (SignalSet ForeignPtr CSigset
fp1) = IO SignalSet -> SignalSet
forall a. IO a -> a
unsafePerformIO (IO SignalSet -> SignalSet) -> IO SignalSet -> SignalSet
forall a b. (a -> b) -> a -> b
$ do
  fp2 <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  withForeignPtr fp1 $ \Ptr CSigset
p1 ->
    ForeignPtr CSigset -> (Ptr CSigset -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CSigset
fp2 ((Ptr CSigset -> IO ()) -> IO ())
-> (Ptr CSigset -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CSigset
p2 -> do
      Ptr CSigset -> Ptr CSigset -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr CSigset
p2 Ptr CSigset
p1 Int
sizeof_sigset_t
      String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"deleteSignal" (Ptr CSigset -> CInt -> IO CInt
c_sigdelset Ptr CSigset
p2 CInt
sig)
  return (SignalSet fp2)

inSignalSet :: Signal -> SignalSet -> Bool
inSignalSet :: CInt -> SignalSet -> Bool
inSignalSet CInt
sig (SignalSet ForeignPtr CSigset
fp) = IO Bool -> Bool
forall a. IO a -> a
unsafePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
  ForeignPtr CSigset -> (Ptr CSigset -> IO Bool) -> IO Bool
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CSigset
fp ((Ptr CSigset -> IO Bool) -> IO Bool)
-> (Ptr CSigset -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr CSigset
p -> do
    r <- String -> IO CInt -> IO CInt
forall a. (Eq a, Num a) => String -> IO a -> IO a
throwErrnoIfMinus1 String
"inSignalSet" (Ptr CSigset -> CInt -> IO CInt
c_sigismember Ptr CSigset
p CInt
sig)
    return (r /= 0)


{-# LINE 750 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 774 "libraries/unix/System/Posix/Signals.hsc" #-}

-- | @getSignalMask@ calls @sigprocmask@ to determine the
--   set of interrupts which are currently being blocked.
getSignalMask :: IO SignalSet
getSignalMask :: IO SignalSet
getSignalMask = do
  fp <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  withForeignPtr fp $ \Ptr CSigset
p ->
    String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"getSignalMask" (CInt -> Ptr CSigset -> Ptr CSigset -> IO CInt
c_sigprocmask CInt
0 Ptr CSigset
forall a. Ptr a
nullPtr Ptr CSigset
p)
  return (SignalSet fp)

sigProcMask :: String -> CInt -> SignalSet -> IO ()
sigProcMask :: String -> CInt -> SignalSet -> IO ()
sigProcMask String
fn CInt
how (SignalSet ForeignPtr CSigset
set) =
  ForeignPtr CSigset -> (Ptr CSigset -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CSigset
set ((Ptr CSigset -> IO ()) -> IO ())
-> (Ptr CSigset -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CSigset
p_set ->
    String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
fn (CInt -> Ptr CSigset -> Ptr CSigset -> IO CInt
c_sigprocmask CInt
how Ptr CSigset
p_set Ptr CSigset
forall a. Ptr a
nullPtr)

-- | @setSignalMask mask@ calls @sigprocmask@ with
--   @SIG_SETMASK@ to block all interrupts in @mask@.
setSignalMask :: SignalSet -> IO ()
setSignalMask :: SignalSet -> IO ()
setSignalMask SignalSet
set = String -> CInt -> SignalSet -> IO ()
sigProcMask String
"setSignalMask" (CONST_SIG_SETMASK :: CInt) set

-- | @blockSignals mask@ calls @sigprocmask@ with
--   @SIG_BLOCK@ to add all interrupts in @mask@ to the
--  set of blocked interrupts.
blockSignals :: SignalSet -> IO ()
blockSignals :: SignalSet -> IO ()
blockSignals SignalSet
set = String -> CInt -> SignalSet -> IO ()
sigProcMask String
"blockSignals" (CONST_SIG_BLOCK :: CInt) set

-- | @unblockSignals mask@ calls @sigprocmask@ with
--   @SIG_UNBLOCK@ to remove all interrupts in @mask@ from the
--   set of blocked interrupts.
unblockSignals :: SignalSet -> IO ()
unblockSignals :: SignalSet -> IO ()
unblockSignals SignalSet
set = String -> CInt -> SignalSet -> IO ()
sigProcMask String
"unblockSignals" (CONST_SIG_UNBLOCK :: CInt) set


{-# LINE 807 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 821 "libraries/unix/System/Posix/Signals.hsc" #-}

-- | @getPendingSignals@ calls @sigpending@ to obtain
--   the set of interrupts which have been received but are currently blocked.
getPendingSignals :: IO SignalSet
getPendingSignals :: IO SignalSet
getPendingSignals = do
  fp <- Int -> IO (ForeignPtr CSigset)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
sizeof_sigset_t
  withForeignPtr fp $ \Ptr CSigset
p ->
   String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"getPendingSignals" (Ptr CSigset -> IO CInt
c_sigpending Ptr CSigset
p)
  return (SignalSet fp)

-- | @awaitSignal iset@ suspends execution until an interrupt is received.
-- If @iset@ is @Just s@, @awaitSignal@ calls @sigsuspend@, installing
-- @s@ as the new signal mask before suspending execution; otherwise, it
-- calls @sigsuspend@ with current signal mask. Note that RTS
-- scheduler signal (either 'virtualTimerExpired' or 'realTimeAlarm')
-- could cause premature termination of this call. It might be necessary to block that
-- signal before invocation of @awaitSignal@ with 'blockSignals' 'reservedSignals'.
--
-- @awaitSignal@ returns when signal was received and processed by a
-- signal handler, or if the signal could not be caught. If you have
-- installed any signal handlers with @installHandler@, it may be wise
-- to call @yield@ directly after @awaitSignal@ to ensure that the
-- signal handler runs as promptly as possible.
awaitSignal :: Maybe SignalSet -> IO ()
awaitSignal :: Maybe SignalSet -> IO ()
awaitSignal Maybe SignalSet
maybe_sigset = do
  fp <- case Maybe SignalSet
maybe_sigset of
          Maybe SignalSet
Nothing -> do SignalSet fp <- IO SignalSet
getSignalMask; return fp
          Just (SignalSet ForeignPtr CSigset
fp) -> ForeignPtr CSigset -> IO (ForeignPtr CSigset)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ForeignPtr CSigset
fp
  withForeignPtr fp $ \Ptr CSigset
p -> do
  _ <- Ptr CSigset -> IO CInt
c_sigsuspend Ptr CSigset
p
  return ()
  -- ignore the return value; according to the docs it can only ever be
  -- (-1) with errno set to EINTR.
  -- XXX My manpage says it can also return EFAULT. And why is ignoring
  -- EINTR the right thing to do?


{-# LINE 858 "libraries/unix/System/Posix/Signals.hsc" #-}


{-# LINE 860 "libraries/unix/System/Posix/Signals.hsc" #-}

foreign import ccall unsafe "sigsuspend"
  c_sigsuspend :: Ptr CSigset -> IO CInt

foreign import capi unsafe "signal.h sigdelset"
  c_sigdelset   :: Ptr CSigset -> CInt -> IO CInt

foreign import capi unsafe "signal.h sigfillset"
  c_sigfillset  :: Ptr CSigset -> IO CInt

foreign import capi unsafe "signal.h sigismember"
  c_sigismember :: Ptr CSigset -> CInt -> IO CInt

foreign import ccall unsafe "sigpending"
  c_sigpending :: Ptr CSigset -> IO CInt


{-# LINE 877 "libraries/unix/System/Posix/Signals.hsc" #-}