
On 23 February 2011 10:59, Bertram Felgenhauer
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