summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libraries/base/GHC/Event/Control.hs28
1 files changed, 23 insertions, 5 deletions
diff --git a/libraries/base/GHC/Event/Control.hs b/libraries/base/GHC/Event/Control.hs
index 0b0f5587a7..83950c24a6 100644
--- a/libraries/base/GHC/Event/Control.hs
+++ b/libraries/base/GHC/Event/Control.hs
@@ -30,11 +30,12 @@ module GHC.Event.Control
import Foreign.ForeignPtr (ForeignPtr)
import GHC.Base
+import GHC.IORef
import GHC.Conc.Signal (Signal)
import GHC.Real (fromIntegral)
import GHC.Show (Show)
import GHC.Word (Word8)
-import Foreign.C.Error (throwErrnoIfMinus1_)
+import Foreign.C.Error (throwErrnoIfMinus1_, throwErrno, getErrno, eBADF)
import Foreign.C.Types (CInt(..), CSize(..))
import Foreign.ForeignPtr (mallocForeignPtrBytes, withForeignPtr)
import Foreign.Marshal (alloca, allocaBytes)
@@ -69,7 +70,9 @@ data Control = W {
, wakeupWriteFd :: {-# UNPACK #-} !Fd
#endif
, didRegisterWakeupFd :: !Bool
- } deriving (Show)
+ -- | Have this Control's fds been cleaned up?
+ , controlIsDead :: !(IORef Bool)
+ }
#if defined(HAVE_EVENTFD)
wakeupReadFd :: Control -> Fd
@@ -101,6 +104,7 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
(wake_rd, wake_wr) <- createPipe
when shouldRegister $ c_setIOManagerWakeupFd wake_wr
#endif
+ isDead <- newIORef False
return W { controlReadFd = fromIntegral ctrl_rd
, controlWriteFd = fromIntegral ctrl_wr
#if defined(HAVE_EVENTFD)
@@ -110,6 +114,7 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
, wakeupWriteFd = fromIntegral wake_wr
#endif
, didRegisterWakeupFd = shouldRegister
+ , controlIsDead = isDead
}
-- | Close the control structure used by the IO manager thread.
@@ -119,6 +124,7 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
-- file after it has been closed.
closeControl :: Control -> IO ()
closeControl w = do
+ atomicModifyIORef (controlIsDead w) (\_ -> (True, ()))
_ <- c_close . fromIntegral . controlReadFd $ w
_ <- c_close . fromIntegral . controlWriteFd $ w
when (didRegisterWakeupFd w) $ c_setIOManagerWakeupFd (-1)
@@ -172,9 +178,21 @@ readControlMessage ctrl fd
sendWakeup :: Control -> IO ()
#if defined(HAVE_EVENTFD)
-sendWakeup c =
- throwErrnoIfMinus1_ "sendWakeup" $
- c_eventfd_write (fromIntegral (controlEventFd c)) 1
+sendWakeup c = do
+ n <- c_eventfd_write (fromIntegral (controlEventFd c)) 1
+ case n of
+ 0 -> return ()
+ _ -> do errno <- getErrno
+ -- Check that Control is still alive if we failed, since it's
+ -- possible that someone cleaned up the fds behind our backs and
+ -- consequently eventfd_write failed with EBADF. If it is dead
+ -- then just swallow the error since we are shutting down
+ -- anyways. Otherwise we will see failures during shutdown from
+ -- setnumcapabilities001 (#12038)
+ isDead <- readIORef (controlIsDead c)
+ if isDead && errno == eBADF
+ then return ()
+ else throwErrno "sendWakeup"
#else
sendWakeup c = do
n <- sendMessage (wakeupWriteFd c) CMsgWakeup