[Haskell-cafe] interrupting an accept()ing thread
Lukas Mai
l.mai at web.de
Sat Jul 7 08:47:44 EDT 2007
Am Freitag, 6. Juli 2007 01:24 schrieb Lukas Mai:
> Hello, cafe!
>
> I have the following code (paraphrased):
>
> ...
> forkIO spin
> ...
> spin = do
> (t, _) <- accept s -- (*)
> forkIO $ dealWith t -- (**)
> spin
>
> My problem is that I want to stop spin from another thread. The "obvious"
> solution would be to throw it an exception. However, that leaks a socket
> (t) if the exception arrives between (*) and (**). I could wrap the whole
> thing in block, but from looking at the source of Network.Socket it seems
> that accept itself is not exception safe; so no matter what I do, I can't
> use asynchronous exceptions to make spin exit.
>
> (Is this actually true? Should accept be fixed (along with a lot of other
> library functions)?)
Answering myself: I now think that the above isn't true. :-)
Quoting Control.Exception:
> Some operations are interruptible, which means that they can receive
> asynchronous exceptions even in the scope of a block. Any function which
> may itself block is defined as interruptible; this includes takeMVar (but
> not tryTakeMVar), and most operations which perform some I/O with the
> outside world. The reason for having interruptible operations is so that we
> can write things like
>
> block (
> a <- takeMVar m
> catch (unblock (...))
> (\e -> ...)
> )
>
> if the takeMVar was not interruptible, then this particular combination
> could lead to deadlock, because the thread itself would be blocked in a
> state where it can't receive any asynchronous exceptions. With takeMVar
> interruptible, however, we can be safe in the knowledge that the thread can
> receive exceptions right up until the point when the takeMVar succeeds.
> Similar arguments apply for other interruptible operations like openFile.
If I understand this correctly, spin should be written as:
spin = do
block $ do
(t, _) <- accept s
unblock (forkIO $ doStuff t) `finally` sClose t
spin
Now t can't leak from spin because it's protected by block, while
the underlying accept() syscall is still interruptible by
asynchronous exceptions.
Lukas
More information about the Haskell-Cafe
mailing list