time-manager-0.5.2: Scalable timer
Safe HaskellNone
LanguageHaskell2010

System.ThreadManager

Description

A thread manager. The manager has responsibility to kill managed threads.

Because this is based on the accompanying System.TimeManager module, the same caveats apply:

  • Only works for GHC.
  • Only works with a threaded runtime.
  • Users of older versions should check the current semantics.
  • Using 32-bit systems means the max timeout is maxBound :: Int (2147483647) microseconds, which is less than 36 minutes.
  • Using the same Handle in different threads might cause issues in some edge cases. (i.e. using cancel/pause in one thread, and resume in another)
Synopsis

Documentation

data ThreadManager Source #

Manager to own threads.

newThreadManager :: IO ThreadManager Source #

Create a thread manager.

A manager owns threads; it does not time them out. A caller which wants both passes its own Manager to forkManagedTimeout.

stopAfter :: ThreadManager -> IO a -> (Maybe SomeException -> IO ()) -> IO a Source #

Stopping the manager.

stopAfter threadManager action cleanup

The action is run in the scope of an exception handler that catches all exceptions (including asynchronous ones); this allows the cleanup handler to cleanup in all circumstances. If an exception is caught, it is rethrown after the cleanup is complete.

This tells the managed threads to stop; it does not wait for them to be gone, and neither does the cleanup handler. They are the manager's until they end, so countManaged goes on counting them -- which is what a caller waits on with waitUntilAllGone before it frees what those threads were using.

A thread whose place is still being kept by reserveManaged is not told but refused when it arrives, and never runs.

A thread which swallows the exception and never ends is therefore counted for ever, and waitUntilAllGone on such a manager never returns. Nothing here can make it end; a caller which cannot rule that out should put its own timeout around the wait.

stopAfterWithResult :: ThreadManager -> IO a -> (Either SomeException a -> IO b) -> IO b Source #

Generalization of stopAfter where the cleanup handler is allowed to construct the final result

Unlike in stopAfter, if an exception is thrown, it is not re-thrown after the cleanup handler completes; the cleanup handler itself can decide to rethrow it or compute a result.

Since: 0.3.2

Fork

data Reservation Source #

A place kept for a thread that is not running yet.

Registering a thread needs its ThreadId, and it is the thread itself which provides it, by asking for its own. A caller which forks through a function that hands no identity back cannot do it on the thread's behalf, so until the thread arrives and registers itself, what is counted is the place kept for it.

reserveManaged :: ThreadManager -> IO Reservation Source #

Keeping a place for a thread about to be forked. It counts towards countManaged from here, so that a manager stopped in between does not see a connection that has been accepted as one that is gone. A place that is never taken is never given back, so a caller which reserves and then fails to fork leaves the manager counting it.

takeReservation :: ThreadManager -> Reservation -> IO () -> IO () Source #

Running the action of a thread which was reserved for, taking the place kept for it: the thread records itself, so that stopAfter can reach it, and gives the reservation back.

The reservation is given back only once the thread is recorded, so that it is counted throughout. A thread which gets here after stopAfter has stopped the manager is killed rather than registered.

The reservation must be one kept by this manager. Taking one kept by another lowers this manager's count instead of that one's: the other manager never reaches zero, and once this count goes negative, countManaged, isAllGone and waitUntilAllGone throw AssertionFailed.

forkManaged Source #

Arguments

:: ThreadManager 
-> String

Thread name

-> IO ()

Action

-> IO () 

Fork a managed thread.

A place is kept for the thread before it is forked, so that it counts towards countManaged from this call rather than from the moment the run-time system gives the thread its first step. The thread adds itself to the manager's queue as the first thing it does, takes the place over, and is removed again when it terminates (normally or abnormally).

forkManagedFinally Source #

Arguments

:: ThreadManager 
-> String

Thread name

-> IO ()

Action

-> IO ()

Cleanup function

-> IO () 

Like forkManaged, but with a cleanup function, run regardless of how the action ends. An exception from the action is not caught: it ends the thread as it would under forkManaged.

forkManagedUnmask Source #

Arguments

:: ThreadManager 
-> String

Thread name

-> ((forall x. IO x -> IO x) -> IO ())

Action with unmask argument

-> IO () 

Like forkManaged, but run the action with exceptions masked until the provided unmask is used. (i.e. (forall x. IO x -> IO x))

forkManagedUnmaskFinally Source #

Arguments

:: ThreadManager 
-> String

Thread name

-> ((forall x. IO x -> IO x) -> IO ())

Action with unmask argument

-> IO ()

Cleanup: will always run, regardless of how the thread ends

-> IO () 

Like forkManagedUnmask, but with a cleanup function, run regardless of how the action ends. An exception from the action is not caught: it ends the thread as it would under forkManagedUnmask.

forkManagedBy Source #

Arguments

:: ThreadManager 
-> (((forall x. IO x -> IO x) -> IO ()) -> IO a)

The fork to make the thread with

-> String

Thread name

-> ((forall x. IO x -> IO x) -> IO ())

Action with unmask argument

-> IO a 

Fork a managed thread with a fork of the caller's own, for a caller which does not fork with forkIO. (The warp library, for example, forks the thread serving a connection through a function of its settings, so that the user can replace it.)

A place is kept for the thread before the fork, so that it counts towards countManaged from here rather than from the moment the thread starts, and the place is given back whether the fork makes the thread or throws. A caller which forks by itself can do the same with reserveManaged and takeReservation, which this is made of.

forkManagedByFinally Source #

Arguments

:: ThreadManager 
-> (((forall x. IO x -> IO x) -> IO ()) -> IO a)

The fork to make the thread with

-> String

Thread name

-> ((forall x. IO x -> IO x) -> IO ())

Action with unmask argument

-> IO ()

Cleanup: will always run, regardless of how the thread ends

-> IO a 

Like forkManagedBy, but with a cleanup function.

forkManagedTimeout Source #

Arguments

:: ThreadManager 
-> Manager

Time manager

-> String

Thread name

-> (Handle -> IO ())

Action with timeout handle

-> IO () 

Fork a managed thread with a handle created by a timeout manager.

The time manager is the caller's, since this manager has none: owning a thread and timing it out are separate things, and only this pair of functions needs both. What needs them together is the lock that keeps the timeout and stopAfter from both throwing at the thread.

forkManagedTimeoutFinally Source #

Arguments

:: ThreadManager 
-> Manager

Time manager

-> String

Thread name

-> (Handle -> IO ())

Action with timeout handle

-> IO ()

Cleanup: will always run, regardless of how the thread ends

-> IO () 

Like forkManagedTimeout, but with a cleanup function, run regardless of how the action ends. An exception from the action is not caught: it ends the thread as it would under forkManagedTimeout.

Synchronization

waitUntilAllGone :: ThreadManager -> IO () Source #

Wait until all managed threads are finished.

After stopAfter this waits for the threads it stopped to end, not merely for them to have been told. See there for the thread that never ends.

A place kept by reserveManaged and never taken is never given back, so this never returns for a caller which reserves and then fails to fork.

isAllGone :: ThreadManager -> STM Bool Source #

STM action that checks if all managed threads are finished.

countManaged :: ThreadManager -> STM Int Source #

STM action for how many threads are managed, counting the places kept by reserveManaged for threads which have not started, and the threads stopAfter has stopped which have not ended yet.

Throws AssertionFailed if the count of places has gone negative, which happens when a reservation is taken by a manager other than the one that kept it. A mistake of that kind which does not drive the count negative goes unnoticed.