. navigate
 Navigate
6. Capsules & Separate Translation left arrow
x
right arrow 8. Overloading & Generic Definitions
Red Rationale
7.

EXCEPTION HANDLING &
MULTITASKING

Exception Handling     Raising Exceptions     Handling Exceptions     Terminating Other Tasks
Multitasking     Introduction     Activations and Scheduling
Message Passing     Deadlocks     Distributed Computing Regions



7.   EXCEPTION HANDLING AND MULTITASKING


7.1  EXCEPTION HANDLING

The following sections provide an overview of the RED language exception handling facilities. Features provided are described in the context of the real-time applications they are designed to support.




7.1.1  RAISING EXCEPTIONS

Exceptions may be raised explicitly by the user or implicitly by the system. System-defined exceptions include: arithmetic overflow, underflow, and zero-divide; range violations on assignment, case, subscript, and exponent; and use of uninitialized data. The user may define other exceptions via an exception declaration. The naming and scoping of exceptions follow the same rules as all other named objects in the language.

An exception may be explicitly raised by a RAISE statement. When an exception is raised, control is transferred to an appropriate handler. The handler may, in turn, raise some other exception. Occasionally, a handler may perform some specific processing and then pass the exception on to some other handler. For instance, an I/O capsule may export several exceptions and may enforce some rules about the maximum number of tolerable errors. Whenever an exception is raised in one of the capsule's routines, the routine handles the exception by performing the appropriate bookkeeping and then passing the original exception on to the invoker.

The reraising of an exception is accomplished with the RERAISE statement. Using the RAISE statement with no exception specified was considered (in the interest of reducing the number of reserved words) but was rejected on reliability grounds. when initially sketching out code, a programmer could easily write in the beginning of a RAISE statement, intending subsequently to fill in the actual exception name. Omission of such details is a common coding problem and one of the main motivations for not allowing default declarations. The separate reraise syntax guarantees that the same exception will be reraised only if the programmer really intended that to happen.




7.1.2  HANDLING EXCEPTIONS

Once an exception has been raised at run time, the system searches for a handler. Handlers are found in GUARD statements of the form:

example

When an exception occurs during the elaboration of the guarded body, control is transferred to the appropriate member of the WHEN list. The WHEN list and ELSE clause are optional and the identifiers that specify which exceptions are handled may, in fact, be lists of identifiers. The syntactic similarity with the CASE and WAIT statements is intentional, since the three statements perform tasks that are conceptually similar.

If an exception occurs during execution of a guarded body and an appropriate handler is supplied in the guard statement, the choice of a handler is straightforward. In practice, however, this will generally not be the case. In a structured program, one would expect the guarded bodies to invoke lower level routines. The lower level routines contain the detailed computations that may raise exceptions, but lack the global viewpoint to handle the errors. It is therefore necessary to be able to find a handler when the statement raising the exception is not itself a constituent of a guarded body.

The requirements for such processing are described in SM 1OC. Within a routine, a search is made for a handler by working outwards through the statically nested guarded bodies. If no handler is found, the exception is reraised at the point of call, thus allowing the exception to be raised in progressively higher-level routines. If an exception is raised but not handled in a task, that task is terminated but no other task is affected.

The RED language is in compliance with Steelman 1OC. The search for a handler begins in the scope in which the exception is raised and progresses according to the following rules:

  1. If the scope is a GUARD statement with an appropriate handler, apply the handler.

  2. If the scope is a routine, reraise the exception at the point of invocation.

  3. If the scope is a task, terminate the task.

  4. If the scope is the body which declares the exception name, raise the X_UNHANDLED exception in the enclosing scope.

  5. If none of rules 1-4 apply, reraise the exception in the enclosing scope.

The search for a handler may entail leaving several scopes. Exiting scopes due to exception processing entails the same storage deallocations as does normal termination. As a result, RED requires that exit from a scope be deferred until all subtasks created therein have terminated. If this is not the desired behavior, the user need simply provide a guard statement with an ELSE clause which exterminates the subtasks and then reraises the exception.




7.1.3  TERMINATING OTHER TASKS

Although it is dangerous for one task to terminate another, it is occasionally necessary to take this kind of action. For instance, a computer system controlling the flight of an airplane might support a variety of functions not required for the survival of the aircraft and its passengers. Should an emergency occur, all auxiliary functions would have to be shut down quickly so as to bring all the available resources to bear on the immediate problem. By permitting such termination, the RED facility maximizes safety without depriving the user of the power and flexibility necessary to get the job done.

