Wrap an
IO computation to time out and return
Nothing
in case no result is available within
n microseconds
(
1/10^6 seconds). In case a result is available before the
timeout expires,
Just a is returned. A negative timeout
interval means "wait indefinitely". When specifying long timeouts, be
careful not to exceed
maxBound :: Int, which on 32-bit
machines is only 2147483647 μs, less than 36 minutes. Consider using
Control.Concurrent.Timeout.timeout from
unbounded-delays package.
>>> timeout 1000000 (threadDelay 1000 *> pure "finished on time")
Just "finished on time"
>>> timeout 10000 (threadDelay 100000 *> pure "finished on time")
Nothing
The design of this combinator was guided by the objective that
timeout n f should behave exactly the same as
f as
long as
f doesn't time out. This means that
f has
the same
myThreadId it would have without the timeout wrapper.
Any exceptions
f might throw cancel the timeout and propagate
further up. It also possible for
f to receive exceptions
thrown to it by another thread.
A tricky implementation detail is the question of how to abort an
IO computation. This combinator relies on asynchronous
exceptions internally (namely throwing the computation the
Timeout exception). The technique works very well for
computations executing inside of the Haskell runtime system, but it
doesn't work at all for non-Haskell code. Foreign function calls, for
example, cannot be timed out with this combinator simply because an
arbitrary C function cannot receive asynchronous exceptions. When
timeout is used to wrap an FFI call that blocks, no timeout
event can be delivered until the FFI call returns, which pretty much
negates the purpose of the combinator. In practice, however, this
limitation is less severe than it may sound. Standard I/O functions
like
hGetBuf,
hPutBuf, Network.Socket.accept, or
hWaitForInput appear to be blocking, but they really don't
because the runtime system uses scheduling mechanisms like
select(2) to perform asynchronous I/O, so it is possible to
interrupt standard socket I/O or file I/O using this combinator.