-*- Mode: Modula-3 -*-
*
* For information about this program, contact Blair MacIntyre
* (bm@cs.columbia.edu) or Steven Feiner (feiner@cs.columbia.edu)
* at the Computer Science Dept., Columbia University,
* 1214 Amsterdam Ave. Mailstop 0401, New York, NY, 10027.
*
* Copyright (C) 1995, 1996 by The Trustees of Columbia University in the
* City of New York. Blair MacIntyre, Computer Science Department.
* See file COPYRIGHT-COLUMBIA for details.
*
* Author : Blair MacIntyre
* Created On : Thu May 11 11:11:52 1995
* Last Modified By: Blair MacIntyre
* Last Modified On: Tue Dec 3 11:37:24 1996
* Update Count : 38
*
* $Source: /usr/cvs/cm3/m3-comm/events/src/EventCounter.i3,v $
* $Date: 2001-12-02 00:20:37 $
* $Author: wagner $
* $Revision: 1.2 $
*
* $Log: EventCounter.i3,v $
* Revision 1.2 2001-12-02 00:20:37 wagner
* add copyright notes, fix overrides for cm3, and make everything compile
*
* added: events/COPYRIGHT-COLUMBIA
* added: events/src/COPYRIGHT-COLUMBIA
* modified: events/src/Event.i3
* modified: events/src/Event.m3
* modified: events/src/EventConn.i3
* modified: events/src/EventConn.m3
* modified: events/src/EventCounter.i3
* modified: events/src/EventCounter.m3
* modified: events/src/EventHandle.i3
* modified: events/src/EventIO.i3
* modified: events/src/EventNumber.i3
* modified: events/src/EventNumber.m3
* modified: events/src/EventNumberF.i3
* modified: events/src/EventPort.i3
* modified: events/src/EventPort.m3
* modified: events/src/EventProtocol.i3
* modified: events/src/EventRd.i3
* modified: events/src/EventRd.m3
* modified: events/src/EventSpaceID.i3
* modified: events/src/EventSpaceID.m3
* modified: events/src/EventStubLib.i3
* modified: events/src/EventStubLib.m3
* modified: events/src/EventWireRep.i3
* modified: events/src/EventWireRep.m3
* modified: events/src/EventWr.i3
* modified: events/src/EventWr.m3
* modified: events/src/EventWrF.i3
* modified: events/src/HostInfo.i3
* modified: events/src/HostInfo.m3
* modified: events/src/RdWrMutex.i3
* modified: events/src/RdWrMutex.m3
* modified: events/src/Work.i3
* modified: events/src/WorkerPool.i3
* modified: events/src/WorkerPool.m3
* modified: events/src/Zombie.i3
* modified: events/src/m3makefile
* modified: events/src/m3overrides
*
* Revision 1.1.1.1 2001/12/02 00:06:45 wagner
* Blair MacIntyre's events library
*
* Revision 1.2 1997/01/23 15:26:34 bm
* Lots of little bug fixes.
*
*
* HISTORY
* Idea taking from a C version of similar idea in MUTS, written by
* Robbert van Renesse, Brad Glade, Cornell University
*
* This module implements event counters.
* Event counters are like MUTEXs, but can only be grabbed in a certain
* order. Furthermore, other threads are allowed to wait for a certain
* event values to be reached without incrementing the counter.
* Finally, instead of blocking, a thread can leave an event
* associated with an event value on the internal queue, which can be
* processed .
*
* The lock associated with an EventCount is a RdWrMutex, and is
* passed in via the init()
method.
*
* The intended use for event counters is to syncronize threads that are
* handling numbered events that may arrive out of order.
* The wait() method allows additional threads to wait until after a
* certain numbered event has finished. These wait()
ing threads
* will run after the event value has been reached and
* do not lock the counter. This implies two things:
* - the scheduler may end up running these threads at some arbitrary
* time, so a thread that waits for the event counter to reach value N
* should not depend on it being N when it is run.
* - these threads should not call release(), since they haven't
* acquired()d the lock.
*
* The init()
method should be called to initialize a new event
* counter. By default, the counter is initialized to zero.
* The acquire(value: EventNumber.T)
method is like Thread.Acquire(), but
* blocks until the mutex is free and the event counter reaches the
* given value. If multiple attempts are made to acquire the same
* value, all but one will raise the Duplicate
exception when the counter
* reaches the given value (duplicates will not be checked until that
* point). It is undefined which one will acquire the lock, and which
* will receive an exception. tryAcquire()
is similar to acquire,
* but will not block. If the lock cannot be acquired immediately, it
* will return FALSE. Otherwise the lock is acquired and
* tryAcquire()
returns TRUE.
*
* enqueueAction(value: EventNumber.T; handler: Handler)
adds an
* action to the EventCount queue that will be exectuted with the
* counter reaches value.
An enqueued action is semantically
* similar to a thread acquiring the lock, executing the
* action itself when the acquire succeeds, and then releasing the
* lock. However, the action will be executed by the thread that
* releases the lock when it is at value-1.
If the enqueued action
* can be executed (no other thread or action has acquired the lock at
* the requested value), handler.handle()
will be called to execute
* the action. If the action cannot be executed because a duplicate
* value has already been acquired, handler.duplicate()
will be called.
*
* The release()
method is similar to Thread.Release(), but
* increments the event counter in addition to releasing the lock.
* The wait(value: Integer.T)
method causes the threads to
* wait until the event counter is release()
d by the thread that
* acquire()d it with the same value, incrementing the counter past the
* value.
*
* If the event number overflows its maximum value, release()
raises
* Overflow
.
*
* The set(value: EventNumber.T)
is similar to acquire except that
* it sets the value of the counter to value. However, set can never
* lower the value of the counter, and an Invalid
exception will be
* raised if this is attempted. A call to set()
will lock the
* counter and then change it. If a set of clients are already
* waiting to acquire()
the next N
values of the counter, some M
* of them, M <= N
, may acquire the counter before set()
. Once
* set()
acquires the counter, it is set to the new value and all
* clients that were blocked attempting to acquire some value less
* than this new value are unblocked with a Duplicate
exception. All
* clients that were blocked waiting for some value less than this new
* value are unblocked.
INTERFACE EventCounter;
IMPORT RdWrMutex, EventNumber;
EXCEPTION Duplicate;
EXCEPTION Overflow;
EXCEPTION Invalid;
TYPE
Handler = OBJECT METHODS
handle() := DefaultHandlerHandle;
duplicate() := DefaultHandlerDuplicate;
END;
T <: Public;
Public = OBJECT METHODS
init(mu: RdWrMutex.T; value: EventNumber.T := NIL): T;
acquire(value: EventNumber.T) RAISES {Duplicate};
tryAcquire(value: EventNumber.T): BOOLEAN RAISES {Duplicate};
enqueueAction(value: EventNumber.T; handler: Handler) RAISES {Duplicate};
wait(value: EventNumber.T);
release();
value(): EventNumber.T;
set(value: EventNumber.T) RAISES {Invalid};
END;
PROCEDURE New(mu: RdWrMutex.T; t: EventNumber.T := NIL): T;
(* Same as "NEW(T).init(t)" *)
PROCEDURE DefaultHandlerHandle(self: Handler);
PROCEDURE DefaultHandlerDuplicate(self: Handler);
(* These routines return immediately. *)
PROCEDURE ToText(self: T): TEXT;
(* For debugging, return a textual representation of the
EventCounter state. *)
END EventCounter.