I am looking at hPutStr’ and I do not understand why buffer_mode
and nl
are returned from the wantWritableHandle
action. It seems strange to me that the case statement is not just in the action function. Is there any good reason for this, is it just the preference of the author to keep h_
out of scope with the case statement, or something else?
is it just the preference of the author to keep
h_
out of scope
I guess so. Bear in mind that this code was probably written years ago and hardly revisited since, so it’s not necessarily written in any coherent style.
It is definitely not just preference nor scope. hPutChar
, and commitBuffer
both call wantWritableHandle
and will deadlock if called within wantWritableHandle
in hPutStr'
.
Note that wantWritableHandle h act
ultimately calls withHandle'
to run its handler act
in a masked context:
withHandle' fun h m act =
mask_ $ do
(h',v) <- do_operation fun h act m
checkHandleInvariants h'
putMVar m h'
return v
mask_
makes that the block cannot be interrupted by asynchronous exceptions (perhaps thrown from another thread). Although it may be vital to perform cleanup work as part of the masked block, it is important to keep masked blocks as small as possible, in order to handle asynchronous exceptions as promptly as possible.
Hence it is good that the act
in hPutStr'
only does a single, fast thing: obtaining a spare buffer. It should not also write to the file handle, because that may block indefinitely, for example when there is no buffering and we are writing to a pipe. That would mean that killing your app with Ctrl+C would not work unless you read out all contents of the pipe first.
But there’s also a more specific reason it won’t work, right? That is, a Handle
is a Handle__
in an MVar
, and withHandle'
takes that MVar
and only returns it once its body has finished. Therefore you can’t nest calls to withHandle'
.
I am looking at issue bytstring: hPutStrLn is not atomic and am wondering if there is a way to use to use the fact that Handle is an MVar to allow multiple buffers to be flushed atomically?