[Return to Library]  [TOC]  [PREV]  SECT--  [NEXT]  [INDEX] [Help]

5    Event Processing

This chapter discusses specifications related to events that are outside the normal program flow. The topics covered are:


[Return to Library]  [TOC]  [PREV]  SECT--  [NEXT]  [INDEX] [Help]

5.1    Exception Handling

This section discusses the following considerations involved in the notification and handling of exceptional events during the course of normal program execution. An exception is a condition in the current software and/or hardware state that should be noted or fixed. The exception handler deals with the exception condition.

The next sections cover the following topics:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.1    Exception Handling Requirements

This Digital UNIX calling standard supports the following exception handling capabilities:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.2    Exception Handling Overview

When an exception occurs (is raised), the following events take place:

When a handler is invoked, it is called as a procedure with arguments that describe the following:

When the handler is called, the exception is said to be delivered to the handler.

The handler can respond to the exception in several ways, including various combinations of the following:

When an exception handler has finished processing an exception, it must indicate this state in one of the following ways:

All exceptions are handled using the same interfaces, data structures, and algorithms. That is, exception handling is unified for all kinds of exceptions, regardless of their origins. The interfaces and data structures are defined in the file /usr/include/excpt.h.

Each exception has an exception value that identifies the type of exception, such as subscript range violation or memory access control violation. Exceptions can also be associated with one or more exception qualifiers (such as the name of an array and the subscript that was out of range, or an address associated with a memory access control violation).


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.3    Kinds of Exceptions

There are three kinds of exceptions:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.3.1    General Exceptions
General exceptions are divided into two categories:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.3.2    Unwind Exceptions
Unwind exceptions result from the invocation of the unwind support code by a thread. These exceptions are always delivered to the thread that invoked the unwind.

Unwind exceptions are delivered as part of the notification process that an unwind is in progress. (See Section 5.2 for details.)


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.3.3    Signal Exceptions
Signal exceptions result from the delivery of a POSIX signal. This signal is subsequently converted into an exception that can be handled using the capabilities defined by this calling standard.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.4    Status Values and Exception Codes

A status value is a quadword that can be used as a return value from a procedure call to indicate success, failure, or other information about the requested operation. A status value can also be used as an exception code to indicate the reason that an exception is being raised.

Figure 5-1 shows the components of a status value structure.


Figure 5-1: Status Value Representation


The components of this representation are as follows:

  1. osf_facility

    A facility code indicating the software component that defines this status value. Only those values defined in the file /usr/include/excpt.h can be used. This component consists of three subfields:

  2. code

    This field contains a value for a particular status condition.

There are several ways for a software system or application to define its own status values:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.5    Exception Records

The fundamental data structure for describing exceptions is the exception record. Exception records can be joined together by handlers to form a linked list. Each record in a list describes one exception.

The first exception record in the list describes the primary exception. Secondary exceptions can be specified by adding exception records to the list. Secondary exceptions qualify or elaborate the primary exception. In some cases, they are raised at the same time as the primary exception. In other cases, a handler can add new secondary exceptions to the list before handling or reraising the exception.

Storage for exception records can be allocated in read-only memory. The exception record that is passed to a handler is a separate read-write copy constructed from information in the original exception record augmented with additional information.

Figure 5-2 shows the format of an exception record.


