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


Ulm's Oberon Library:
Events


NAME

Events - priority driven event handling

SYNOPSIS

CONST default = 0; ignore = 1; funcs = 2;
TYPE EventType = POINTER TO EventTypeRec;
TYPE EventTypeRec = RECORD (Services.ObjectRec) END;
TYPE Reaction = INTEGER; (* one of default, ignore, or funcs *)
TYPE Message = ARRAY 80 OF CHAR;
TYPE Event = POINTER TO EventRec;
TYPE EventRec =
   RECORD
      (Objects.ObjectRec)
      type: EventType;
      message: Message;
   END;
TYPE EventHandler = PROCEDURE (event: Event);
TYPE EventManager = PROCEDURE (type: EventType; reaction: Reaction);
TYPE HandlerList = POINTER TO HandlerRec;
TYPE HandlerRec =
   RECORD
      (Objects.ObjectRec)
      handler: EventHandler;
      next: HandlerList;
   END;
TYPE Priority = INTEGER; (* must be non-negative *)
TYPE PrioritySystem = POINTER TO PrioritySystemRec;
TYPE PrioritySystemRec = RECORD (Objects.ObjectRec) END;


CONST priorityViolation = 0; CONST unbalancedExitPriority = 1; CONST unbalancedRestoreReaction = 2; CONST negPriority = 3; CONST errorcodes = 4; TYPE ErrorEvent = POINTER TO ErrorEventRec; TYPE ErrorEventRec = RECORD (EventRec) errorcode: SHORTINT; END; VAR errormsg: ARRAY errorcodes OF Message; VAR error: EventType;

PROCEDURE Define(VAR type: EventType); PROCEDURE Init(type: EventType); PROCEDURE GetReaction(type: EventType) : Reaction; PROCEDURE SetPriority(type: EventType; priority: Priority); PROCEDURE GetEventPriority(type: EventType) : Priority; PROCEDURE Manager(type: EventType; manager: EventManager); PROCEDURE Handler(type: EventType; handler: EventHandler); PROCEDURE RemoveHandlers(type: EventType); PROCEDURE Ignore(type: EventType); PROCEDURE GetHandlers(type: EventType; handlers: HandlerList); PROCEDURE Log(loghandler: EventHandler); PROCEDURE GetLog(VAR loghandler: EventHandler); PROCEDURE QueueHandler(handler: EventHandler); PROCEDURE AbortHandler(handler: EventHandler); PROCEDURE GetAbortHandler(VAR handler: EventHandler); PROCEDURE Raise(event: Event); PROCEDURE EnterPriority(priority: Priority); PROCEDURE AssertPriority(priority: Priority); PROCEDURE ExitPriority; PROCEDURE CreatePrioritySystem(VAR prioritySystem: PrioritySystem); PROCEDURE CurrentPrioritySystem() : PrioritySystem; PROCEDURE SwitchPrioritySystem(prioritySystem: PrioritySystem); PROCEDURE GetPriority() : Priority; PROCEDURE NilHandler(event: Event); PROCEDURE SaveReaction(type: EventType); PROCEDURE RestoreReaction(type: EventType);

DESCRIPTION

Events allows to define the reaction on an event and the entry of an event independently from each other. Event types connect both parties: reactions are specified for event types and an event type must be given for each event. Typical events are UNIX signals, run time errors, library errors, and program termination.

The reaction on an event is either

default
program termination (abort handler)
ignore
event is ignored
funcs
call associated event handlers
After defining an event type (by Define or Init) the reaction is default.

Event handlers are procedures to be called on event entry. They are of type EventHandler and get one parameter of type Event which contains the necessary information about the event. The number of event handlers of an event is not limited. One good example for distributed event handling is program termination (which is an event of Process): this allows each module not only to have an initialization part but also to have a cleanup procedure which is called automatically. The calling order is reverse to the order of handler definitions. This is very important for program termination because the calling order of cleanup procedures must be reverse to the calling order of initializations parts. Normal execution resumes (Raise returns) after call of all event handlers.

Handler defines an additional event handler for type. The reaction is set to funcs if the previous reaction was default or ignore. RemoveHandlers removes the list of event handlers of type and sets the reaction to default (i.e. program abortion). Ignore causes receipt of events of type type to be ignored. RemoveHandlers and Ignore cause the list of event handlers to be lost (if the previous reaction was funcs). This is not appropriate in case of temporary reaction changes. SaveReaction and RestoreReaction implement a stack of event reactions. SaveReaction saves the old reaction and sets the current reaction to ignore. The new reaction can be changed as usual by Handler or RemoveHandlers.

