Commits

Bryan O'Sullivan committed 8bf9b07

Use an MVar for debug logging to avoid multi-threaded interleaving.

Turns out that, because Handle goes out of its way to allow concurrent access,
if two threads are trying to log at the same time, their output is interleaved
at the character level, rendering it useless.

Using an MVar instead is a little crude, not to mention cruel to concurrency,
but at least it makes the output readable.

Comments (0)

Files changed (1)

src/Network/Riak/Debug.hs

     ) where
 
 import Control.Exception hiding (handle)
-import Data.IORef (IORef, newIORef, readIORef, writeIORef)
+import Control.Concurrent.MVar (MVar, modifyMVar_, newMVar, withMVar)
 import Network.Riak.Types.Internal
 import System.Environment (getEnv)
 import System.IO (Handle, hPutStrLn, stderr)
 #endif
 
 #ifdef DEBUG
-handle :: IORef Handle
-handle = unsafePerformIO $ newIORef stderr
+handle :: MVar Handle
+handle = unsafePerformIO $ newMVar stderr
 {-# NOINLINE handle #-}
 #endif
 
 -- | Set the 'Handle' to log to ('stderr' is the default).
 setHandle :: Handle -> IO ()
 #ifdef DEBUG
-setHandle = writeIORef handle
+setHandle = modifyMVar_ handle . const . return
 #else
 setHandle _ = return ()
 {-# INLINE setHandle #-}
 #ifdef DEBUG
 debug func str
     | level == 0 = return ()
-    | otherwise  = do
-  h <- readIORef handle
-  hPutStrLn h $ str ++ " [" ++ func ++ "]"
+    | otherwise  =
+  withMVar handle $ \h -> hPutStrLn h $ str ++ " [" ++ func ++ "]"
 #else
 debug _ _ = return ()
 {-# INLINE debug #-}