{-# LINE 1 "System/Posix/Signals.hsc" #-}{-# LANGUAGE DeriveDataTypeable,PatternGuards #-}{-# LINE 2 "System/Posix/Signals.hsc" #-}{-# OPTIONS_GHC -fno-cse #-}-- global variables------------------------------------------------------------------------------- |-- 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-------------------------------------------------------------------------------{-# LINE 18 "System/Posix/Signals.hsc" #-}#include "HsUnixConfig.h"{-# LINE 21 "System/Posix/Signals.hsc" #-}{-# LINE 22 "System/Posix/Signals.hsc" #-}{-# LINE 23 "System/Posix/Signals.hsc" #-}moduleSystem.Posix.Signals(-- * The Signal typeSignal,-- * Specific signalsnullSignal,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 51 "System/Posix/Signals.hsc" #-}pollableEvent,sigPOLL,{-# LINE 53 "System/Posix/Signals.hsc" #-}profilingTimerExpired,sigPROF,badSystemCall,sigSYS,breakpointTrap,sigTRAP,urgentDataAvailable,sigURG,virtualTimerExpired,sigVTALRM,cpuTimeLimitExceeded,sigXCPU,fileSizeLimitExceeded,sigXFSZ,-- * Sending signalsraiseSignal,signalProcess,signalProcessGroup,{-# LINE 67 "System/Posix/Signals.hsc" #-}-- * Handling signalsHandler(Default,Ignore,Catch,CatchOnce),installHandler,{-# LINE 71 "System/Posix/Signals.hsc" #-}-- * Signal setsSignalSet,emptySignalSet,fullSignalSet,reservedSignals,addSignal,deleteSignal,inSignalSet,-- * The process signal maskgetSignalMask,setSignalMask,blockSignals,unblockSignals,-- * The alarm timerscheduleAlarm,-- * Waiting for signalsgetPendingSignals,{-# LINE 86 "System/Posix/Signals.hsc" #-}awaitSignal,{-# LINE 88 "System/Posix/Signals.hsc" #-}{-# LINE 90 "System/Posix/Signals.hsc" #-}-- * The @NOCLDSTOP@ flagsetStoppedChildFlag,queryStoppedChildFlag,{-# LINE 93 "System/Posix/Signals.hsc" #-}-- MISSING FUNCTIONALITY:-- sigaction(), (inc. the sigaction structure + flags etc.)-- the siginfo structure-- sigaltstack()-- sighold, sigignore, sigpause, sigrelse, sigset-- siginterrupt)whereimportForeignhiding(unsafePerformIO)importForeign.CimportSystem.IO.Unsafe(unsafePerformIO)importSystem.Posix.TypesimportSystem.Posix.InternalsimportSystem.Posix.ProcessimportSystem.Posix.Process.InternalsimportData.Dynamic{-# LINE 112 "System/Posix/Signals.hsc" #-}{-# LINE 113 "System/Posix/Signals.hsc" #-}#include "rts/Signals.h"{-# LINE 117 "System/Posix/Signals.hsc" #-}importGHC.Conchiding(Signal){-# LINE 120 "System/Posix/Signals.hsc" #-}-- ------------------------------------------------------------------------------- Specific signalsnullSignal::SignalnullSignal=0sigABRT::CIntsigABRT=CONST_SIGABRTsigALRM::CIntsigALRM=CONST_SIGALRMsigBUS::CIntsigBUS=CONST_SIGBUSsigCHLD::CIntsigCHLD=CONST_SIGCHLDsigCONT::CIntsigCONT=CONST_SIGCONTsigFPE::CIntsigFPE=CONST_SIGFPEsigHUP::CIntsigHUP=CONST_SIGHUPsigILL::CIntsigILL=CONST_SIGILLsigINT::CIntsigINT=CONST_SIGINTsigKILL::CIntsigKILL=CONST_SIGKILLsigPIPE::CIntsigPIPE=CONST_SIGPIPEsigQUIT::CIntsigQUIT=CONST_SIGQUITsigSEGV::CIntsigSEGV=CONST_SIGSEGVsigSTOP::CIntsigSTOP=CONST_SIGSTOPsigTERM::CIntsigTERM=CONST_SIGTERMsigTSTP::CIntsigTSTP=CONST_SIGTSTPsigTTIN::CIntsigTTIN=CONST_SIGTTINsigTTOU::CIntsigTTOU=CONST_SIGTTOUsigUSR1::CIntsigUSR1=CONST_SIGUSR1sigUSR2::CIntsigUSR2=CONST_SIGUSR2{-# LINE 168 "System/Posix/Signals.hsc" #-}sigPOLL::CIntsigPOLL=CONST_SIGPOLL{-# LINE 171 "System/Posix/Signals.hsc" #-}sigPROF::CIntsigPROF=CONST_SIGPROFsigSYS::CIntsigSYS=CONST_SIGSYSsigTRAP::CIntsigTRAP=CONST_SIGTRAPsigURG::CIntsigURG=CONST_SIGURGsigVTALRM::CIntsigVTALRM=CONST_SIGVTALRMsigXCPU::CIntsigXCPU=CONST_SIGXCPUsigXFSZ::CIntsigXFSZ=CONST_SIGXFSZinternalAbort::SignalinternalAbort=sigABRTrealTimeAlarm::SignalrealTimeAlarm=sigALRMbusError::SignalbusError=sigBUSprocessStatusChanged::SignalprocessStatusChanged=sigCHLDcontinueProcess::SignalcontinueProcess=sigCONTfloatingPointException::SignalfloatingPointException=sigFPElostConnection::SignallostConnection=sigHUPillegalInstruction::SignalillegalInstruction=sigILLkeyboardSignal::SignalkeyboardSignal=sigINTkillProcess::SignalkillProcess=sigKILLopenEndedPipe::SignalopenEndedPipe=sigPIPEkeyboardTermination::SignalkeyboardTermination=sigQUITsegmentationViolation::SignalsegmentationViolation=sigSEGVsoftwareStop::SignalsoftwareStop=sigSTOPsoftwareTermination::SignalsoftwareTermination=sigTERMkeyboardStop::SignalkeyboardStop=sigTSTPbackgroundRead::SignalbackgroundRead=sigTTINbackgroundWrite::SignalbackgroundWrite=sigTTOUuserDefinedSignal1::SignaluserDefinedSignal1=sigUSR1userDefinedSignal2::SignaluserDefinedSignal2=sigUSR2{-# LINE 247 "System/Posix/Signals.hsc" #-}pollableEvent::SignalpollableEvent=sigPOLL{-# LINE 250 "System/Posix/Signals.hsc" #-}profilingTimerExpired::SignalprofilingTimerExpired=sigPROFbadSystemCall::SignalbadSystemCall=sigSYSbreakpointTrap::SignalbreakpointTrap=sigTRAPurgentDataAvailable::SignalurgentDataAvailable=sigURGvirtualTimerExpired::SignalvirtualTimerExpired=sigVTALRMcpuTimeLimitExceeded::SignalcpuTimeLimitExceeded=sigXCPUfileSizeLimitExceeded::SignalfileSizeLimitExceeded=sigXFSZ-- ------------------------------------------------------------------------------- Signal-related functions-- | @signalProcess int pid@ calls @kill@ to signal process @pid@ -- with interrupt signal @int@.signalProcess::Signal->ProcessID->IO()signalProcesssigpid=throwErrnoIfMinus1_"signalProcess"(c_killpidsig)foreignimportccallunsafe"kill"c_kill::CPid->CInt->IOCInt-- | @signalProcessGroup int pgid@ calls @kill@ to signal -- all processes in group @pgid@ with interrupt signal @int@.signalProcessGroup::Signal->ProcessGroupID->IO()signalProcessGroupsigpgid=throwErrnoIfMinus1_"signalProcessGroup"(c_killpgpgidsig)foreignimportccallunsafe"killpg"c_killpg::CPid->CInt->IOCInt-- | @raiseSignal int@ calls @kill@ to signal the current process-- with interrupt signal @int@. raiseSignal::Signal->IO()raiseSignalsig=throwErrnoIfMinus1_"raiseSignal"(c_raisesig){-# LINE 303 "System/Posix/Signals.hsc" #-}foreignimportccallunsafe"raise"c_raise::CInt->IOCInt{-# LINE 306 "System/Posix/Signals.hsc" #-}{-# LINE 308 "System/Posix/Signals.hsc" #-}typeSignal=CInt-- | The actions to perform when a signal is received.dataHandler=Default|Ignore-- not yet: | Hold |Catch(IO())|CatchOnce(IO())|CatchInfo(SignalInfo->IO())|CatchInfoOnce(SignalInfo->IO())deriving(Typeable)-- | Information about a received signal (derived from @siginfo_t@).dataSignalInfo=SignalInfo{siginfoSignal::Signal,siginfoError::Errno,siginfoSpecific::SignalSpecificInfo}-- | Information specific to a particular type of signal-- (derived from @siginfo_t@).dataSignalSpecificInfo=NoSignalSpecificInfo|SigChldInfo{siginfoPid::ProcessID,siginfoUid::UserID,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 returnedinstallHandler::Signal->Handler->MaybeSignalSet-- ^ other signals to block->IOHandler-- ^ old handler{-# LINE 356 "System/Posix/Signals.hsc" #-}installHandlersighandler_maybe_mask=doensureIOManagerIsRunning-- 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)<-casehandlerofIgnore->doold_action<-stg_sig_installsigSTG_SIG_IGNnullPtrold_handler<-setHandlersigNothingreturn(old_action,old_handler)Default->doold_action<-stg_sig_installsigSTG_SIG_DFLnullPtrold_handler<-setHandlersigNothingreturn(old_action,old_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.letdyn=toDynhandlerold_handler<-casehandlerofCatchaction->setHandlersig(Just(constaction,dyn))CatchOnceaction->setHandlersig(Just(constaction,dyn))CatchInfoaction->setHandlersig(Just(getinfoaction,dyn))CatchInfoOnceaction->setHandlersig(Just(getinfoaction,dyn))_->error"installHandler"letaction=casehandlerofCatch_->STG_SIG_HANCatchOnce_->STG_SIG_RSTCatchInfo_->STG_SIG_HANCatchInfoOnce_->STG_SIG_RST_->error"installHandler"old_action<-stg_sig_installsigactionnullPtr-- mask is pointless, so leave it NULLreturn(old_action,old_handler)case(old_handler,old_action)of(_,STG_SIG_DFL)->return$Default(_,STG_SIG_IGN)->return$Ignore(Nothing,_)->return$Ignore(Just(_,dyn),_)|Justh<-fromDynamicdyn->returnh|Justio<-fromDynamicdyn->return(Catchio)-- handlers put there by the base package have type IO ()|otherwise->returnDefaultforeignimportccallunsafestg_sig_install::CInt-- sig no.->CInt-- action code (STG_SIG_HAN etc.)->PtrCSigset-- (in, out) blocked->IOCInt-- (ret) old action codegetinfo::(SignalInfo->IO())->ForeignPtrWord8->IO()getinfohandlerfp_info=dosi<-unmarshalSigInfofp_infohandlersiunmarshalSigInfo::ForeignPtrWord8->IOSignalInfounmarshalSigInfofp=dowithForeignPtrfp$\p->dosig<-((\hsc_ptr->peekByteOffhsc_ptr0))p{-# LINE 426 "System/Posix/Signals.hsc" #-}errno<-((\hsc_ptr->peekByteOffhsc_ptr4))p{-# LINE 427 "System/Posix/Signals.hsc" #-}extra<-casesigof_|sig==sigCHLD->dopid<-((\hsc_ptr->peekByteOffhsc_ptr12))p{-# LINE 430 "System/Posix/Signals.hsc" #-}uid<-((\hsc_ptr->peekByteOffhsc_ptr16))p{-# LINE 431 "System/Posix/Signals.hsc" #-}wstat<-((\hsc_ptr->peekByteOffhsc_ptr20))p{-# LINE 432 "System/Posix/Signals.hsc" #-}pstat<-decipherWaitStatuswstatreturnSigChldInfo{siginfoPid=pid,siginfoUid=uid,siginfoStatus=pstat}_|otherwise->returnNoSignalSpecificInforeturnSignalInfo{siginfoSignal=sig,siginfoError=Errnoerrno,siginfoSpecific=extra}{-# LINE 445 "System/Posix/Signals.hsc" #-}{-# LINE 446 "System/Posix/Signals.hsc" #-}-- ------------------------------------------------------------------------------- Alarms-- | @scheduleAlarm i@ calls @alarm@ to schedule a real time-- alarm at least @i@ seconds in the future.scheduleAlarm::Int->IOIntscheduleAlarmsecs=dor<-c_alarm(fromIntegralsecs)return(fromIntegralr)foreignimportccallunsafe"alarm"c_alarm::CUInt->IOCUInt{-# LINE 461 "System/Posix/Signals.hsc" #-}-- ------------------------------------------------------------------------------- The NOCLDSTOP flagforeignimportccall"&nocldstop"nocldstop::PtrInt-- | Tells the system whether or not to set the @SA_NOCLDSTOP@ flag when-- installing new signal handlers.setStoppedChildFlag::Bool->IOBoolsetStoppedChildFlagb=dorc<-peeknocldstoppokenocldstop$fromEnum(notb)return(rc==(0::Int))-- | Queries the current state of the stopped child flag.queryStoppedChildFlag::IOBoolqueryStoppedChildFlag=dorc<-peeknocldstopreturn(rc==(0::Int)){-# LINE 480 "System/Posix/Signals.hsc" #-}-- ------------------------------------------------------------------------------- Manipulating signal setsnewtypeSignalSet=SignalSet(ForeignPtrCSigset)emptySignalSet::SignalSetemptySignalSet=unsafePerformIO$dofp<-mallocForeignPtrBytessizeof_sigset_tthrowErrnoIfMinus1_"emptySignalSet"(withForeignPtrfp$c_sigemptyset)return(SignalSetfp)fullSignalSet::SignalSetfullSignalSet=unsafePerformIO$dofp<-mallocForeignPtrBytessizeof_sigset_tthrowErrnoIfMinus1_"fullSignalSet"(withForeignPtrfp$c_sigfillset)return(SignalSetfp)-- | A set of signals reserved for use by the implementation. In GHC, this will normally-- include either `sigVTALRM` or `sigALRM`.reservedSignals::SignalSetreservedSignals=addSignalrtsTimerSignalemptySignalSetforeignimportccallrtsTimerSignal::CIntinfixr`addSignal`,`deleteSignal`addSignal::Signal->SignalSet->SignalSetaddSignalsig(SignalSetfp1)=unsafePerformIO$dofp2<-mallocForeignPtrBytessizeof_sigset_twithForeignPtrfp1$\p1->withForeignPtrfp2$\p2->docopyBytesp2p1sizeof_sigset_tthrowErrnoIfMinus1_"addSignal"(c_sigaddsetp2sig)return(SignalSetfp2)deleteSignal::Signal->SignalSet->SignalSetdeleteSignalsig(SignalSetfp1)=unsafePerformIO$dofp2<-mallocForeignPtrBytessizeof_sigset_twithForeignPtrfp1$\p1->withForeignPtrfp2$\p2->docopyBytesp2p1sizeof_sigset_tthrowErrnoIfMinus1_"deleteSignal"(c_sigdelsetp2sig)return(SignalSetfp2)inSignalSet::Signal->SignalSet->BoolinSignalSetsig(SignalSetfp)=unsafePerformIO$withForeignPtrfp$\p->dor<-throwErrnoIfMinus1"inSignalSet"(c_sigismemberpsig)return(r/=0)-- | @getSignalMask@ calls @sigprocmask@ to determine the-- set of interrupts which are currently being blocked.getSignalMask::IOSignalSetgetSignalMask=dofp<-mallocForeignPtrBytessizeof_sigset_twithForeignPtrfp$\p->throwErrnoIfMinus1_"getSignalMask"(c_sigprocmask0nullPtrp)return(SignalSetfp)sigProcMask::String->CInt->SignalSet->IO()sigProcMaskfnhow(SignalSetset)=withForeignPtrset$\p_set->throwErrnoIfMinus1_fn(c_sigprocmaskhowp_setnullPtr)-- | @setSignalMask mask@ calls @sigprocmask@ with-- @SIG_SETMASK@ to block all interrupts in @mask@.setSignalMask::SignalSet->IO()setSignalMaskset=sigProcMask"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()blockSignalsset=sigProcMask"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()unblockSignalsset=sigProcMask"unblockSignals"(CONST_SIG_UNBLOCK::CInt)set-- | @getPendingSignals@ calls @sigpending@ to obtain-- the set of interrupts which have been received but are currently blocked.getPendingSignals::IOSignalSetgetPendingSignals=dofp<-mallocForeignPtrBytessizeof_sigset_twithForeignPtrfp$\p->throwErrnoIfMinus1_"getPendingSignals"(c_sigpendingp)return(SignalSetfp){-# LINE 571 "System/Posix/Signals.hsc" #-}-- | @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::MaybeSignalSet->IO()awaitSignalmaybe_sigset=dofp<-casemaybe_sigsetofNothing->doSignalSetfp<-getSignalMask;returnfpJust(SignalSetfp)->returnfpwithForeignPtrfp$\p->do_<-c_sigsuspendpreturn()-- 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?foreignimportccallunsafe"sigsuspend"c_sigsuspend::PtrCSigset->IOCInt{-# LINE 601 "System/Posix/Signals.hsc" #-}{-# LINE 612 "System/Posix/Signals.hsc" #-}foreignimportccallunsafe"__hscore_sigdelset"c_sigdelset::PtrCSigset->CInt->IOCIntforeignimportccallunsafe"__hscore_sigfillset"c_sigfillset::PtrCSigset->IOCIntforeignimportccallunsafe"__hscore_sigismember"c_sigismember::PtrCSigset->CInt->IOCInt{-# LINE 621 "System/Posix/Signals.hsc" #-}foreignimportccallunsafe"sigpending"c_sigpending::PtrCSigset->IOCInt