I ran into this particular problem in @mvoidex's hsdev server while tracking down why hsdev would send incomplete responses. I was able to track the problem down to a reimplementation of sendAll:
sendAll :: Socket -> BS.ByteString -> IO ()
sendAll sock bs
| BS.null bs = return ()
| otherwise = do
sent <- Net.send sock bs
when (sent > 0) $ sendAll sock (BS.drop sent bs)
The subtle bug in this code is the send > 0: send can return 0 because the OS is waiting for a buffer to drain and the underlying descriptors are in non-blocking mode (GHC runtime "feature".)
One way around the send == 0 issue is to call Control.Concurrent.threadDelay. Optimally, you'd really want to call Control.Concurrent.threadWaitWrite, but you can't because converting the socket to a file descriptor is a one way process.
Is there a way to call threadWaitWrite without converting the socket to a descriptor?
I ran into this particular problem in @mvoidex's
hsdevserver while tracking down whyhsdevwould send incomplete responses. I was able to track the problem down to a reimplementation ofsendAll:The subtle bug in this code is the
send > 0:sendcan return 0 because the OS is waiting for a buffer to drain and the underlying descriptors are in non-blocking mode (GHC runtime "feature".)One way around the
send == 0issue is to callControl.Concurrent.threadDelay. Optimally, you'd really want to callControl.Concurrent.threadWaitWrite, but you can't because converting the socket to a file descriptor is a one way process.Is there a way to call
threadWaitWritewithout converting the socket to a descriptor?