The current type of reaction for type can be retrieved by call of GetReaction. GetHandlers returns the list of event handlers in case of funcs reaction.

In some cases (e.g. inheritance of UNIX signals) there is a significant difference between ignore reaction and an empty event handler. NilHandler is of type EventHandler and can be given as argument to Handler.

Some types of events need some extra action in case of reaction changes (e.g. UNIX signals). In this case, Manager allows to define an event manager which is called on all changes of reaction.

Events defines a software priority system analogous to the hardware priority system of the PDP11. Each event has a priority (default Priorities.default). The current priority is defined as following

(1)
Priorities.base at beginning of execution.
(2)
During the call of an event handler the current priority is set to the priority of the event.
(3)
The priority can be raised by calling EnterPriority or AssertPriority and restored by ExitPriority.

Events with priority less than or equal to the current priority are queued until the current priority is diminished to a value less than the priority of the event. Events with priority less than or equal to Priorities.base are ignored (independent from the reaction). System events with default reaction may cause abortion even if their priority is less than or equal to the current priority. Priority values must not be negative.

SetPriority redefines the priority of events of type type to priority. GetEventPriority returns the priority of type. GetPriority returns the current priority. EnterPriority sets the current priority to priority. It is an error to give a priority less than the current priority \&(this error causes badpriority to be raised). AssertPriority sets the current priority to priority if the current priority is less than priority. ExitPriority requests the priority that was valid before the last call of EnterPriority or AssertPriority to be restored.

A priority system is defined by a stack of priorities which is manipulated by EnterPriority, AssertPriority and ExitPriority. In some cases coroutines or groups of coroutines need their own priority system: CreatePrioritySystem creates a new priority system with an empty stack and a current priority which equals Priorities.base. CurrentPrioritySystem returns the priority system which is currently active. SwitchPrioritySystem changes the current priority system to prioritySystem.

Raise causes event to happen if the reaction of the associated event type (event.type) is not equal to ignore. If the priority of the event is less than or equal to the current priority the event is queued (events with higher priority will be handled earlier, FIFO for events with equal priority). The abort handler is called in the default case. If reaction equals funcs the event handlers are called in reverse order of definition. The parameter event is passed to all event handlers. Raise returns as follows:

default
no return
ignore
immediate return
funcs
either after queuing of the event or after call of the associated event handlers

QueueHandler allows to replace the internal event queuing system of Events by an alternative implementation. The handler is invoked for every event that was passed to Events.Raise and whose priority does not exceed the current priority. SysMain installs its own queuing system which creates individual tasks for each event that cannot be processed immediately.

For tracing it is of interest to get a log of all events. Log defines an event handler which is called on each event with reaction funcs. Subsequent calls of Log replace the log handler. GetLog sets loghandler to the current log handler.

Events does not know how to achieve program abortion (usually program termination with core dump). AbortHandler defines a handler for abortion which must not return. The module Process defines a procedure which calls Process.Abort as abort handler during its initialization phase. Because Process is part of each Oberon program there should be no need to redefine the abort handler. Multiple calls of AbortHandler replace the abort handler. GetAbortHandler sets handler to the current abort handler.

SEE ALSO

EventConditions
supports synchronous event handling
Priorities
defines the priorities used by the Oberon library
Process
definition of termination events; program termination and abortion
RTErrors
raises events for runtime errors
Services
allows services for Events.EventType to be defined
SysErrors
common event driven error handling for system calls
SysSignals
UNIX signals

DIAGNOSTICS

Some usage errors cause events with priority Priorities.liberrors to be raised. The event records are of type ErrorEvent and contain one of the error codes given below:
priorityViolation
SetPriority was called with a priority less than the current priority
unbalancedExitPriority
ExitPriority was called without prior call of EnterPriority or AssertPriority.
unbalancedRestoreReaction
RestoreReaction was called without prior call of SaveReaction
negPriority
A negative priority value was given.

BUGS

Some system events (i.e. UNIX signals) with default reaction have some different behavior: The abort handler is not necessarily called in case of default reaction and they can cause abortion even if their priority is less than or equal to the current priority.
Edited by: borchert, last change: 2004/03/30, revision: 1.15, converted to HTML: 2004/03/30

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