jgoerzen/hslogger — Issue #4: lazy bug
Author: exFalso
Created: 2011-12-11 01:37:36+00:00
State: open

hslogger seems to deadlock when printing lazy bytestrings.

I am guessing this is because hslogger has a global lock which won't be released until the lazy string is fully evaluated. This will lead to a deadlock if another thread whose actions determine the evaluation of the string also tries to log.

Test case: (sorry i couldn't make up a smaller one)

(server.hs)
import System.Log.Logger
import System.IO
import Control.Concurrent
import Network
import Control.DeepSeq
import Control.Exception

import qualified Data.ByteString.Lazy as L

main = do
updateGlobalLogger "Main" (setLevel NOTICE)
socket <- listenOn (PortNumber 11111)

putStrLn "(SERVER) Waiting for client to connect"
(hndle, _, _) <- accept socket
hSetBuffering hndle NoBuffering
putStrLn "(SERVER) Client connected"

forkIO (thread hndle)

--toPrint <- evaluate . force . show =<< L.hGetContents hndle
toPrint <- return . show =<< L.hGetContents hndle

noticeM "Main" ("Deadlock! :) " ++ toPrint)
return ()

thread hndle = do
noticeM "Main" $ "Never to be seen"
hPutStrLn hndle "Some Message"

(client.hs)
import System.IO
import Network

import qualified Data.ByteString.Char8 as L

main = do
putStrLn "(CLIENT) Connecting..."
hndle <- connectTo "localhost" (PortNumber 11111)
hSetBuffering hndle NoBuffering
putStrLn "(CLIENT) Connected"
toEcho <- hGetLine hndle
putStrLn $ "(CLIENT) Echoing " ++ show toEcho ++ " back to server"
hFlush stdout
hPutStr hndle toEcho
putStrLn "(CLIENT) Message sent"

Compile, then run server.hs then client.hs - it will deadlock. Commenting/Uncommenting the "toPrint <-..." lines in server.hs will solve the issue.

A simple solution is to force evaluating the string before acquiring the global lock.