From 74625d6847e970e8bdc6991c327515b3e10b231b Mon Sep 17 00:00:00 2001 From: Andreas Voellmy Date: Mon, 9 Mar 2015 18:27:41 -0400 Subject: RTS/IOManager: fix trac issue #9722. Summary: Whenever the RTS has been inactive for idleGCDelayTime, the idle timer fires and calls wakeUpRts(), which in turn calls ioManagerWakeup(), which in turn writes a byte (or a few) to a file descriptor (stored in the io_manager_wakeup_fd variable) registered by the TimerManager and on which the TimerManager will wait. (Note that the write will only occur if the file descriptor is non-negative.) When the RTS shuts down, it shuts down the TimerManager, and in this process the file descriptor stored in io_manager_wakeup_fd is closed. In the error case, the idle timer fires after the close of the file occurs, and then the write() call in ioManagerWakeup() fails and the aforementioned error message gets printed. This patch solves the problem by (1) having the TimerManager (via Control) write -1 to io_manager_wakeup_fd just before closing the file descriptor written in io_manager_wakeup_fd, and (2) having ioManagerWakeup() ignore an error returned by write() in the case that the write returned -1 and the io_manager_wakeup_fd is -1. Reviewers: austin, simonmar, hvr, thomie Reviewed By: thomie Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D722 GHC Trac Issues: #9722 --- libraries/base/GHC/Event/Control.hs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'libraries/base') diff --git a/libraries/base/GHC/Event/Control.hs b/libraries/base/GHC/Event/Control.hs index 747a416343..5dcc66e6dc 100644 --- a/libraries/base/GHC/Event/Control.hs +++ b/libraries/base/GHC/Event/Control.hs @@ -68,6 +68,7 @@ data Control = W { , wakeupReadFd :: {-# UNPACK #-} !Fd , wakeupWriteFd :: {-# UNPACK #-} !Fd #endif + , didRegisterWakeupFd :: !Bool } deriving (Show) #if defined(HAVE_EVENTFD) @@ -108,13 +109,19 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do , wakeupReadFd = fromIntegral wake_rd , wakeupWriteFd = fromIntegral wake_wr #endif + , didRegisterWakeupFd = shouldRegister } -- | Close the control structure used by the IO manager thread. +-- N.B. If this Control is the Control whose wakeup file was registered with +-- the RTS, then *BEFORE* the wakeup file is closed, we must call +-- c_setIOManagerWakeupFd (-1), so that the RTS does not try to use the wakeup +-- file after it has been closed. closeControl :: Control -> IO () closeControl w = do _ <- c_close . fromIntegral . controlReadFd $ w _ <- c_close . fromIntegral . controlWriteFd $ w + when (didRegisterWakeupFd w) $ c_setIOManagerWakeupFd (-1) #if defined(HAVE_EVENTFD) _ <- c_close . fromIntegral . controlEventFd $ w #else -- cgit v1.2.1