The Thread interface

INTERFACE Thread;

TYPE
  T <: ROOT;
  Mutex = MUTEX;
  Condition <: ROOT;

A Thread.T is a handle on a thread. A Mutex is locked by some thread, or unlocked. A Condition is a set of waiting threads. A newly-allocated Mutex is unlocked; a newly-allocated Condition is empty. It is a checked runtime error to pass the NIL Mutex, Condition, or T to any procedure in this interface.

TYPE Closure = OBJECT METHODS apply(): REFANY END;

PROCEDURE Fork(cl: Closure): T;

Return a handle on a newly-created thread executing cl.apply().

PROCEDURE Join(t: T): REFANY;

Wait until t has terminated and return its result. It is a checked runtime error to call this more than once for any t.

PROCEDURE Wait(m: Mutex; c: Condition);

The calling thread must have m locked. Atomically unlocks m and waits on c. Then relocks m and returns.

PROCEDURE Acquire(m: Mutex);

Wait until m is unlocked and then lock it.

PROCEDURE Release(m: Mutex);

The calling thread must have m locked. Unlocks m.

PROCEDURE Broadcast(c: Condition);

All threads waiting on c become eligible to run.

PROCEDURE Signal(c: Condition);

One or more threads waiting on c become eligible to run.

PROCEDURE Pause(n: LONGREAL);

Wait for n seconds to elapse.

To wait until a specified point in time in the future, say t, you can use the call

 Pause(t - Time.Now())

PROCEDURE Self(): T;

Return the handle of the calling thread.

EXCEPTION Alerted;

Used to approximate asynchronous interrupts.

PROCEDURE Alert(t: T);

Mark t as an alerted thread.

PROCEDURE TestAlert(): BOOLEAN;

If the calling thread has been marked alerted, return TRUE and unmark it.

PROCEDURE AlertWait(m: Mutex; c: Condition) RAISES {Alerted};

Like Wait, but if the thread is marked alerted at the time of call or sometime during the wait, lock m and raise Alerted.

PROCEDURE AlertJoin(t: T): REFANY RAISES {Alerted};

Like Join, but if the thread is marked alerted at the time of call or sometime during the wait, raise Alerted.

PROCEDURE AlertPause(n: LONGREAL) RAISES {Alerted};

Like Pause, but if the thread is marked alerted at the time of the call or sometime during the wait, raise Alerted.

Specifying thread stack size.

Normally Fork uses a default value for the size of the stack of the new thread. It is possible to change the default value, and also to specify the value used for a particular call to Fork by supplying a SizedClosure rather than a Closure. Stack sizes are given as a number of Word.Ts.

PROCEDURE GetDefaultStackSize(): CARDINAL;

Return the current default stack size for new threads.

PROCEDURE MinDefaultStackSize(min: CARDINAL); 

Change the default stack size for newly forked threads to the greater of min and the current default stack size.

PROCEDURE IncDefaultStackSize(inc: CARDINAL);

Increment the default stack size for newly forked threads by inc.

TYPE
  SizedClosure = Closure OBJECT stackSize: CARDINAL := 0 END;

<*PRAGMA SPEC*>

<* SPEC FUNC MaxLL(m: MUTEX): BOOLEAN *>
<* SPEC AXIOM (ALL [m1, m2: MUTEX]
                   (NOT MaxLL(m1) AND MaxLL(m2) AND m1 # NIL AND m2 # NIL)
                   IMPLIES m1 < m2) *>

Any mutex in MaxLL is greater than every mutex not in MaxLL.

<* SPEC Acquire(m) MODIFIES LL
                   REQUIRES sup(LL) < m
                   ENSURES LL' = INSERT(LL, m) *>

<* SPEC Release(m) MODIFIES LL
                   REQUIRES MEMBER(m, LL)
                   ENSURES LL' = DELETE(LL, m) *>

END Thread.