The procedure call

      exterminate(activation_name)

will cause the X_TERMINATE exception to be raised in the named activation. Exterminate is a procedure in the predefined capsule which defines the scheduler. Notice that exterminate invokes a capability of the scheduler. This is necessary to guarantee that things are done in an expeditious but orderly manner. In particular, regardless of the state of the activation before the exterminate call, the scheduler will put it in the ready state about to execute a RAISE X_TERMINATE. The RAISE statement will actually be elaborated whenever the task is next assigned a processor; this depends upon the task's relative priority. Once the X_TERMINATE exception has been raised, it is treated like any other exception, the actual termination of the task being caused by the absence of a handler which does not perform a reraise.

There are occasionally critical points at which a program should not be interrupted. These typically occur in connection with manipulating locks on data. The procedures CRITICAL and NONCRITICAL, respectively, serve to disable and reenable X_TERMINATE. The semantics of the REGION statement guarantees that the associated lock will always be unlocked upon exit from the region. Conceptually, this is done in the presence of exceptions by executing:

example

Note that if an X_TERMINATE is raised between the lock and the guard, the lock will never be unlocked. To prevent this, X_TERMINATE must be disabled during the lock-guard sequence as in

example




7.2  MULTITASKING


7.2.1  INTRODUCTION

The RED language provides two levels of multitasking primitives. At the higher level, primitives are available for creating and terminating activations of tasks, for sending and receiving messages between activations, and for synchronizing the use of shared data. These primitives make use of a scheduler that provides service to activations based on priority and time of request for service. At the lower level, RED provides primitives that can be used to define different schedulers, and to define alternate methods of message passing and synchronization. These low-level primitives are sufficiently powerful that the high-level primitives can be implemented in terms of them. Also, interrupt handling can be accomplished through the low-level facilities.

We expect that most application programs will use the high-level primitives. If low-level primitives must be used to implement alternatives to the high-level facilities, these alternatives can be used in the same manner as the built-in ones (e.g., via the WAIT and REGION statements). For example, a simulation package that schedules events in simulated time could be implemented using the low-level primitives. The simulation programs that made use of this package would be similar to ordinary RED programs.

The following sections discuss high-level multitasking in more detail. Low-level multitasking is discussed in Section 9.5.




7.2.2  ACTIVATIONS AND SCHEDULING

Each task activation is named by a single activation variable and has an associated priority level (an integer between 0 and 255). The activation variable can be used to set and query the priority of an activation. Within a priority level activations are scheduled on a first-come first-served basis (255 is the highest priority and is served first).

The activation variable can also be used to cause the X_TERMINATE exception to be raised in an activation and to delay an activation for some specified period of time. The X;TERMINATE exception makes it possible to terminate other tasks when necessary. Tasks can be programmed to terminate gracefully (when X_TERMlNATE has been raised in them) by restoring data in the external environment to a consistent state.

Care has been taken in RED to ensure that there are no "dangling reference" problems associated with activations. A dangling reference could occur if an activation had access to a variable with a shorter lifetime than its own. RED avoids dangling references through these provisions: '

  1. each actual VAR and READONLY parameter to a task must have a lifetime as long as the lifetime of the task being activated,

  2. a scope cannot be exited until all activations of tasks declared in the scope have terminated, and

  3. tasks may not have OUT formal parameters.




7.2.3  MESSAGE PASSING

One style of developing parallel programs is to separate the activations into disjoint groups that share no memory. Since synchronization to share common data is needed only within a group, and not between groups, the resulting program is easier to understand and verify. Furthermore, the partitioning is often natural, especially when the data are distributed on different computers of a network.

In such a structure, inter-group communication is accomplished by sending and receiving messages. Since the different groups are independent of one another, it is desirable that the message passing mechanism not require them to synchronize their activities too closely.

RED provides a convenient and easily used form of inter-group communication by means of mailboxes and the WAIT statement. A mailbox provides a buffer between the sender and receiver. The size of this buffer, specified at the time the mailbox is created, determines how closely coordinated senders and receivers must be. If it is desired that the sender and receiver proceed precisely in step, then a mailbox of size 0 may be specified.

Mailboxes provide send and receive operations for sending and receiving messages, respectively. These operations can be invoked as stand-alone statements or as clauses in the WAIT statement. The latter use is convenient, for example, when an activation is waiting for messages from several mailboxes. In such a case, each branch of the WAIT statement would invoke the RECEIVE routine for the corresponding mailbox. The statement

