[Haskell-cafe] Timeout exceptions sometimes don't work, even in pure (non FFI) code
daniel.is.fischer at googlemail.com
Tue Feb 1 17:18:04 CET 2011
On Tuesday 01 February 2011 16:40:43, Job Vranish wrote:
> I'm trying to test some properties with quickcheck. If these tests fail,
> they will almost certainly fail by nontermination.
> I've been using the 'within' function to catch these nontermination
> cases. However, I was surprised to find that this doesn't always work.
> 'within' uses the 'timeout' function under the hood. Here is an example
> that demonstrates the problem:
> import System.Timeout
> import Control.Exception
> works :: Int -> Int
> works x = sum $ cycle [x]
> doesntWork :: Int -> Int
> doesntWork x = last $ cycle [x]
> test1 = timeout 1 $ evaluate $ works 5 == 5 -- terminates
> test2 = timeout 1 $ evaluate $ doesntWork 5 == 5 -- never terminates
> test1 returns Nothing as expected, but test2 never terminates. Why?
When compiled with optimisations, works doesn't terminate either.
I believe it's because works actually does some work and allocations
(without optimisations), while doesntWork is a non-allocating loop.
GHC only makes context switches on allocations, so with a non-allocating
loop, the timeout thread never gets to run to see whether the time limit is
Without optimisations, sum allocates thunks, with optimisations it becomes
a tight loop not hitting the heap. `last $ cycle [x]' becomes a tight loop
even without optimisations.
> I thought timeout exceptions are supposed to always work with pure (non
> FFI) Haskell code.
> Is there any way I can work around this?
Make sure your tests always allocate, or write them as IO stuff and call
yield (or threadDelay) within the loops to let GHC make some context
> I'm using ghc 6.12.2
> - Job
More information about the Haskell-Cafe