network-mux
Safe HaskellNone
LanguageHaskell2010

Network.Mux.Timeout

Description

An alternative implementation of timeout for platforms (i.e. Windows) where the standard implementation is too expensive.

The implementation provided here is for the special case where only one timeout is active at once. A concurrent implementation would be possible but is not currently needed.

Synopsis

Documentation

type TimeoutFn (m :: Type -> Type) = forall a. DiffTime -> m a -> m (Maybe a) Source #

The type of the timeout function.

withTimeoutSerial :: (MonadAsync m, MonadFork m, MonadMonotonicTime m, MonadTimer m, MonadMask m, MonadThrow (STM m)) => (TimeoutFn m -> m b) -> m b Source #

A timeout that is reasonably efficient for all platforms.

On Unix it uses exactly timeout and on Windows it uses withTimeoutSerialAlternative.

withTimeoutSerial $ \timeout ->
  -- now use timeout as one would use System.Timeout.timeout
  -- but not concurrently!

The implementation has a serial constraint: the body action that calls timeout can only do so from one thread at once.

withTimeoutSerialNative :: (MonadAsync m, MonadFork m, MonadMonotonicTime m, MonadTimer m, MonadMask m, MonadThrow (STM m)) => (TimeoutFn m -> m b) -> m b Source #

A timeout that is reasonably efficient for all platforms.

On Unix it uses exactly timeout and on Windows it uses withTimeoutSerialAlternative.

withTimeoutSerial $ \timeout ->
  -- now use timeout as one would use System.Timeout.timeout
  -- but not concurrently!

The implementation has a serial constraint: the body action that calls timeout can only do so from one thread at once.

This version simply passes the native platform's timeout.

withTimeoutSerialAlternative :: (MonadAsync m, MonadFork m, MonadMonotonicTime m, MonadTimer m, MonadMask m, MonadThrow (STM m)) => (TimeoutFn m -> m b) -> m b Source #

An alternative implementation of timeout for platforms where the standard implementation is too expensive.

withTimeoutSerial $ \timeout ->
  -- now use timeout as one would use System.Timeout.timeout
  -- but not concurrently!

This implementation has a serial constraint: the body action that calls timeout can only do so from one thread at once.

Further details for the curious:

the problem with System.Timeout.timeout is that (as of base 4.12) it has two implementations, one for Unix with the threaded RTS, and one for all other configurations.

The Unix threaded RTS implementation is rather clever and very fast. In the normal case of no timeout, it only has to allocate a timer entry. Only in the case the timeout occurs does it allocate a forkIO thread to do the potentially-blocking operation of sending the asynchronous exception to interrupt the action under timeout.

The implementation for all other configurations has to allocate a forkIO thread up front, whether or not the timeout fires. This is fine for many applications but not for network timers which have to be created and altered/cancelled with very high frequency.

The implementation here only relies upon threadDelay which has an efficient implementation on all platforms. It uses a separate monitoring thread which will throw an exception to terminate the action if the timeout expires. This is why it uses the "with" style: because it keeps a monitoring thread over a region of execution that may use many timeouts. The cost of allocating this thread is amortised over all the timeouts used.

This implementation is simplified by the constraint that the timeouts only be used serially. In addition, it has the limitation that timeouts may not always be detected promptly: e.g. a 10s timeout on an action that finishes immediately, followed by a 5s timeout on an action will only actually be interrupted after 10s. So it's possible that action with the 5s timeout runs for up to 10s. This is ok for many applications provided that the variance in timeouts is not too large and the timeouts don't need to be too tight.