{-# LANGUAGE Trustworthy #-}{-# LANGUAGE BangPatterns, ForeignFunctionInterface, NoImplicitPrelude #-}moduleGHC.Event.Thread(getSystemEventManager,ensureIOManagerIsRunning,threadWaitRead,threadWaitWrite,closeFdWith,threadDelay,registerDelay)whereimportData.IORef(IORef,newIORef,readIORef,writeIORef)importData.Maybe(Maybe(..))importForeign.C.Error(eBADF,errnoToIOError)importForeign.Ptr(Ptr)importGHC.BaseimportGHC.Conc.Sync(TVar,ThreadId,ThreadStatus(..),atomically,forkIO,labelThread,modifyMVar_,newTVar,sharedCAF,threadStatus,writeTVar)importGHC.IO(mask_,onException)importGHC.IO.Exception(ioError)importGHC.MVar(MVar,newEmptyMVar,newMVar,putMVar,takeMVar)importGHC.Event.Internal(eventIs,evtClose)importGHC.Event.Manager(Event,EventManager,evtRead,evtWrite,loop,new,registerFd,unregisterFd_,registerTimeout)importqualifiedGHC.Event.ManagerasMimportSystem.IO.Unsafe(unsafePerformIO)importSystem.Posix.Types(Fd)-- | Suspends the current thread for a given number of microseconds-- (GHC only).---- There is no guarantee that the thread will be rescheduled promptly-- when the delay has expired, but the thread will never continue to-- run /earlier/ than specified.threadDelay::Int->IO()threadDelayusecs=mask_$doJustmgr<-getSystemEventManagerm<-newEmptyMVarreg<-registerTimeoutmgrusecs(putMVarm())takeMVarm`onException`M.unregisterTimeoutmgrreg-- | Set the value of returned TVar to True after a given number of-- microseconds. The caveats associated with threadDelay also apply.--registerDelay::Int->IO(TVarBool)registerDelayusecs=dot<-atomically$newTVarFalseJustmgr<-getSystemEventManager_<-registerTimeoutmgrusecs.atomically$writeTVartTruereturnt-- | Block the current thread until data is available to read from the-- given file descriptor.---- This will throw an 'IOError' if the file descriptor was closed-- while this thread was blocked. To safely close a file descriptor-- that has been used with 'threadWaitRead', use 'closeFdWith'.threadWaitRead::Fd->IO()threadWaitRead=threadWaitevtRead{-# INLINE threadWaitRead #-}-- | Block the current thread until the given file descriptor can-- accept data to write.---- This will throw an 'IOError' if the file descriptor was closed-- while this thread was blocked. To safely close a file descriptor-- that has been used with 'threadWaitWrite', use 'closeFdWith'.threadWaitWrite::Fd->IO()threadWaitWrite=threadWaitevtWrite{-# INLINE threadWaitWrite #-}-- | Close a file descriptor in a concurrency-safe way.---- Any threads that are blocked on the file descriptor via-- 'threadWaitRead' or 'threadWaitWrite' will be unblocked by having-- IO exceptions thrown.closeFdWith::(Fd->IO())-- ^ Action that performs the close.->Fd-- ^ File descriptor to close.->IO()closeFdWithclosefd=doJustmgr<-getSystemEventManagerM.closeFdmgrclosefdthreadWait::Event->Fd->IO()threadWaitevtfd=mask_$dom<-newEmptyMVarJustmgr<-getSystemEventManagerreg<-registerFdmgr(\rege->unregisterFd_mgrreg>>putMVarme)fdevtevt'<-takeMVarm`onException`unregisterFd_mgrregifevt'`eventIs`evtClosethenioError$errnoToIOError"threadWait"eBADFNothingNothingelsereturn()-- | Retrieve the system event manager.---- This function always returns 'Just' the system event manager when using the-- threaded RTS and 'Nothing' otherwise.getSystemEventManager::IO(MaybeEventManager)getSystemEventManager=readIORefeventManagerforeignimportccallunsafe"getOrSetSystemEventThreadEventManagerStore"getOrSetSystemEventThreadEventManagerStore::Ptra->IO(Ptra)eventManager::IORef(MaybeEventManager)eventManager=unsafePerformIO$doem<-newIORefNothingsharedCAFemgetOrSetSystemEventThreadEventManagerStore{-# NOINLINE eventManager #-}foreignimportccallunsafe"getOrSetSystemEventThreadIOManagerThreadStore"getOrSetSystemEventThreadIOManagerThreadStore::Ptra->IO(Ptra){-# NOINLINE ioManager #-}ioManager::MVar(MaybeThreadId)ioManager=unsafePerformIO$dom<-newMVarNothingsharedCAFmgetOrSetSystemEventThreadIOManagerThreadStoreensureIOManagerIsRunning::IO()ensureIOManagerIsRunning|notthreaded=return()|otherwise=modifyMVar_ioManager$\old->doletcreate=do!mgr<-newwriteIORefeventManager$Justmgr!t<-forkIO$loopmgrlabelThreadt"IOManager"return$JusttcaseoldofNothing->createst@(Justt)->dos<-threadStatustcasesofThreadFinished->createThreadDied->do-- Sanity check: if the thread has died, there is a chance-- that event manager is still alive. This could happend during-- the fork, for example. In this case we should clean up-- open pipes and everything else related to the event manager.-- See #4449mem<-readIORefeventManager_<-casememofNothing->return()Justem->M.cleanupemcreate_other->returnstforeignimportccallunsafe"rtsSupportsBoundThreads"threaded::Bool