Figure 5-2: Exception Record Format


  1. ExceptionCode is an exception code value. (See Section 5.1.4.)

  2. ExceptionFlags is a bit field of flags that further qualify the exception. These flag bits are significant only in the primary exception record; their state is unpredictable in secondary exception records. ExceptionFlags bits are logically divided into two groups: detail flag and environment flags. Detail flags provide additional information about the exception. Environment flags provide additional information about the environment in which the exception is being delivered.

    The following ExceptionFlags bits are detail flags that give additional details:

    The following ExceptionFlags bits are environment flags that give additional information about the environment at the time of exception delivery:

    All FLAGS bits other than those defined in the preceding lists must be zero.

  3. ExceptionRecord is zero or contains the address of the next exception record in the list.

  4. ExceptionAddress is the address of the instruction causing the exception.

    For a hardware, signal, or asynchronous software exception, this field contains the address of the instruction at which the hardware, signal, or asynchronous exception interrupted execution of the thread.

    For a synchronous software exception, this field contains the address of the call instruction that invoked the library routine for raising the exception.

    This field is significant only in primary exception records; its contents are unpredictable in secondary exception records.

  5. NumberParameters is the number of exception-specific qualifiers in the exception record.

  6. Each ExceptionInformation [n] value is a single quadword that provides additional information specific to the exception. The quadword can also contain information intended for display in messages.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.5.1    Exception Records for General Exceptions
In the case of software-caused exceptions, the information in the exception records for general and unwind exceptions can vary widely from a simple single-exception value to a long chain of exceptions and exception qualifiers. This calling standard defines the conventions for constructing these exception records. However, a complete enumeration of all possible combinations is beyond the scope of this document.

All Alpha hardware exceptions have exception information associated with them. This information can be as little as the exception type and exception PC or as much as three registers worth of additional information. The specific information that is supplied with each exception type is defined in the Alpha Architecture Reference Manual.

Hardware exceptions are reported to user mode in the form of POSIX signals. See Section 5.1.5.3.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.5.2    Exception Records for Unwind Exceptions
Unwind exceptions have at least one of the following flags set to 1:

The ExceptionCode for unwind exceptions contains the reason code for the unwind along with any supplied qualifiers. This information is similar to the contents of the ExceptionCode field for general exceptions.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.5.3    Exception Records for Signal Exceptions
In exception records for signal exceptions, the value of the ExceptionCode field includes the signal number. Any additional exception qualifiers that are present can further qualify the signal. These qualifiers are most useful for hardware-generated signals.

For example, in a POSIX-conforming environment, all arithmetic exceptions are delivered with a signal number SIGFPE. The qualifiers can indicate whether the signal was caused by a floating underflow, integer overflow, or other arithmetic exception. (In a POSIX-conformant environment, no mechanism is provided for a user program to deliver a signal with a qualifier of any kind. Thus, the presence of such a qualifier occurs because it was produced by some system facility, such as the hardware exception dispatching code.) See Section 5.1.13 for a discussion of exception and signal handling coexistence.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.6    Frame-Based Exception Handlers

A frame-based exception handler is established when a procedure whose descriptor specifies an exception handler becomes current. Thus, frame-based handlers are usually associated with a procedure at compile time and are located at run time through the procedure descriptor. These exception handlers are normally used to implement a particular language's exception handling semantics.

The frame-based exception handlers that can be invoked are those established by active procedures, from the most current procedure to the oldest predecessor.

An exception handler that conforms to this calling standard should not handle any exception that its establisher did not cause, unless there is a prior agreement between the writers of the exception handler and the writers of the code that raised the exception.

Exceptions can be raised and unwind operations that cause exception handlers to be called can occur when the current value of at least one variable is in a register rather than in memory. Therefore, a handler and any descendant procedure called directly or indirectly by a handler must not access any variables except those explicitly passed to the procedure as arguments or those that exist in the normal scope of the procedure.

This requirement can be violated for specific memory locations only by agreement between the handler and all procedures that might access those memory locations. The effects of such agreements are not specified by this calling standard.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.7    Establishing Handlers

The list of established frame-based handlers for a thread is defined by the thread's procedure invocation chain. (See Chapter 7 for information on procedure invocations and call chains.)

A procedure descriptor for which PDSC_FLAGS_HANDLER_VALID is 1 must specify in PDSC_RPD_HANDLER_ADDRESS the procedure value of an exception handler. The exception handler specified by a procedure descriptor is established when the corresponding procedure is added to the invocation chain; that is, when the procedure designated by the descriptor becomes current.

The exception handler remains established as long as that procedure invocation is part of the invocation chain. The handler is revoked when that procedure is removed from the invocation chain; that is, when the procedure invocation designated by the descriptor terminates, either by returning or being unwound.

