{-# LANGUAGE CPP #-}{-# LANGUAGE MagicHash #-}{-# LANGUAGE NoImplicitPrelude #-}{-# LANGUAGE RankNTypes #-}{-# LANGUAGE UnboxedTuples #-}{-# LANGUAGE UnliftedFFITypes #-}{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE KindSignatures #-}{-# LANGUAGE Unsafe #-}------------------------------------------------------------------------------- |-- Module : GHC.Internal.Conc.Bound-- Copyright : (c) The University of Glasgow 2001-- License : BSD-style (see the file libraries/base/LICENSE)---- Maintainer : libraries@haskell.org-- Stability : stable-- Portability : non-portable (concurrency)---- Bound thread support.-------------------------------------------------------------------------------moduleGHC.Internal.Conc.Bound (forkOS ,forkOSWithUnmask ,isCurrentThreadBound ,runInBoundThread ,runInUnboundThread ,rtsSupportsBoundThreads )where---- JavaScript platform doesn't support bound threads #if !defined(javascript_HOST_ARCH) #define SUPPORT_BOUND_THREADS #endif #if !defined(SUPPORT_BOUND_THREADS) importGHC.Internal.BaseimportGHC.Internal.Conc.Sync(ThreadId)forkOS::IO()->IOThreadIdforkOS_=error"forkOS not supported on this architecture"forkOSWithUnmask::((foralla.IOa->IOa)->IO())->IOThreadIdforkOSWithUnmask_=error"forkOS not supported on this architecture"isCurrentThreadBound::IOBoolisCurrentThreadBound=pureFalserunInBoundThread::IOa->IOarunInBoundThreadaction=actionrunInUnboundThread::IOa->IOarunInUnboundThreadaction=actionrtsSupportsBoundThreads::BoolrtsSupportsBoundThreads=False #else importGHC.Internal.Foreign.StablePtr importGHC.Internal.Foreign.C.Types importGHC.Internal.Control.Monad.Fail importGHC.Internal.Data.Either importqualifiedGHC.Internal.Control.Exception.Base asExceptionimportGHC.Internal.Base importGHC.Internal.Conc.Sync importGHC.Internal.IO importGHC.Internal.Exception importGHC.Internal.IORef importGHC.Internal.MVar -- | 'True' if bound threads are supported.-- If @rtsSupportsBoundThreads@ is 'False', 'isCurrentThreadBound'-- will always return 'False' and both 'forkOS' and 'runInBoundThread' will-- fail.foreignimportccallunsafertsSupportsBoundThreads ::Bool {- | Like 'forkIO', this sparks off a new thread to run the 'IO' computation passed as the first argument, and returns the 'ThreadId' of the newly created thread. However, 'forkOS' creates a /bound/ thread, which is necessary if you need to call foreign (non-Haskell) libraries that make use of thread-local state, such as OpenGL (see "Control.Concurrent#boundthreads"). Using 'forkOS' instead of 'forkIO' makes no difference at all to the scheduling behaviour of the Haskell runtime system. It is a common misconception that you need to use 'forkOS' instead of 'forkIO' to avoid blocking all the Haskell threads when making a foreign call; this isn't the case. To allow foreign calls to be made without blocking all the Haskell threads (with GHC), it is only necessary to use the @-threaded@ option when linking your program, and to make sure the foreign import is not marked @unsafe@. -}forkOS ::IO ()->IO ThreadId foreignexportccallforkOS_entry ::StablePtr (IO ())->IO ()foreignimportccall"forkOS_entry"forkOS_entry_reimported ::StablePtr (IO ())->IO ()forkOS_entry ::StablePtr (IO ())->IO ()forkOS_entry :: StablePtr (IO ()) -> IO () forkOS_entry StablePtr (IO ()) stableAction =doaction <-StablePtr (IO ()) -> IO (IO ()) forall a. StablePtr a -> IO a deRefStablePtr StablePtr (IO ()) stableAction action failNonThreaded ::IO a failNonThreaded :: forall a. IO a failNonThreaded =String -> IO a forall a. String -> IO a forall (m :: * -> *) a. MonadFail m => String -> m a fail (String -> IO a) -> String -> IO a forall a b. (a -> b) -> a -> b $ String "RTS doesn't support multiple OS threads "String -> String -> String forall a. [a] -> [a] -> [a] ++ String "(use ghc -threaded when linking)" #if defined(wasm32_HOST_ARCH) forkOS_=failNonThreaded #else foreignimportccallforkOS_createThread ::StablePtr (IO ())->IO CInt forkOS :: IO () -> IO ThreadId forkOS IO () action0 |Bool rtsSupportsBoundThreads =domv <-IO (MVar ThreadId) forall a. IO (MVar a) newEmptyMVar b <-Exception.getMaskingState let-- async exceptions are masked in the child if they are masked-- in the parent, as for forkIO (see #1048). forkOS_createThread-- creates a thread with exceptions masked by default.action1 =caseMaskingState b ofMaskingState Unmasked ->IO () -> IO () forall a. IO a -> IO a unsafeUnmask IO () action0 MaskingState MaskedInterruptible ->IO () action0 MaskingState MaskedUninterruptible ->IO () -> IO () forall a. IO a -> IO a uninterruptibleMask_ IO () action0 action_plus =IO () -> (SomeException -> IO ()) -> IO () forall e a. Exception e => IO a -> (e -> IO a) -> IO a catch IO () action1 SomeException -> IO () childHandler entry <-newStablePtr (myThreadId >>= putMVar mv >> action_plus )err <-forkOS_createThread entry when (err /= 0)$ fail "Cannot create OS thread."tid <-takeMVar mv freeStablePtr entry return tid |Bool otherwise =IO ThreadId forall a. IO a failNonThreaded #endif -- | Like 'forkIOWithUnmask', but the child thread is a bound thread,-- as with 'forkOS'.forkOSWithUnmask ::((foralla .IO a ->IO a )->IO ())->IO ThreadId forkOSWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId forkOSWithUnmask (forall a. IO a -> IO a) -> IO () io =IO () -> IO ThreadId forkOS ((forall a. IO a -> IO a) -> IO () io IO a -> IO a forall a. IO a -> IO a unsafeUnmask )-- | Returns 'True' if the calling thread is /bound/, that is, if it is-- safe to use foreign libraries that rely on thread-local state from the-- calling thread.isCurrentThreadBound ::IO Bool isCurrentThreadBound :: IO Bool isCurrentThreadBound =(State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO ((State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool) -> (State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool forall a b. (a -> b) -> a -> b $ \State# RealWorld s# ->caseState# RealWorld -> (# State# RealWorld, Int# #) isCurrentThreadBound# State# RealWorld s# of(#State# RealWorld s2# ,Int# flg #)->(#State# RealWorld s2# ,Int# -> Bool isTrue# (Int# flg Int# -> Int# -> Int# /=# Int# 0#)#){- | Run the 'IO' computation passed as the first argument. If the calling thread is not /bound/, a bound thread is created temporarily. @runInBoundThread@ doesn't finish until the 'IO' computation finishes. You can wrap a series of foreign function calls that rely on thread-local state with @runInBoundThread@ so that you can use them without knowing whether the current thread is /bound/. -}runInBoundThread ::IO a ->IO a runInBoundThread :: forall a. IO a -> IO a runInBoundThread IO a action |Bool rtsSupportsBoundThreads =dobound <-IO Bool isCurrentThreadBound ifbound thenaction elsedoref <-newIORef undefined letaction_plus =IO a -> IO (Either SomeException a) forall e a. Exception e => IO a -> IO (Either e a) Exception.try IO a action IO (Either SomeException a) -> (Either SomeException a -> IO ()) -> IO () forall a b. IO a -> (a -> IO b) -> IO b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= IORef (Either SomeException a) -> Either SomeException a -> IO () forall a. IORef a -> a -> IO () writeIORef IORef (Either SomeException a) ref bracket (newStablePtr action_plus )freeStablePtr (\StablePtr (IO ()) cEntry ->StablePtr (IO ()) -> IO () forkOS_entry_reimported StablePtr (IO ()) cEntry IO () -> IO (Either SomeException a) -> IO (Either SomeException a) forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> IORef (Either SomeException a) -> IO (Either SomeException a) forall a. IORef a -> IO a readIORef IORef (Either SomeException a) ref )>>= unsafeResult |Bool otherwise =IO a forall a. IO a failNonThreaded {- | Run the 'IO' computation passed as the first argument. If the calling thread is /bound/, an unbound thread is created temporarily using 'forkIO'. @runInBoundThread@ doesn't finish until the 'IO' computation finishes. Use this function /only/ in the rare case that you have actually observed a performance loss due to the use of bound threads. A program that doesn't need its main thread to be bound and makes /heavy/ use of concurrency (e.g. a web server), might want to wrap its @main@ action in @runInUnboundThread@. Note that exceptions which are thrown to the current thread are thrown in turn to the thread that is executing the given computation. This ensures there's always a way of killing the forked thread. -}runInUnboundThread ::IO a ->IO a runInUnboundThread :: forall a. IO a -> IO a runInUnboundThread IO a action =dobound <-IO Bool isCurrentThreadBound ifbound thendomv <-newEmptyMVar mask $ \forall a. IO a -> IO a restore ->dotid <-IO () -> IO ThreadId forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId forall a b. (a -> b) -> a -> b $ IO a -> IO (Either SomeException a) forall e a. Exception e => IO a -> IO (Either e a) Exception.try (IO a -> IO a forall a. IO a -> IO a restore IO a action )IO (Either SomeException a) -> (Either SomeException a -> IO ()) -> IO () forall a b. IO a -> (a -> IO b) -> IO b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= MVar (Either SomeException a) -> Either SomeException a -> IO () forall a. MVar a -> a -> IO () putMVar MVar (Either SomeException a) mv letwait =MVar (Either SomeException a) -> IO (Either SomeException a) forall a. MVar a -> IO a takeMVar MVar (Either SomeException a) mv IO (Either SomeException a) -> (SomeException -> IO (Either SomeException a)) -> IO (Either SomeException a) forall e a. Exception e => IO a -> (e -> IO a) -> IO a `catchException` \(SomeException e ::SomeException )->ThreadId -> SomeException -> IO () forall e. Exception e => ThreadId -> e -> IO () Exception.throwTo ThreadId tid SomeException e IO () -> IO (Either SomeException a) -> IO (Either SomeException a) forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> IO (Either SomeException a) wait wait >>= unsafeResult elseaction unsafeResult ::Either SomeException a ->IO a unsafeResult :: forall a. Either SomeException a -> IO a unsafeResult =(SomeException -> IO a) -> (a -> IO a) -> Either SomeException a -> IO a forall a c b. (a -> c) -> (b -> c) -> Either a b -> c either SomeException -> IO a forall e a. (HasCallStack, Exception e) => e -> IO a Exception.throwIO a -> IO a forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return #endif