WorkerThreads.mesa
Copyright Ó 1993 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, April 2, 1993
Christian Jacobi, April 13, 1993 11:39 am PDT
WorkerThreads: CEDAR DEFINITIONS = {
This package allows to use multi threading with reduced risk of allocating too many threads.
With the availability of multiprocessors we have a desire to use parallel processing to reduce latency. However, for many applications there is no given natural number of threads. If an unbounded number of threads is used too much scheduling or too much stack space may be required. This package helps such application in two non trivial tasks: limiting the number of threads, and, finding an appropriate limit.
The usual disclaimers hold:
Enqueued procedures must be global.
Priority is set once after forking but is never again touched or reset.
If all the available threads in a pool are blocked, no further progress will be made.
It is dangerous for a worker thread to wait for an event to be generated by another worker thread, as the pool might not have enough virtual threads left to guarantee the other worker beeing forked.
Only a fraction of all possible wedges are detected.
Design rationale for pool versus LIST OF Activity types:
Typical usage is to allocate a pool statically per client package, but, build a LIST OF Activity for each invocation of a client procedure.
Pool: TYPE = REF PoolRep;
Pool of virtual threads performing activities
PoolRep: PRIVATE TYPE;
IsPool: PROC [x: REF] RETURNS [BOOL];
NarrowPool: PROC [x: REF] RETURNS [Pool];
CreatePool: PROC [percentage: INT ¬ 4, initialPriority: CARD32 ¬ 2] RETURNS [Pool];
Creates a new pool of virtual threads.
percentage: the (approximate) percentage of threads to be allocated for this pool.
A relative number (instead of a count) is used, because clients might have no idea how many threads are reasonably or efficient in the particular operating system.
Activity: TYPE = REF ActivityRep;
ActivityRep: PRIVATE TYPE;
IsActivity: PROC [x: REF] RETURNS [BOOL];
NarrowActivity: PROC [x: REF] RETURNS [Activity];
Fork: PROC [pool: Pool, proc: PROC[REF], data: REF ¬ NIL, promiseToPerform: BOOL ¬ FALSE] RETURNS [Activity];
Depending on thread allocation, proc is forked, or, enqueued.
pool: to debit the thread. For pool=NIL a small shared pool is substituted. Restrict usage of the shared pool to applications which do not wedge or block for long.
data: is handed over to proc.
promiseToPerform: Optimization. If true, one fork might be suppressed. This reduces the thread count, but the caller must substitute for this thread by calling Perform.
ActivityState: TYPE = {queued, busy, finished, discarded, aborting, aborted};
Activites start in queued state; the following transitions may be seen by clients:
queued -> {busy, discarded, finished, aborting, aborted}
busy -> {finished, aborting, aborted}
aborting -> aborted
Once finished, discarded, aborted is reached the state does not change anymore.
State: PROC [activity: Activity] RETURNS [ActivityState];
Returns current state of activity. The state might change asynchronously but only valid transitions will occur.
Perform: PROC [activity: Activity];
If the activity has not not yet started, activate it.
If the activity would wedge, caller might wedge too.
Restriction: Aborting the caller process might abort activity instead.
Discard: PROC [activity: Activity];
If the activity has not yet started (state=queued), discard it.
Abort: PROC [activity: Activity];
If the activity has not yet started, discard it.
If the activity is busy, request abortion of handling process.
Wait: PROC [activities: LIST OF Activity, perform: BOOL ¬ TRUE];
Waits until activities are finished, discarded, aborting, or, aborted.
perform: like calling Perform first. perform is recommended, but optional because of its aborting restriction.
AvailableCnt: PROC [pool: Pool] RETURNS [INT];
Returns number of virtual threads available in pool (right now).
PeekActivity: PROC [pool: Pool] RETURNS [activity: Activity];
Returns first activity queued but not yet handled from the pool (or NIL if none available).
The state of the activity may have already changed until the caller gets to see it.
}.