Ticket #4533: fix-4533.dpatch

File fix-4533.dpatch, 17.0 KB (added by bos, 2 years ago)

Updated patch

Line 
15 patches for repository http://darcs.haskell.org/ghc-7.0/packages/base:
2
3Fri Nov 26 12:08:41 PST 2010  Bryan O'Sullivan <bos@serpentine.com>
4  * Fix typo
5
6Fri Nov 26 15:27:56 PST 2010  Bryan O'Sullivan <bos@serpentine.com>
7  * Bump the version of base
8
9Fri Nov 26 15:28:10 PST 2010  Bryan O'Sullivan <bos@serpentine.com>
10  * Fix #4514 - IO manager deadlock
11 
12  * The public APIs for threadWaitRead and threadWaitWrite remain unchanged,
13    and now throw an IOError if a file descriptor is closed behind their
14    backs.  This behaviour is documented.
15 
16  * The GHC.Conc API is extended to add a closeFd function, the behaviour
17    of which is documented.
18 
19  * Behind the scenes, we add a new evtClose event, which is used only when
20    one thread closes a file descriptor that other threads are blocking on.
21 
22  * Both base's IO code and network use the new closeFd function.
23 
24
25Fri Nov 26 22:04:25 PST 2010  Bryan O'Sullivan <bos@serpentine.com>
26  * Drop System.Mem.Weak's dependency on Prelude
27
28Sat Nov 27 10:18:26 PST 2010  Bryan O'Sullivan <bos@serpentine.com>
29  * Fix #4533 - unregister callbacks on exception, fixing a memory leak
30 
31  Our problem here was that if a thread blocked in threadWait or
32  threadDelay and was killed by an exception thrown from another thread,
33  its registration with the IO manager would not be cleared.
34 
35  The fix is simply to install exception handlers that do the cleanup and
36  propagate the exception.
37 
38
39New patches:
40
41[Fix typo
42Bryan O'Sullivan <bos@serpentine.com>**20101126200841
43 Ignore-this: fc81cd0e820931df6dc87c52751594ef
44] hunk ./System/Event/KQueue.hsc 281
45 toEvent (Filter f)
46     | f == (#const EVFILT_READ) = E.evtRead
47     | f == (#const EVFILT_WRITE) = E.evtWrite
48-    | otherwise = error $ "toEvent: unknonwn filter " ++ show f
49+    | otherwise = error $ "toEvent: unknown filter " ++ show f
50 
51 foreign import ccall unsafe "kqueue"
52     c_kqueue :: IO CInt
53[Bump the version of base
54Bryan O'Sullivan <bos@serpentine.com>**20101126232756
55 Ignore-this: deae33d1f0411b39d2f04e3e3e4e3598
56] hunk ./base.cabal 2
57 name:           base
58-version:        4.3.0.0
59+version:        4.3.1.0
60 license:        BSD3
61 license-file:   LICENSE
62 maintainer:     libraries@haskell.org
63[Fix #4514 - IO manager deadlock
64Bryan O'Sullivan <bos@serpentine.com>**20101126232810
65 Ignore-this: 9deacf960c78c797ef6859b60ca9922
66 
67 * The public APIs for threadWaitRead and threadWaitWrite remain unchanged,
68   and now throw an IOError if a file descriptor is closed behind their
69   backs.  This behaviour is documented.
70 
71 * The GHC.Conc API is extended to add a closeFd function, the behaviour
72   of which is documented.
73 
74 * Behind the scenes, we add a new evtClose event, which is used only when
75   one thread closes a file descriptor that other threads are blocking on.
76 
77 * Both base's IO code and network use the new closeFd function.
78 
79] {
80hunk ./Control/Concurrent.hs 50
81         threadDelay,            -- :: Int -> IO ()
82         threadWaitRead,         -- :: Int -> IO ()
83         threadWaitWrite,        -- :: Int -> IO ()
84+        closeFd,                -- :: (Int -> IO ()) -> Int -> IO ()
85 #endif
86 
87         -- * Communication abstractions
88hunk ./Control/Concurrent.hs 454
89 
90 -- | Block the current thread until data is available to read on the
91 -- given file descriptor (GHC only).
92+--
93+-- This will throw an 'IOError' if the file descriptor was closed
94+-- while this thread was blocked.
95 threadWaitRead :: Fd -> IO ()
96 threadWaitRead fd
97 #ifdef mingw32_HOST_OS
98hunk ./Control/Concurrent.hs 477
99 
100 -- | Block the current thread until data can be written to the
101 -- given file descriptor (GHC only).
102+--
103+-- This will throw an 'IOError' if the file descriptor was closed
104+-- while this thread was blocked.
105 threadWaitWrite :: Fd -> IO ()
106 threadWaitWrite fd
107 #ifdef mingw32_HOST_OS
108hunk ./Control/Concurrent.hs 489
109   = GHC.Conc.threadWaitWrite fd
110 #endif
111 
112+-- | Close a file descriptor in a concurrency-safe way (GHC only).  If
113+-- you are using 'threadWaitRead' or 'threadWaitWrite' to perform
114+-- blocking I\/O, you /must/ use this function to close file
115+-- descriptors, or blocked threads may not be woken.
116+--
117+-- Any threads that are blocked on the file descriptor via
118+-- 'threadWaitRead' or 'threadWaitWrite' will be unblocked by having
119+-- IO exceptions thrown.
120+closeFd :: (Fd -> IO ())        -- ^ Low-level action that performs the real close.
121+        -> Fd                   -- ^ File descriptor to close.
122+        -> IO ()
123+closeFd close fd
124+#ifdef mingw32_HOST_OS
125+  = close fd
126+#else
127+  = GHC.Conc.closeFd close fd
128+#endif
129+
130 #ifdef mingw32_HOST_OS
131 foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
132 
133hunk ./GHC/Conc.lhs 55
134         , registerDelay         -- :: Int -> IO (TVar Bool)
135         , threadWaitRead        -- :: Int -> IO ()
136         , threadWaitWrite       -- :: Int -> IO ()
137+        , closeFd               -- :: (Int -> IO ()) -> Int -> IO ()
138 
139         -- * TVars
140         , STM(..)
141hunk ./GHC/Conc/IO.hs 34
142         , registerDelay         -- :: Int -> IO (TVar Bool)
143         , threadWaitRead        -- :: Int -> IO ()
144         , threadWaitWrite       -- :: Int -> IO ()
145+        , closeFd               -- :: (Int -> IO ()) -> Int -> IO ()
146 
147 #ifdef mingw32_HOST_OS
148         , asyncRead     -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
149hunk ./GHC/Conc/IO.hs 86
150 
151 -- | Block the current thread until data can be written to the
152 -- given file descriptor (GHC only).
153+--
154+-- This will throw an 'IOError' if the file descriptor was closed
155+-- while this thread was blocked.
156 threadWaitWrite :: Fd -> IO ()
157 threadWaitWrite fd
158 #ifndef mingw32_HOST_OS
159hunk ./GHC/Conc/IO.hs 99
160         case waitWrite# fd# s of { s' -> (# s', () #)
161         }}
162 
163+-- | Close a file descriptor in a concurrency-safe way (GHC only).  If
164+-- you are using 'threadWaitRead' or 'threadWaitWrite' to perform
165+-- blocking I\/O, you /must/ use this function to close file
166+-- descriptors, or blocked threads may not be woken.
167+--
168+-- Any threads that are blocked on the file descriptor via
169+-- 'threadWaitRead' or 'threadWaitWrite' will be unblocked by having
170+-- IO exceptions thrown.
171+closeFd :: (Fd -> IO ())        -- ^ Low-level action that performs the real close.
172+        -> Fd                   -- ^ File descriptor to close.
173+        -> IO ()
174+closeFd close fd
175+#ifndef mingw32_HOST_OS
176+  | threaded  = Event.closeFd close fd
177+#endif
178+  | otherwise = close fd
179+
180 -- | Suspends the current thread for a given number of microseconds
181 -- (GHC only).
182 --
183hunk ./GHC/IO/FD.hs 284
184 #ifndef mingw32_HOST_OS
185   (flip finally) (release fd) $ do
186 #endif
187-  throwErrnoIfMinus1Retry_ "GHC.IO.FD.close" $
188+  let closer realFd =
189+        throwErrnoIfMinus1Retry_ "GHC.IO.FD.close" $
190 #ifdef mingw32_HOST_OS
191hunk ./GHC/IO/FD.hs 287
192-    if fdIsSocket fd then
193-       c_closesocket (fdFD fd)
194-    else
195+        if fdIsSocket fd then
196+          c_closesocket (fromIntegral realFd)
197+        else
198 #endif
199hunk ./GHC/IO/FD.hs 291
200-       c_close (fdFD fd)
201+          c_close (fromIntegral realFd)
202+  closeFd closer (fromIntegral (fdFD fd))
203 
204 release :: FD -> IO ()
205 #ifdef mingw32_HOST_OS
206hunk ./System/Event.hs 25
207     , registerFd_
208     , unregisterFd
209     , unregisterFd_
210-    , fdWasClosed
211+    , closeFd
212 
213       -- * Registering interest in timeout events
214     , TimeoutCallback
215hunk ./System/Event/Internal.hs 15
216     , Event
217     , evtRead
218     , evtWrite
219+    , evtClose
220     , eventIs
221     -- * Timeout type
222     , Timeout(..)
223hunk ./System/Event/Internal.hs 33
224 import GHC.Show (Show(..))
225 import GHC.List (filter, null)
226 
227--- | An I/O event.
228+-- | An I\/O event.
229 newtype Event = Event Int
230     deriving (Eq)
231 
232hunk ./System/Event/Internal.hs 41
233 evtNothing = Event 0
234 {-# INLINE evtNothing #-}
235 
236+-- | Data is available to be read.
237 evtRead :: Event
238 evtRead = Event 1
239 {-# INLINE evtRead #-}
240hunk ./System/Event/Internal.hs 46
241 
242+-- | The file descriptor is ready to accept a write.
243 evtWrite :: Event
244 evtWrite = Event 2
245 {-# INLINE evtWrite #-}
246hunk ./System/Event/Internal.hs 51
247 
248+-- | Another thread closed the file descriptor.
249+evtClose :: Event
250+evtClose = Event 4
251+{-# INLINE evtClose #-}
252+
253 eventIs :: Event -> Event -> Bool
254 eventIs (Event a) (Event b) = a .&. b /= 0
255 
256hunk ./System/Event/Internal.hs 61
257 instance Show Event where
258     show e = '[' : (intercalate "," . filter (not . null) $
259-                    [evtRead `so` "evtRead", evtWrite `so` "evtWrite"]) ++ "]"
260+                    [evtRead `so` "evtRead",
261+                     evtWrite `so` "evtWrite",
262+                     evtClose `so` "evtClose"]) ++ "]"
263         where ev `so` disp | e `eventIs` ev = disp
264                            | otherwise      = ""
265 
266hunk ./System/Event/Manager.hs 29
267     , registerFd
268     , unregisterFd_
269     , unregisterFd
270-    , fdWasClosed
271+    , closeFd
272 
273       -- * Registering interest in timeout events
274     , TimeoutCallback
275hunk ./System/Event/Manager.hs 51
276 import Data.IORef (IORef, atomicModifyIORef, mkWeakIORef, newIORef, readIORef,
277                    writeIORef)
278 import Data.Maybe (Maybe(..))
279-import Data.Monoid (mconcat, mempty)
280+import Data.Monoid (mappend, mconcat, mempty)
281 import GHC.Base
282 import GHC.Conc.Signal (runHandlers)
283 import GHC.List (filter)
284hunk ./System/Event/Manager.hs 60
285 import GHC.Show (Show(..))
286 import System.Event.Clock (getCurrentTime)
287 import System.Event.Control
288-import System.Event.Internal (Backend, Event, evtRead, evtWrite, Timeout(..))
289+import System.Event.Internal (Backend, Event, evtClose, evtRead, evtWrite,
290+                              Timeout(..))
291 import System.Event.Unique (Unique, UniqueSource, newSource, newUnique)
292 import System.Posix.Types (Fd)
293 
294hunk ./System/Event/Manager.hs 335
295   wake <- unregisterFd_ mgr reg
296   when wake $ wakeManager mgr
297 
298--- | Notify the event manager that a file descriptor has been closed.
299-fdWasClosed :: EventManager -> Fd -> IO ()
300-fdWasClosed mgr fd =
301-  modifyMVar_ (emFds mgr) $ \oldMap ->
302+-- | Close a file descriptor in a race-safe way.
303+closeFd :: EventManager -> (Fd -> IO ()) -> Fd -> IO ()
304+closeFd mgr close fd = do
305+  fds <- modifyMVar (emFds mgr) $ \oldMap -> do
306+    close fd
307     case IM.delete (fromIntegral fd) oldMap of
308hunk ./System/Event/Manager.hs 341
309-      (Nothing,  _)       -> return oldMap
310+      (Nothing,  _)       -> return (oldMap, [])
311       (Just fds, !newMap) -> do
312         when (eventsOf fds /= mempty) $ wakeManager mgr
313hunk ./System/Event/Manager.hs 344
314-        return newMap
315+        return (newMap, fds)
316+  forM_ fds $ \(FdData reg ev cb) -> cb reg (ev `mappend` evtClose)
317 
318 ------------------------------------------------------------------------
319 -- Registering interest in timeout events
320hunk ./System/Event/Thread.hs 8
321       ensureIOManagerIsRunning
322     , threadWaitRead
323     , threadWaitWrite
324+    , closeFd
325     , threadDelay
326     , registerDelay
327     ) where
328hunk ./System/Event/Thread.hs 15
329 
330 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
331 import Data.Maybe (Maybe(..))
332+import Foreign.C.Error (eBADF, errnoToIOError)
333 import Foreign.Ptr (Ptr)
334 import GHC.Base
335 import GHC.Conc.Sync (TVar, ThreadId, ThreadStatus(..), atomically, forkIO,
336hunk ./System/Event/Thread.hs 21
337                       labelThread, modifyMVar_, newTVar, sharedCAF,
338                       threadStatus, writeTVar)
339+import GHC.IO.Exception (ioError)
340 import GHC.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar)
341hunk ./System/Event/Thread.hs 23
342+import GHC.Real (fromIntegral)
343+import System.Event.Internal (eventIs, evtClose)
344 import System.Event.Manager (Event, EventManager, evtRead, evtWrite, loop,
345                              new, registerFd, unregisterFd_, registerTimeout)
346hunk ./System/Event/Thread.hs 27
347+import qualified System.Event.Manager as M
348 import System.IO.Unsafe (unsafePerformIO)
349 import System.Posix.Types (Fd)
350 
351hunk ./System/Event/Thread.hs 56
352 
353 -- | Block the current thread until data is available to read from the
354 -- given file descriptor.
355+--
356+-- This will throw an 'IOError' if the file descriptor was closed
357+-- while this thread is blocked.
358 threadWaitRead :: Fd -> IO ()
359 threadWaitRead = threadWait evtRead
360 {-# INLINE threadWaitRead #-}
361hunk ./System/Event/Thread.hs 65
362 
363 -- | Block the current thread until the given file descriptor can
364 -- accept data to write.
365+--
366+-- This will throw an 'IOError' if the file descriptor was closed
367+-- while this thread is blocked.
368 threadWaitWrite :: Fd -> IO ()
369 threadWaitWrite = threadWait evtWrite
370 {-# INLINE threadWaitWrite #-}
371hunk ./System/Event/Thread.hs 72
372 
373+-- | Close a file descriptor in a concurrency-safe way.
374+--
375+-- Any threads that are blocked on the file descriptor via
376+-- 'threadWaitRead' or 'threadWaitWrite' will be unblocked by having
377+-- IO exceptions thrown.
378+closeFd :: (Fd -> IO ())        -- ^ Action that performs the close.
379+        -> Fd                   -- ^ File descriptor to close.
380+        -> IO ()
381+closeFd close fd = do
382+  Just mgr <- readIORef eventManager
383+  M.closeFd mgr close fd
384+
385 threadWait :: Event -> Fd -> IO ()
386 threadWait evt fd = do
387   m <- newEmptyMVar
388hunk ./System/Event/Thread.hs 88
389   Just mgr <- readIORef eventManager
390-  _ <- registerFd mgr (\reg _ -> unregisterFd_ mgr reg >> putMVar m ()) fd evt
391-  takeMVar m
392+  _ <- registerFd mgr (\reg e -> unregisterFd_ mgr reg >> putMVar m e) fd evt
393+  evt' <- takeMVar m
394+  if evt' `eventIs` evtClose
395+    then ioError $ errnoToIOError "threadWait" eBADF Nothing Nothing
396+    else return ()
397 
398 foreign import ccall unsafe "getOrSetSystemEventThreadEventManagerStore"
399     getOrSetSystemEventThreadEventManagerStore :: Ptr a -> IO (Ptr a)
400}
401[Drop System.Mem.Weak's dependency on Prelude
402Bryan O'Sullivan <bos@serpentine.com>**20101127060425
403 Ignore-this: e33216175ae42fe438d8be153cef0fd9
404] {
405hunk ./System/Mem/Weak.hs 70
406        -- $precise
407    ) where
408 
409-import Prelude
410+import Data.Maybe (Maybe(..))
411 
412 #ifdef __HUGS__
413 import Hugs.Weak
414hunk ./System/Mem/Weak.hs 74
415+import Prelude
416 #endif
417 
418 #ifdef __GLASGOW_HASKELL__
419hunk ./System/Mem/Weak.hs 78
420+import GHC.Base (return)
421+import GHC.Types (IO)
422 import GHC.Weak
423 #endif
424 
425}
426[Fix #4533 - unregister callbacks on exception, fixing a memory leak
427Bryan O'Sullivan <bos@serpentine.com>**20101127181826
428 Ignore-this: c37da82a058637c285a2b2fee4eee217
429 
430 Our problem here was that if a thread blocked in threadWait or
431 threadDelay and was killed by an exception thrown from another thread,
432 its registration with the IO manager would not be cleared.
433 
434 The fix is simply to install exception handlers that do the cleanup and
435 propagate the exception.
436 
437] {
438hunk ./System/Event/Thread.hs 13
439     , registerDelay
440     ) where
441 
442+import Control.Exception (SomeException, catch, throw)
443 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
444 import Data.Maybe (Maybe(..))
445 import Foreign.C.Error (eBADF, errnoToIOError)
446hunk ./System/Event/Thread.hs 42
447 threadDelay usecs = do
448   Just mgr <- readIORef eventManager
449   m <- newEmptyMVar
450-  _ <- registerTimeout mgr usecs (putMVar m ())
451-  takeMVar m
452+  reg <- registerTimeout mgr usecs (putMVar m ())
453+  takeMVar m `catch` \(e::SomeException) ->
454+    M.unregisterTimeout mgr reg >> throw e
455 
456 -- | Set the value of returned TVar to True after a given number of
457 -- microseconds. The caveats associated with threadDelay also apply.
458hunk ./System/Event/Thread.hs 90
459 threadWait evt fd = do
460   m <- newEmptyMVar
461   Just mgr <- readIORef eventManager
462-  _ <- registerFd mgr (\reg e -> unregisterFd_ mgr reg >> putMVar m e) fd evt
463-  evt' <- takeMVar m
464+  reg <- registerFd mgr (\reg e -> unregisterFd_ mgr reg >> putMVar m e) fd evt
465+  evt' <- takeMVar m `catch` \(e::SomeException) ->
466+            unregisterFd_ mgr reg >> throw e
467   if evt' `eventIs` evtClose
468     then ioError $ errnoToIOError "threadWait" eBADF Nothing Nothing
469     else return ()
470}
471
472Context:
473
474[use LANGUAGE instead of OPTIONS_GHC
475Simon Marlow <marlowsd@gmail.com>**20101124162530
476 Ignore-this: b72019eeeb706f366706578a45b22d46
477]
478[The 7.0 branch doesn't know about -fno-warn-identities
479Ian Lynagh <igloo@earth.li>**20101125143652]
480[Fixing uses of fromIntegral for Windows
481dimitris@microsoft.com**20101117183351]
482[Encode immediately in hPutStr and hPutChar
483Simon Marlow <marlowsd@gmail.com>**20101125102520
484 Ignore-this: 1503393cde63dd99a1e8c9d716bcbe10
485 This means that decoding errors will be detected accurately, and can
486 be caught and handled.  Overall the implementation is simpler this way
487 too.
488 
489 It does impose a performance hit on small hPutStrs, although larger
490 hPutStrs seem to be unaffected.  To compensate somewhat, I optimised
491 hPutStrLn.
492]
493[Remove unnecessary fromIntegral calls
494simonpj@microsoft.com**20101116172451
495 Ignore-this: 8c44dc2b381c050d4eaaf287bbc55b9
496]
497[fix hTell behaviour with Unicode Handles
498Simon Marlow <marlowsd@gmail.com>**20101125121831
499 Ignore-this: bb6fefd609a30c106e877783e0f9e0a4
500]
501[Don't throw an error if the output buffer had no room
502Simon Marlow <marlowsd@gmail.com>**20101124164221
503 Ignore-this: 45023b77b7d107daae552d36701a225a
504 This is consistent with the other codecs, and will be relied on by
505 some upcoming changes in the IO library.
506]
507[doc fix: don't refer to unblock.
508Simon Marlow <marlowsd@gmail.com>**20101108133212
509 Ignore-this: 52da909a3d262dda2c5f8e616da8ace3
510]
511[TAG base 4.3.0.0 release
512Ian Lynagh <igloo@earth.li>**20101117140835]
513Patch bundle hash:
514d88c3036c9aa2a122852ea940d368079363add4a