Thus, the set of frame-based handlers that is established at any moment is defined by the current procedure call chain.

Dynamic activation or deactivation of exception handlers is not defined by this calling standard (and, in fact, is not permitted within the semantics of many language standards). If this capability is required, it must be defined on a language-by-language basis.

Compilers that choose to support this capability can establish language-specific static exception handlers that provide the dynamic exception handling semantics of that language. Such static handlers would be established by means of the procedure descriptor of the establishing procedure. If a language compiler decides to support dynamic activation of exception handlers, it must be prepared to recognize code that intends to use this feature. This requirement results from the need to add appropriate trapb instructions and other compile-time considerations necessary to make dynamic exception handling function correctly.


Note

There can be additional protocols and conventions for dynamic exception handling. Such protocols and conventions might be needed, for example, to enable a debugger to perform effectively within the language exception handling environment. Such conventions are driven by the requirements of the languages and the language support utilities, and are not addressed by this calling standard.



[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.8    Raising Exceptions

This section describes the four ways of raising exceptions.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.8.1    Raising General Exceptions
A thread can raise a general exception in its own context by calling a system library routine defined as follows:

exc_raise_exception (ExceptionRecord)

Arguments:


ExceptionRecord  The address of a primary exception record 

Function Value:

None

The exc_raise_exception() routine sets ExceptionAddress to the address of the invoking call instruction. If exc_raise_exception() detects that the exception record passed as the first argument is not a valid exception record, the routine raises the exception EXC_INVALID_EXCEPTION_RECORD.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.8.2    Raising General Exceptions Using gentrap
The Alpha Architecture Reference Manual defines the gentrap PAL call as a mechanism for software to raise hardware-like exceptions at minimum cost. This mechanism is suitable for use in low levels of the operating system or during bootstrapping when only a limited execution environment is generally available.

In a constrained environment, gentrap can be handled directly through the SCB vector. In a more complete environment, the gentrap parameter is transformed into a corresponding exception code and reported as a normal hardware exception. Low-level software can use this mechanism to report exceptions in a way that is independent of the execution environment. Compiled code can also use this mechanism to raise common generic exceptions more cheaply than would be possible if the code had to make a full procedure call to exc_raise_exception().

The gentrap PAL call is defined as follows:

gentrap (EXPT_CODE)

Argument:


EXPT_CODE  Code for the exception to be raised 

If the EXPT_CODE value is one of the small negative values shown in Table 5-3, that value is mapped to the corresponding POSIX signal, as shown. The signal qualifier is set to EXPT_CODE. The signal can be converted to an exception by installing exc_raise_signal_exception() as the signal handler. (See Section 5.1.13.) The gentrap instruction sets ExceptionAddress to the address of the PAL call.

For other values of EXPT_CODE, the behavior of gentrap is not defined by this standard.

Note that there are no mechanisms to associate any parameters with an exception raised using gentrap.


Table 5-3: gentrap EXPT_CODE Values
EXPT_CODE ValueSymbolMeaningPOSIX Signal
-1  GEN_INTOVF  Integer overflow  SIGFPE 
-2  GEN_INTDIV  Integer divide by zero  SIGFPE 
-3  GEN_FLTOVF  Floating overflow  SIGFPE 
-4  GEN_FLTDIV  Floating divide by zero  SIGFPE 
-5  GEN_FLTUND  Floating underflow  SIGFPE 
-6  GEN_FLTINV  Floating invalid operation  SIGFPE 
-7  GEN_FLTINE  Floating inexact result  SIGFPE 
-8  GEN_DECOVF  Decimal overflow  SIGTRAP 
-9  GEN_DECDIV  Decimal divide by zero  SIGTRAP 
-10  GEN_DECINV  Decimal invalid operand  SIGTRAP 
-11  GEN_ROPRAND  Reserved operand  SIGFPE 
-12  GEN_ASSERTERR  Assertion error  SIGTRAP 
-13  GEN_NULPTRERR  Null pointer error  SIGTRAP 
-14  GEN_STKOVF  Stack overflow  SIGTRAP 
-15  GEN_STRLENERR  String length error  SIGTRAP 
-16  GEN_SUBSTRERR  Substring error  SIGTRAP 
-17  GEN_RANGEERR  Range error  SIGTRAP 
-18  GEN_SUBRNG  Subscript range error  SIGTRAP 
-19  GEN_SUBRNG1  Subscript 1 range error  SIGTRAP 
-20  GEN_SUBRNG2  Subscript 2 range error  SIGTRAP 
-21  GEN_SUBRNG3  Subscript 3 range error  SIGTRAP 
-22  GEN_SUBRNG4  Subscript 4 range error  SIGTRAP 
-23  GEN_SUBRNG5  Subscript 5 range error  SIGTRAP 
-24  GEN_SUBRNG6  Subscript 6 range error  SIGTRAP 
-25  GEN_SUBRNG7  Subscript 7 range error  SIGTRAP 


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.8.3    Raising Unwind Exceptions
The mechanism used to raise an unwind exception is described in detail in Section 5.2.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.8.4    Raising Signal Exceptions
Signal exceptions can be raised asynchronously (such as, for notification of a terminal line hangup) or synchronously. The exact circumstances that cause an asynchronous signal exception to be raised vary widely from hardware exception notification to software notification, as in the POSIX-defined alarm() routine. Section 5.1.13 contains information on exception and signal handling coexistence.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.9    Search for and Invocation of Exception Handlers

The search for and subsequent invocation of an exception handler begins with the program counter value that indicates the address at which the exception was raised. Generally, a program counter value is associated with a procedure descriptor. (Section 8.1 describes procedure descriptors.) The procedure descriptor provides information needed to identify the procedure containing the code and interpret those parts of the stack frame that are needed to traverse the procedure call chain. (Chapter 7 discusses procedure invocation and call chains.)

If a null frame procedure or other fragment of code does not have an associated procedure descriptor, it is assumed that an appropriate initial program counter value is located in the normal return address register ($26). If there is a procedure descriptor associated with this address, the search for an exception handler begins using that address; otherwise, a fatal exception is raised and the executing thread is terminated.

The next sections discuss the order of invocation for exception handlers as well as handler invocation and arguments.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.9.1    Invocation Order for Exception Handlers
When an exception is raised, established exception handlers are invoked in a specific order.

Any frame-based handlers are invoked in order, from the handler established by the most current procedure invocation to the handler established by the oldest predecessor in the invocation chain.

If no frame-based handlers have been established, or if all of them reraise the exception, the system last chance handler is invoked.

A nested exception occurs if an exception is raised while an exception handler is active. When a nested exception occurs, the structure of the procedure invocation chain, from the most recent procedure invocation to the oldest predecessor, contains the following elements in the specified order:

  1. The procedure invocation within which the nested exception was raised.

  2. Zero or more procedures invoked indirectly or directly by the most recently invoked (most current) handler.

  3. The most current handler.

    If there are zero invocations in item 2, this invocation is the same as item 1 (the invocation in which the nested exception was raised). In this case, items 1 and 3 count as a single invocation.

  4. The procedure invocation within which the active exception that immediately preceded the nested exception was raised, that is, the invocation in which the exception was raised for which the most current handler was invoked.

  5. Zero or more procedure invocations. All handlers established by these procedures have been invoked for the exception that immediately preceded the nested exception and all have reraised that exception.

  6. The establisher of the most current handler.

    If there are zero invocations in item 5, this invocation is the same as item 4 (the invocation in which the exception that immediately preceded the nested exception was raised).

  7. Zero or more procedure invocations for which no established handlers have yet been invoked.

Figure 5-3 shows an example of a procedure invocation chain, where BB is the most recent invocation and A is the oldest predecessor. The numbers on the left side of the figure correspond to the elements in the previous list.


Figure 5-3: Procedure Invocation Chain


The following list contains the time-ordered events that gave rise to this invocation chain:

Established handlers are invoked in reverse order to the order in which their establishers were invoked. That is, the search of stack frames for procedure invocations that have established handlers is in the order 1 to 7.

If further nested exceptions occur, this procedure invocation chain structure is repeated for those further nested exceptions. Frame-based handlers are invoked according to the order previously listed; that is, from those established by the most current procedure to those established by the oldest predecessor.

The following pseudocode shows the steps for locating and invoking exception handlers. Note that these steps cover only the search of stack frames for a handler proper and do not address the mapping of a POSIX signal to an exception.

  1. Let current_invocation be the procedure invocation in which the exception was raised.

  2. [loop]: If current_invocation does not establish a handler, go to step [check-begin].

  3. Invoke the handler established by current_invocation.

  4. If the handler returns ExceptionContinueExecution or initiates an unwind, exit from these steps.

  5. [check-begin]: If current_invocation is the beginning of the procedure invocation chain, go to step [last-chance].

  6. If current_invocation is an active handler, let current_invocation be the invocation in which the exception was raised that invoked this active handler, and go to step [loop].

  7. Let current_invocation be the procedure invocation that invoked current_invocation.

  8. Go to step [loop].

  9. [last-chance]: Invoke the system last chance handler.

If, during the search for and invocation of frame-based handlers, the exception dispatcher detects that the thread's main stack is corrupt, the following actions occur:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.9.2    Handler Invocation and Arguments
Every exception handler is invoked as a function that returns a status value. The function call is defined as follows:

(*ExceptionHandler)
    ( ExceptionRecord, EstablisherFrame,
                          ContextRecord, DispatcherContext )

Arguments:


ExceptionRecord  The address of a primary exception record. 
EstablisherFrame  The virtual frame pointer of the establisher (discussed in Section 7.1). 
ContextRecord  The address of a sigcontext structure containing the saved original context at the point where the exception occurred. During an unwind, this argument contains the address of the sigcontext structure for the establisher. (The sigcontext structure is defined in the file /usr/include/signal.h.) 
DispatcherContext  The address of a control record for the exception dispatcher. 

Function Value:


STATUS  A value indicating the action to be taken upon handler return. The valid values are ExceptionContinueExecution and ExceptionContinueSearch. Note: the exception dispatcher allows additional return values from its own exception handlers. 

The control record pointed to by DispatcherContext provides communication between the handler and the exception dispatcher
(the system routine that actually invokes the handler). This record provides information about the establisher. The following list discusses three fields in the record:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.10    Modification of Exception Records and Context by Handlers

The exception records, exception qualifiers, invocation context blocks, and control records that are passed to an exception handler are always allocated in writable memory. Handlers can write to any location in these data structures. The exception records and exception qualifiers that are passed to a handler are copies of the original ones. Modifications to them are seen by other subsequently called handlers (within the limits described later) but do not affect the original data structures.

The effects of a handler-modifying passed exception information are as follows:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.11    Handler Completion and Return Value

When an exception handler has finished all its processing, it performs one of the following actions: Section 5.2 contains a complete description of the unwinding process. This section discusses the other methods of handler completion.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.11.1    Completion by Reraising the Exception
If an exception handler determines that additional handlers should be invoked for the exception because it could not completely handle the exception, the handler can reraise the exception by returning ExceptionContinueSearch.

Reraising causes the next exception handler to be invoked. (See Section 5.1.9.1 for details.)

If all exception handlers established by the thread reraise the exception, the system last chance handler is invoked, with system-dependent results.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.11.2    Completion by Continuing Thread Execution
By returning ExceptionContinueExecution, an exception handler can continue execution of the thread at the address specified by the continuation PC in the ContextRecord, with the context of the interrupted procedure restored.

If ExceptionContinueExecution is returned and the EXCEPTION_NONCONTINUABLE flag is 1, a nested exception is raised with ExceptionCode equalling EXC_STATUS_NONCONTINUABLE_EXCEPTION. This second exception is also noncontinuable.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.11.3    Completion During Unwinding
When an unwind is in progress, the status returned by handlers must be ExceptionContinueSearch. Otherwise, EXC_STATUS_INVALID_DISPOSITION is raised; that is, handlers cannot continue during an unwind operation.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.11.4    Completion from Signal Exceptions
The permissibility and effects of continuing from a signal exception are governed by the underlying signal, as specified by the implementation of the POSIX environment.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.12    Other Considerations in Handling Exceptions

This section details certain aspects of the Alpha architecture that have significant implications for exception handling. These aspects are:

The rules presented are designed to assure correct operation across all implementations of that architecture. As with all aspects of this calling standard, optimization information may assure correct behavior as if these rules were followed, without appearing to explicitly do so.

Alternative approaches that exploit implementation-specific characteristics are also possible, but are outside the scope of this calling standard.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.12.1    Exception Synchronization
The Alpha hardware architecture allows instructions to be completed in a different order than that in which they were issued. The architecture also allows for exceptions caused by an instruction to be raised after subsequently issued instructions have been completed. Thus, when a hardware exception occurs, the state of the machine cannot be assumed with precision unless it has been guaranteed by bounding the exception range with the appropriate insertion of trapb instructions.

The rules for bounding the exception range are as follows:

These rules ensure that exceptions are detected in the context within which exception handlers have been set up to handle them.

However, these rules do not ensure that all exceptions are detected while the procedure within which the exception-causing instruction was issued is current. For example, if a procedure without an exception handler is called by a procedure that has an exception handler that is not sensitive to invocation depth, an exception detected while that called procedure is current might have been caused by an instruction issued while the caller was the current procedure. Therefore, the frame, designated by the exception handling information, is the frame that was current when the exception was detected, not necessarily the frame that was current when the exception-causing instruction was issued.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.12.2    Continuation from Exceptions
The Alpha architecture does not guarantee that instructions are completed in the same order in which they were fetched from memory or that instruction execution is strictly sequential. Continuation after some exceptions is possible, but there are restrictions.

Software-raised general exceptions are, by definition, synchronous with the instruction stream and can have a well-defined continuation point. Thus, a handler has the option of requesting continuation from a software raised exception. However, because compiler-generated code typically relies on error-free execution of previously executed code, continuing from a software-raised exception might produce unpredictable results and unreliable behavior unless the handler has explicitly fixed the cause of the exception in a way that is transparent to subsequent code.

Hardware faults on Alpha systems follow rules that, loosely paraphrased, state the following: if the offending exception is fixed, reexecution of the instruction (as determined from the supplied PC) will yield correct results. This generality does not imply that no instructions following the faulting instruction have been executed. (See the Alpha Architecture Reference Manual for details.) Hardware faults can therefore be viewed as similar to software-raised exceptions and can have well-defined continuation points.

Arithmetic traps cannot be restarted unless all the information required for a restart is available. The most straightforward and reliable way for software to guarantee the ability to continue from this type of exception is by placing appropriate trapb instructions in the code stream. Although this technique does allow continuation, it must be used with extreme caution due to the negative side effects it has on application performance. A more sophisticated technique that requires typically one trapb for each basic block is described in the Alpha Architecture Reference Manual in the section on imprecise software completion trap modes.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.1.13    Exception and Signal Handling Coexistence

The procedure-based exception handling facility defined by this calling standard coexists with a global POSIX-style signal facility. The following list describes the features and limitations of such a coexistence.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2    Unwinding

The unwinding capabilities specified in this section support the following:

This section discusses the following topics:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.1    Overview of Unwinding

The term unwinding, or unwind operation, refers to the action of returning from a procedure or a chain of procedures by some mechanism other than the normal return path. Performing an unwind operation in a thread causes a transfer of control from the location at which the unwind operation is initiated to a target location in a target invocation. This transfer of control results in the termination of all procedure invocations, including the invocation in which the unwind request was initiated, up to the target procedure invocation. Thread execution then continues at the target location.

Before control is transferred to the unwind target location, the unwind support code invokes all frame-based handlers that were established by procedure invocations which are being terminated, as well as the handler for the target invocation.

This behavior gives each procedure invocation the chance to perform clean-up processing before its context is lost. These handlers are invoked with an indication that an unwind is in progress. The exception record passed to the target invocation's handler also has EXCEPTION_TARGET_UNWIND set to 1.

Once all the relevant frame-based handlers have been called and the appropriate frames have been removed from existence, the target invocation's saved context is restored and execution is resumed at the specified location.

The results of attempting an unwind operation to any invocation previous to the top-level procedure of a thread are undefined by this calling standard.

Unwinding does not require an exception handler to be active. Unwind operations can be used by languages to implement nonlocal GOTOs.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.2    Types of Unwind Operations

There are two types of unwind requests: general and exit. The following sections describe each type.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.2.1    General Unwind
A general unwind transfers control to a specified location in a specified procedure invocation. The target procedure invocation is specified by a frame pointer. (See Section 7.1 for information on procedure invocation.) The target location is specified with an absolute PC value.

When a general unwind is completed, the registers are updated from the invocation context for the target frame. Register $0 obtains its value from the ReturnValue argument to the unwind operation. This action allows a status to be returned to the target of the unwind.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.2.2    Exit Unwind
It is valuable for a thread that is terminating execution to be able to clean up its use of shared resources. In a single-threaded process, there might be global resources, such as files, locks, or shared memory, that are shared among processes. For multithreaded processes, global resources as well as process-wide resources like a heap might need to be restored to a known state.

Because of this need to clean up shared resources, exiting by a user-mode thread can be accomplished only by unwinding. A special type of unwind, called an exit unwind, performs the following actions to terminate execution:

Threads that use any mechanism for termination other than the normal return process are not considered to be standard and their behavior is undefined.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.3    Types of Unwind Invocations

There are two types of unwind invocations: those initiated while an exception is active and those initiated while no exception is active. This section describes each type.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.3.1    Unwind Operations with No Active Exception
An unwind that is initiated when no exception is active is usually done to perform a nonlocal GOTO; that is, to transfer control directly to some code location that is not part of the currently executing procedure or is not statically known. Even this type of unwind operation must provide a mechanism to allow clean-up operations (including restoring a consistent set of register values) of terminated invocations to be performed. The unwind mechanism supports such clean-up operations.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.3.2    Unwind Operations During an Active Exception
By initiating an unwind operation, the handler, or any descendant procedure called directly or indirectly by the handler, can continue execution of the thread at a location different from the one where the exception was raised.

An unwind operation specifies a target invocation in the procedure invocation chain and a location in that procedure. The operation terminates all invocations up to the target invocation and continues thread execution at the specified location in that procedure.

Before control is transferred to the target location, the unwind operation invokes each frame-based handler that was established by any procedure invocations being terminated, and also invokes the handler for the target invocation.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.4    Unwind Initiation

A thread can initiate a general unwind operation by calling one of two system library routines. The routines differ only in the way their first argument specifies the target frame: as a virtual frame pointer or a real frame pointer. (Section 7.1 discusses ways to refer to procedure invocations.) These routines are defined as follows:

exc_unwind (VirtualTargetFrame, TargetPC,
                            ExceptionRecord, ReturnValue)

exc_unwind_rfp (RealTargetFrame, TargetPC,
                            ExceptionRecord, ReturnValue)

Arguments:


VirtualTargetFrame  If nonzero, specifies the virtual frame pointer of the target procedure invocation to where the unwind is to be done. If zero, specifies that an exit unwind is initiated and causes the EXCEPTION_EXIT_UNWIND flag to be set to 1 in the exception record. 
RealTargetFrame  If nonzero, specifies the real frame pointer of the target procedure invocation to which the unwind is to be done. If zero, specifies that an exit unwind is initiated and causes the EXCEPTION_EXIT_UNWIND flag to be set to 1 in the exception record. 
TargetPC  Specifies the address within the target invocation at which to continue execution. If a target frame argument is zero, this argument is ignored. 
ExceptionRecord  If nonzero, specifies the address of a primary exception record. If zero, specifies that a default exception record should be supplied. 
ReturnValue  Specifies the value to use as the return value (contents of $0) at the completion of the unwind. 

Function Value:

None

If the ExceptionRecord argument is zero, exc_unwind() or exc_unwind_rfp() supplies a default exception record. That default exception record specifies exactly one exception record in which ExceptionCode is EXC_STATUS_UNWIND. For an explicit or default exception record, the EXCEPTION_UNWINDING flag is set to 1; and, if a null target frame argument is specified, the EXCEPTION_EXIT_UNWIND flag is set to 1. The ExceptionAddress is set to TargetPC.

If the ExceptionRecord argument is specified when the unwind is initiated, all other properties of the exception record are determined by ExceptionRecord. If exc_unwind() or exc_unwind_rfp() detects that a specified exception record is not a valid unwind record, the routine will raise the exception of EXC_INVALID_EXCEPTION_RECORD. If the frame corresponding to the target frame argument cannot be found, the system last-chance handler is called because all procedures have been terminated.

Once an unwind is initiated, control never returns from the call.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.5    Multiply Active Unwind Operations

Sometimes, an unwind operation is initiated while another unwind is already active. Such a situation could occur if a handler that is invoked during the original unwind initiates another unwind, or if an exception is raised in the context of such a handler and a handler invoked for that exception, in turn, initiates another unwind operation.

An unwind that is initiated while a previous unwind is active is either a nested unwind or a colliding unwind. This section discusses both types of multiply active unwind operations.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.5.1    Nested Unwind
A nested unwind operation is an unwind that is initiated while a previous unwind is active. For a nested unwind, the target invocation in the procedure invocation chain is not a predecessor of the most current active unwind handler. That is, a nested unwind does not terminate any procedure invocation that would have been terminated by the previously active unwind.

When a nested unwind is initiated, no special rules apply. The nested unwind operation proceeds as a normal unwind operation. When execution resumes at the target location of the nested unwind, the nested unwind is complete and the previous unwind is once again the most current unwind operation.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.5.2    Colliding Unwind
Like the nested unwind, a colliding unwind is an unwind that is initiated while a previous unwind is active. For a colliding unwind, the target invocation in the procedure invocation chain is a predecessor of the most current active unwind handler. That is, a colliding unwind terminates one or more procedure invocations that would have been terminated by the previously active unwind.

A colliding unwind is detected when the most current active unwind handler is terminated. This detection of a colliding unwind is referred to as a collision. When a collision occurs, the second (more recent) unwind operation takes precedence and the previous unwind is abandoned.

The next action is to reinvoke the most current established handler because its establisher has not been unwound. The EXCEPTION_COLLIDED_UNWIND flag is set in the exception record to indicate this situation to the handler.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.6    Unwind Completion

When an unwind is completed, the following conditions are in effect:


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [NEXT]  [INDEX] [Help]

5.2.7    Unwinding Coexistence with setjmp and longjmp

The procedure invocation unwinding facility defined by this calling standard can coexist and interoperate with the setjmp() and longjmp() facilities. It is sufficient for the jmp_buf array to consist of the frame pointer and program counter values that are needed as arguments to exc_unwind() or exc_unwind_rfp(). A null pointer can be provided for the ExceptionRecord argument and the value of the longjmp() expression can be provided for the ReturnValue argument.

Any environment that conforms to this calling standard must implement nonlocal GOTOs by using exc_unwind() or exc_unwind_rfp() (or an equivalent means) to allow all procedures being terminated to clean up any local or global states, as appropriate.


Note

The longjmp() routine for Digital UNIX does not use an unwind operation. Therefore, in the presence of frame-based exception handling, it is preferable to use exc_longjmp(), implemented through an unwind operation.