Oberon || Library || Module Index || Search Engine || Definition || Module


Ulm's Oberon Library:
Conditions


NAME

Conditions - general interface for wait conditions

SYNOPSIS

TYPE Domain = POINTER TO DomainRec;
TYPE DomainRec = RECORD (Disciplines.ObjectRec) END;
TYPE Condition = POINTER TO ConditionRec;
TYPE ConditionRec = RECORD (Disciplines.ObjectRec) END;
TYPE ConditionSet = POINTER TO ConditionSetRec;
TYPE ConditionSetRec = RECORD (Objects.ObjectRec) END;
CONST select = 0; timelimit = 1; async = 2; timecond = 3; preconditions = 4;
TYPE CapabilitySet = SET; (* OF [select..preconditions] *)
TYPE SelectProc = PROCEDURE (domain: Domain; conditionSet: ConditionSet;
                             time: Times.Time;
                             VAR setOfTrueConditions: ConditionSet;
                             errors: RelatedEvents.Object;
                             retry: BOOLEAN;
                             VAR interrupted: BOOLEAN) : BOOLEAN;
TYPE TestProc = PROCEDURE (domain: Domain; condition: Condition;
                           errors: RelatedEvents.Object) : BOOLEAN;
TYPE SendEventProc = PROCEDURE (domain: Domain; condition: Condition;
                                event: Events.Event;
                                errors: RelatedEvents.Object) : BOOLEAN;
TYPE GetTimeProc = PROCEDURE (domain: Domain; conditionSet: ConditionSet;
                              VAR nextTime: Times.Time;
                              VAR nextCond: Condition;
                              errors: RelatedEvents.Object);
TYPE PreConditionsProc = PROCEDURE (domain: Domain; condition: Condition;
                                    VAR preconds: ConditionSet;
                                    errors: RelatedEvents.Object) : BOOLEAN;
TYPE Interface = POINTER TO InterfaceRec;
TYPE InterfaceRec =
   RECORD
      (Objects.ObjectRec)
      test: TestProc;
      select: SelectProc;
      sendevent: SendEventProc;
      gettime: GetHintProc;
      preconditions: PreConditionsProc;
   END;
TYPE Description = POINTER TO DescriptionRec;
TYPE DescriptionRec =
   RECORD
      (Objects.ObjectRec)
      caps: CapabilitySet;
      internal: BOOLEAN;
   END;
TYPE GetTimeOfNextTryProc = PROCEDURE (iteration: INTEGER;
                                       VAR time: Times.Time);


PROCEDURE InitDomain(domain: Domain; if: Interface; desc: Description); PROCEDURE Init(condition: Condition; domain: Domain); PROCEDURE WaitFor(conditionSet: ConditionSet; VAR setOfTrueConditions: ConditionSet; errors: RelatedEvents.Object); PROCEDURE Test(condition: Condition; errors: RelatedEvents.Object) : BOOLEAN; PROCEDURE CreateSet(VAR conditionSet: ConditionSet); PROCEDURE Incl(conditionSet: ConditionSet; condition: Condition); PROCEDURE Excl(conditionSet: ConditionSet; condition: Condition); PROCEDURE Union(result: ConditionSet; set: ConditionSet); PROCEDURE Union3(VAR result: ConditionSet; set1, set2: ConditionSet); PROCEDURE In(conditionSet: ConditionSet; condition: Condition) : BOOLEAN; PROCEDURE Card(conditionSet: ConditionSet) : INTEGER; PROCEDURE ExamineConditions(conditionSet: ConditionSet); PROCEDURE GetNextCondition(conditionSet: ConditionSet; VAR condition: Condition) : BOOLEAN; PROCEDURE SetGetTimeOfNextTryProc(p: GetTimeOfNextTryProc);

DESCRIPTION

A condition is a boolean-valued function (with possible side effects) which allows to wait until it becomes TRUE. Conditions provides a general interface for conditions and a waiting algorithm which blocks the current process until at least one condition of a set becomes TRUE.

There exist a couple of condition variants with differing semantics in dependence of the different kinds of events they allow to wait for. These differences do not affect Conditions itself but result in different uses. The most important variants are:

local events
have only two parties: one which causes the event to happen and one which is interested in the event. Example: StreamConditions.
group events
are of interest for a group of parties. Each of these parties registers its interest which lasts until it is explicitly unregistered. Each receipt of these group events must be acknowledged. Example: EventConditions.
global events
are described by conditions which have no more than one transition from FALSE to TRUE. These conditions may be checked for by any number of parties at any time. Example: TimeConditions.
concurrent conditions
are conditions where only a limited number of them may become TRUE at the same time. These conditions obviously have a side effect when they are created. Example: Semaphores.

Note that conditions are always created and used locally, i.e. even for non-local events each party creates and uses its own condition. Conditions related to group events and concurrent conditions need some special treatment when they become TRUE. Conditions which are related to local or group events may be recycled.

Note that Conditions is independent from the kind of concurrency used. The synchronization of concurrent units which share the same address space is done by other modules (e.g. Tasks). Conditions itself allows only to block all concurrent units of an address space. Nevertheless, conditions of Conditions may be used for the synchronization with other processes (concurrent units of other address spaces) and with concurrent units of the same address space. For this to work, Conditions requires the memory model to follow the semantics of total store ordering, i.e. memory operations are visible for all concurrent units of the same address space in the order of execution.