example

could be used in a task that provides read and write access to a database. The read and write requests will be handled on a first-come first-served basis, except in the case of several requests waiting when the WAIT statement is entered. When this occurs, an arbitrary choice will be made among requests.

A WAIT statement with multiple sends could be used to request a service from multiple providers of that service; the first one to respond would be used. For example,

example

will cause data to be printed on whichever printer is available first (or an arbitrary choice will be made if both are available).

In addition to sends and receives, delays can be used as clauses in WAIT statements. One use is to provide a "timeout", so that the waiting activation does not wait indefinitely, or is awakened periodically to handle other responsibilities.

Delays can also be used to give priority to some mailboxes over others. For example,

example

gives priority to requests coming in on the high priority mailbox. Delays can also be invoked in contexts other than WAIT statements. Delays can be used to provide periodic service and to allow an activation to wait until all activations created by it are inactive.




7.2.4  DEADLOCKS

RED prohibits a send to a zero-length mailbox as a clause in a WAIT statement. This prohibition assures that use of the WAIT statement will not cause cycles of activations waiting to send and receive from zero-length mailboxes. If such cycles occurred, the activations involved would be deadlocked; the cycles could be prevented only by a global scheduling strategy. Such cycles can occur without danger when mailboxes of length greater than zero are used, because senders and receivers of a non-zero-length mailbox need not synchronize to exchange data.




7.2.5  DISTRIBUTED COMPUTING

RED mailboxes are a candidate for a communication mechanism in a distributed network. The notion of ordering of sends and receives must be clarified for a distributed environment, however. In particular, sends (receives) to a mailbox should probably be ordered according to the time that they arrive at the computer where the mailbox is stored, rather than the time they are actually sent. Such an interpretation is consistent with RED mailboxes.

Since the area of distributed computing is still the subject of basic research, it is possible that some applications may require a different set of primitives than the RED mailbox facility. For example, when a mailbox is full, senders are queued up (in the order that the sends arrived at the node containing the mailbox) and given FIFO service. This decision may be inappropriate in a distributed environment because of the inter-node communication that it implies.

RED's low-level multitasking facility provides the flexibility for the user to define different message-passing primitives if this is needed. This flexibility should be useful in adapting RED to the variety of requirements that may be specified in the future.




7.2.6  REGIONS

Mailboxes provide a means of communication between activations that share no memory. In addition, it is often useful for activations to communicate via shared memory.

Regions and datalocks permit activations to synchronize their use of shared memory. A datalock is associated with each set of related data that are to be shared; the data in the set are then used only within a region controlled by the datalock. This ensures that

  1. only one activation at a time can access the data (mutual exclusion); and

  2. the datalock is released when the region is exited, no matter how the exit occurs.

Regions and datalocks are not strictly necessary, since mailboxes can be used for synchronization. However, when mailboxes are used for this purpose the programmer may initialize the synchronization improperly or forget to release a resource when the critical section is finished. These errors can be avoided by the use of regions.

Of course, regions and datalocks do not preclude all errors. For example, a user might forget to limit access to shared data to a REGION statement. Also, releasing the lock automatically when the region is exited does not ensure that the shared data are usable: they might be left in an inconsistent state. To avoid the latter situation, the programmer should limit the problems caused by exceptions (and X_TERMINATE in particular) to as small a section of code as possible. For example,

example

Here, push is defined so that an inconsistent shared stack can never occur. When such a solution is not possible, exception handling can also be used to help restore data to a consistent state.

Another advantage of the REGION statement is that it enables the translator to detect (some) potential deadlocks. This can be achieved by ordering the datalocks according to their use in nested REGION statements; i.e., d1 < d2 if a REGION statement locking on d2 is nested in a REGION statement on d1. If such an ordering cannot be found, it indicates the danger of deadlock so that the translator can issue an appropriate warning.






Exception Handling     Raising Exceptions     Handling Exceptions     Terminating Other Tasks
Multitasking     Introduction     Activations and Scheduling
Message Passing     Deadlocks     Distributed Computing Regions

6. Capsules & Separate Translation left arrow
x
right arrow 8. Overloading & Generic Definitions


Overview

Requirements
      Strawman
      Woodenman
      Tinman
      Ironman
      Steelman

RED Reference
RED Rationale

Types in RED
Time/Life Computer Languages
Memories

Site Index

Overview             Reference ToC             Rationale ToC             Site Index


Home   Favorites   Map

IME logo Copyright © 2009, Mary S. Van Deusen