diff options
author | Marcin Szamotulski <profunctor@pm.me> | 2021-02-04 09:42:03 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-02-13 21:30:09 -0500 |
commit | 83ace021a33fb6f4ce940f969467d6712cbaa858 (patch) | |
tree | bfb6bef653d327bb4d7610e566165588ef08b8b0 /libraries/base/GHC | |
parent | 793dcb3de47587f849ad286caf362cac0c67edb2 (diff) | |
download | haskell-83ace021a33fb6f4ce940f969467d6712cbaa858.tar.gz |
Make closeFdWith uninterrupitble
closeFdWith is accessing shared TMVar - the IO manager callbak table
var. It might be concurrently used by different threads: either becuase
it contains information about different file descriptors or a single
file descriptor is accessed from different threads. For this reason
`takeMVar` might block, although for a very short time as all the
IO operations are using epoll (or its equivalent).
This change makes hClose and Network.Socket.close safe in presence of
asynchronous exceptions. This is especailly important in the context of
`bracket` which expects uninterruptible close handler.
Diffstat (limited to 'libraries/base/GHC')
-rw-r--r-- | libraries/base/GHC/Event/Thread.hs | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/libraries/base/GHC/Event/Thread.hs b/libraries/base/GHC/Event/Thread.hs index 367791354f..a330225622 100644 --- a/libraries/base/GHC/Event/Thread.hs +++ b/libraries/base/GHC/Event/Thread.hs @@ -30,7 +30,7 @@ import GHC.Conc.Sync (TVar, ThreadId, ThreadStatus(..), atomically, forkIO, labelThread, modifyMVar_, withMVar, newTVar, sharedCAF, getNumCapabilities, threadCapability, myThreadId, forkOn, threadStatus, writeTVar, newTVarIO, readTVar, retry,throwSTM,STM) -import GHC.IO (mask_, onException) +import GHC.IO (mask_, uninterruptibleMask_, onException) import GHC.IO.Exception (ioError) import GHC.IOArray (IOArray, newIOArray, readIOArray, writeIOArray, boundsIOArray) @@ -104,7 +104,10 @@ closeFdWith close fd = do mgrs <- flip mapM [low..high] $ \i -> do Just (_,!mgr) <- readIOArray eventManagerArray i return mgr - mask_ $ do + -- 'takeMVar', and 'M.closeFd_' might block, although for a very short time. + -- To make 'closeFdWith' safe in presence of asynchronous exceptions we have + -- to use uninterruptible mask. + uninterruptibleMask_ $ do tables <- flip mapM mgrs $ \mgr -> takeMVar $ M.callbackTableVar mgr fd cbApps <- zipWithM (\mgr table -> M.closeFd_ mgr table fd) mgrs tables close fd `finally` sequence_ (zipWith3 finish mgrs tables cbApps) |