Conditions which are of the same type (and generally defined by one module) belong to one domain. An interface is associated with a domain and some of the interface procedures are able to cope with a set of conditions which all belong to the same domain.

Interfaces are expected to meet following specifications:

test: PROCEDURE(domain: Domain; condition: Condition; errors: RelatedEvents.Object) : BOOLEAN;
Test the condition and return the result. This procedure must not block the current process. Note that TRUE is to be returned even in case of errors because FALSE is only to be returned if it makes sense to wait for condition to become TRUE.

select: PROCEDURE(domain: Domain; conditionSet: ConditionSet; time: Times.Time; VAR setOfTrueConditions: ConditionSet; errors: RelatedEvents.Object; retry: BOOLEAN; VAR interrupted: BOOLEAN) : BOOLEAN;
Wait for one of the conditions in conditionSet to become TRUE. time may be NIL or given as absolute or relative time limit. The time limit is to interpreted in the sense of the system clock Clocks.system. time is guaranteed to be equal to NIL if timelimit is not in the set of capabilities. If successful, select should setOfTrueConditions set to the subset of conditionSet which contains the conditions which evaluates to TRUE. select must return FALSE if the time limit exceeds and all conditions remain FALSE. In case of other errors (e.g. one of the conditions is no longer valid) TRUE is to be returned. In the latter case an error event should be passed to RelatedEvents which is related to errors. This procedure needs only to be provided if select belongs to the set of capabilities. It is important to note that select is expected to return immediately if one of the conditions become TRUE (even if the time limit is not yet exceeded). Implementations which are unable to assure this must not include timelimit in their capability set.
Additionally, implementations are expected to be interruptible (by external events) if retry is FALSE. Otherwise, if retry is TRUE, select is expected to retry the operation on interrupts. interrupted should be set to TRUE if interrupts occurred.

sendevent: PROCEDURE(domain: Domain; condition: Condition; event: Events.Event; errors: RelatedEvents.Object) : BOOLEAN;
Raise the given event immediately if condition becomes TRUE or is no longer valid. In case of external conditions (i.e. desc.internal is FALSE) this notification must be asynchronously, i.e. Process.Pause has to return. FALSE is to be returned if condition already evaluates to TRUE (in this case an event doesn't need to be raised). sendevent needs only to be implemented if async is in the set of capabilities. Note that this capability is very important for a good performance of the waiting algorithm.

gettime: PROCEDURE(domain: Domain; conditionSet: ConditionSet; VAR nextTime: Times.Time; VAR nextCond: Condition; errors: RelatedEvents.Object);
Return a relative time measure which gives the delay time until the first condition (to be returned in nextCond) of conditionSet becomes TRUE. This procedure is only to be provided if timecond is in the set of capabilities.

preconditions: PROCEDURE(domain: Domain; condition: Condition; VAR preconds: ConditionSet; errors: RelatedEvents.Object) : BOOLEAN;
Allows the implementation to specify a set of conditions where at least one of them needs to become TRUE before condition evaluates to TRUE. If preconditions returns TRUE and at least one condition in preconds, preconditions is called again when one of the conditions of preconds becomes TRUE. On repeated calls, preconditions is free to return different condition sets. This procedure must not return conditions which are already TRUE. preconditions needs only to be implemented if preconditions is given in the set of capabilities. FALSE is to be returned when there are no remaining preconditions.

InitDomain initializes a new domain and associates it with the interface if and the given description desc. The description consists of the capability set and a boolean-valued component internal which states whether the value of conditions of the given domain may change during process suspension (i.e. call of Process.Pause). Internal conditions are able change only if the program is running while external conditions may be effected by the outside world. Init initializes a condition and connects it to the given domain.

WaitFor blocks the current process until at least one of the conditions becomes TRUE and returns the set of true conditions in conditionSet. Note that usually Tasks.WaitFor is called which blocks the current task only.

The algorithm of WaitFor may degenerate in some cases to a busy loop, i.e. the conditions are repeatedly tested. To reduce the consumed CPU time in such a case, the process is suspended for some time in each iteration of the busy loop. The delay time of this loop for the n-th retry may be determined by an interface procedure which is to be passed to SetGetTimeOfNextTryProc. Initially, this interface procedure is provided by Conditions itself with a reasonable variant which returns longer delay times for increasing n. Busy loops may be caused by external conditions which do not support the capabilities async or timelimit.

Test returns TRUE if condition evaluates to TRUE.

CreateSet creates and initializes a condition set to the empty set. Incl includes condition to conditionSet. Excl excludes condition from conditionSet. Union stores in result the union of result and set. Union3 returns in result the union of set1 and set2. In returns TRUE if condition is a member of conditionSet. Card returns the cardinality of conditionSet.

ExamineConditions starts a traverse through all conditions of conditionSet. GetNextCondition, if successful, stores one of the conditions of conditionSet into condition and returns FALSE if there are no more conditions.

DIAGNOSTICS

Some errors lead to failed assertions:

Conditions does not generate any error events itself but forwards the events generated by the interface procedures to the errors parameters.

SEE ALSO

Clocks
definition of the system clock
Process
exports Process.Pause which allows to suspend the current process
RelatedEvents
error handling
Tasks
general task management
Times
time measures

Edited by: borchert, last change: 1996/09/13, revision: 1.10, converted to HTML: 1997/04/28

Oberon || Library || Module Index || Search Engine || Definition || Module