[Haskell-cafe] Faster timeout but is it correct?

Bas van Dijk v.dijk.bas at gmail.com
Wed Feb 23 12:39:47 CET 2011


On 23 February 2011 10:59, Bertram Felgenhauer
<bertram.felgenhauer at googlemail.com> wrote:
>> > 1. registerTimeout
>> > 2. (fmap Just f) raises an exception, or the thread gets killed otherwise.
>> > 3. We enter the `catch` handler, with the corresponding exception.
>> > 4. The timeout expires, and the event Manager runs the IO action, i.e.
>> >   throwTo myTid $ Timeout key
>> > 5. And now we have a pending Timeout exception which escapes the 'timeout'.
>> >   The unregTimeout will come too late.
>>
>> Bummer! You're right.
>>
>> But maybe we can catch and ignore a potential pending Timeout
>> exception: (code not tested and profiled yet)
>
> The trouble is that the throwTo action, even though we can no longer stop
> it using unregisterTimeout, may be delayed arbitrarily. So we'd have to
> wait for it to arrive. In that regard we have actually lost power compared
> to spawning a separate thread: throwTo (and thus killThread) explicitely
> guarantees that if two threads throw exceptions at one another
> simultaneously, only one of those will arrive, and also that if throwTo
> returns, the exception has actually been delivered. So if the killThread
> succeeds, the Timeout exception will never arrive.

Unfortunately you're correct. One last attempt at solving this is to
interrupt the throwTo action by throwing an exception to the thread
that is executing the event handling loop:

... -> do unregTimeout
          throwTo emTid InterruptTimeout
          throwIO e

where emTid is the ThreadId of the thread that is executing the event
handling loop and InterruptTimeout is some custom exception. The event
handling loop then has to ignore this exception when executing timeout
callbacks:

forM_ expired $ \(Q.E key _ cb) -> cb (TK key)
                                     `catch` \InterruptTimeout ->
                                         return ()

Of course the problem with this approach is that the InterruptTimeout
will "crash" the event handling loop when it's thrown outside the
scope of the above catch. It seems impossible to protect against that.

Since this event manager based implementation is broken and since my
earlier implementation was not actually faster on the more
representative busyWontTimeout benchmark, I conclude that I can't
improve on the current timeout. So I'm closing the ticket.

>> Actually the event manager based implementation totally crashes on
>> your example, so again: bummer! I get the following error:
>>
>> "gotcha: user error (Pattern match failure in do expression at
>> libraries/base/System/Event/Thread.hs:208:9-16)!"
>>
>> Line 208:
>>
>> Just mgr <- readIORef eventManager
>
> Yikes! I don't believe that's supposed to happen, but I have no clue
> how the event manager is initially started - does the RTS invoke
> ensureIOManagerIsRunning  before running  main?

It would be good to investigate the other uses of:

Just mgr <- readIORef eventManager

in System.Event.Thread to see if they have the same problem.

Thanks,

Bas



More information about the Libraries mailing list