Model and definitions


SPIN and its extensions are written in Modula-3. Programs in Modula-3 are written as a composition of modules communicating by procedure calls through interfaces. Fundamentally, a procedure call is a signal from one module to another to indicate or request a change in the system state. In effect, a procedure call is an event raised by the caller and handled by the procedure's implementation. We exploit this relationship to define events in SPIN.

Events are a metaphor for extended procedure calls. They are defined in terms of Modula-3 procedure signatures, which preserves the natural invocation syntax and the ``feel'' of the language. Consequently, an event is a typed and named message that may carry arguments and return a value. Every procedure and object method is implicitly an event and hence eligible for extension. Events declared in an interface are available for modules that import that interface to either raise the event, or to provide additional handlers for the event. Events not declared in an interface can be explicitly passed between modules as procedure variables.

A handler is a procedure that is registered to receive invocations of an event. Handlers can be dynamically added to or removed from an event. One, multiple or no handlers can be installed on an event at any particular time. The same handler can be installed on any number of events in which case it will be invoked independently for each of them.

Each event handler may be associated with a set of guard predicates, which are used to filter out unwanted event raises. A handler is executed only if all of its guards evaluate to TRUE. For example, an extension may only be interestd in handling page fault events for its data segment, and can define a guard that checks whether the particular virtual address where the fault occurred is in that segment. The predicate is specified outside of the handler to separate the specification of extension code from the specification of the binding properties. Separation allows the same handler to be installed on many events, or on the same event many times with different guards.

An imposed guard is a guard installed with a handler for the purpose of limiting access of that handler to an event. Imposed guards enable an event occurrence to be dynamically checked before it is delivered to a handler.

A binding associates a handler and its guards with an event. A binding is active if it is currently installed on an event and inactive otherwise. If a binding is active its handler receives all instances of event raises for which all of its guards evaluated to TRUE. Otherwise, the handler does not receive event raises through this binding. The same handler may be used in a number of bindings, possibly for different events, and it may be installed for some of them and uninstalled for others. Each installation of such handler receives event raises independently, so the same procedure used as a handler can be invoked many times for the same event raise and be invoked by different events.

An event is defined by a procedure definition. It has the same name and type as the procedure that defines it. The implementation of the procedure becomes this event's original handler which is always (unconditionally) executed unless it is uninstalled.

An event's primary implementation module is the module that defines the original handler for the event. This module is responsible for maintaining properties of the event. The identity of the primary implementation of the module is required as a key to allow using authorization to limit the access to the event.

A centralized event dispatcher implements the event machinery which includes binding handlers to events, evaluating guards, and invoking handlers.

A closure is a data structure associated with either a handler or a guard procedure to provide it with static data specific to the binding. A closure is bound with a procedure at the time a binding is created. A handler or a guard takes a closure if an additional argument (a closure) is passed to it at the time of event raise besides the arguments of the event raise. A closure is a constant pointer that cannot be changed without reinstalling the binding with which it is associated.

A legal procedure is a procedure that can be used by the dispatcher as a handler, guard, or event. All Modula-3 procedures (except for nested procedures) are automatically legal. Non-Modula-3 procedures can be made legal explicitely. A nested Modula-3 procedure cannot be made legal.


Przemek Pardyak, May 20th, 1996