| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
System.ThreadManager
Contents
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
(2147483647) microseconds, which is less than 36 minutes.maxBound:: Int - Using the same
Handlein different threads might cause issues in some edge cases. (i.e. using cancel/pause in one thread, and resume in another)
Synopsis
- data ThreadManager
- newThreadManager :: IO ThreadManager
- stopAfter :: ThreadManager -> IO a -> (Maybe SomeException -> IO ()) -> IO a
- stopAfterWithResult :: ThreadManager -> IO a -> (Either SomeException a -> IO b) -> IO b
- data KilledByThreadManager = KilledByThreadManager (Maybe SomeException)
- data Reservation
- reserveManaged :: ThreadManager -> IO Reservation
- takeReservation :: ThreadManager -> Reservation -> IO () -> IO ()
- forkManaged :: ThreadManager -> String -> IO () -> IO ()
- forkManagedFinally :: ThreadManager -> String -> IO () -> IO () -> IO ()
- forkManagedUnmask :: ThreadManager -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO ()
- forkManagedUnmaskFinally :: ThreadManager -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO () -> IO ()
- forkManagedBy :: ThreadManager -> (((forall x. IO x -> IO x) -> IO ()) -> IO a) -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO a
- forkManagedByFinally :: ThreadManager -> (((forall x. IO x -> IO x) -> IO ()) -> IO a) -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO () -> IO a
- forkManagedTimeout :: ThreadManager -> Manager -> String -> (Handle -> IO ()) -> IO ()
- forkManagedTimeoutFinally :: ThreadManager -> Manager -> String -> (Handle -> IO ()) -> IO () -> IO ()
- waitUntilAllGone :: ThreadManager -> IO ()
- isAllGone :: ThreadManager -> STM Bool
- countManaged :: ThreadManager -> STM Int
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 #
data KilledByThreadManager Source #
An exception used internally to kill a managed thread.
Constructors
| KilledByThreadManager (Maybe SomeException) |
Instances
| Exception KilledByThreadManager Source # | |
Defined in System.ThreadManager | |
| Show KilledByThreadManager Source # | |
Defined in System.ThreadManager Methods showsPrec :: Int -> KilledByThreadManager -> ShowS # show :: KilledByThreadManager -> String # showList :: [KilledByThreadManager] -> ShowS # | |
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.
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).
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.
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.
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.
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.
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.