summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Szamotulski <profunctor@pm.me>2021-02-04 09:42:03 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-02-13 21:30:09 -0500
commit83ace021a33fb6f4ce940f969467d6712cbaa858 (patch)
treebfb6bef653d327bb4d7610e566165588ef08b8b0
parent793dcb3de47587f849ad286caf362cac0c67edb2 (diff)
downloadhaskell-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.
-rw-r--r--libraries/base/GHC/Event/Thread.hs7
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)