The next sections cover the following topics:
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:
The handler indicates that the exception handling support code should
reraise the exception and resume the search for a new handler.
The handler indicates that the exception handling support code should
continue execution of the interrupted thread at the location indicated by
the saved exception program counter.
The handler performs an unwind operation that causes the exception handling
support code to resume execution of the thread at a point other than the point
at which it was interrupted or to terminate the execution of the thread.
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).
A software-caused general exception is raised when an exception-raising
procedure is invoked. This type of exception is always delivered to the thread
that made the call.
A software-caused exception
can be raised at any point during
thread execution. Applications and language run-time libraries can raise general
exceptions to notify a thread of some exceptional (noteworthy) state in the
current thread context. For example, subscript range-checking failures and
assertion-checking failures can be raised as software-caused general exceptions.
A hardware-caused general exception
occurs when a thread performs
some action that causes an exceptional state to exist in the hardware. Such
a state will cause the currently active thread to be interrupted. A hardware-caused
general exception is always delivered to the thread that executed the instruction
that caused the exception.
The following characteristics are specific to individual hardware exceptions:
Hardware exceptions are fully defined in the Alpha Architecture
Reference Manual.
In the Digital UNIX for Alpha systems environment, hardware exceptions
that are not
handled by the operating
system itself are reported to user level in the form of a POSIX signal. Such
signals are then further interpreted as exceptions and are handled as described
in this calling standard. See Section 5.1.13 for
details on how this signal interpretation is achieved.
Unwind exceptions are delivered as part of the notification process
that an unwind is in progress. (See Section 5.2 for details.)
Figure 5-1 shows the components of a status
value structure.
The components of this representation are as follows:
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:
This field has the value ffe(hex) on Digital UNIX for Alpha systems
to distinguish the status value from those of other operating systems.
This field indicates the particular programming language or system associated
with the value.
This field serves the same routine as facility_dependent_1.
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:
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.
The following ExceptionFlags bits are detail flags that give
additional details:
If EXCEPTION_NONCONTINUABLE is 1, an exception handler must
not return ExceptionContinueExecution.
If EXCEPTION_EXIT_UNWIND is 1, the exception handler is being
invoked because of an unwind operation that will terminate execution of the
thread.
If EXCEPTION_UNWINDING is 1, the exception handler is being
invoked because of a general unwind operation with the semantics of longjmp().
The following ExceptionFlags bits are environment flags that
give additional information about the environment at the time of exception
delivery:
If EXCEPTION_NESTED_CALL is 1, an exception or unwind is
in progress at the time this exception is delivered.
If EXCEPTION_STACK_INVALID is 1, the stack is invalid.
Note that this flag is for use by system software; it will never be
1 in an exception record delivered to a normal handler.
If EXCEPTION_TARGET_UNWIND is 1, this frame is the target
frame of an unwind operation. (This flag can be useful in allowing a language-specific
handler to perform proper handling for the last step of an unwind.)
If EXCEPTION_COLLIDED_UNWIND is 1, an unwind collision has
occurred. (See Section 5.2.5 for information
on multiply active unwind operations).
All FLAGS bits other than those defined in the preceding
lists must be zero.
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.
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.
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.
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.
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.
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.
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.5.1.1 Exception Handling Requirements
This Digital UNIX calling standard supports the following exception
handling capabilities:
5.1.2 Exception Handling Overview
When an exception occurs (is
raised), the following events take place:
5.1.3 Kinds of Exceptions
There are three kinds of exceptions:
5.1.3.1 General Exceptions
General exceptions are
divided into two categories:
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.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.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: Status Value Representation
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.
Figure 5-2: Exception Record Format
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.5.1.5.2 Exception Records for Unwind Exceptions
Unwind exceptions
have at least one of the following flags set to 1:
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.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.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.)Note
5.1.8 Raising Exceptions
This section describes the four ways
of raising exceptions.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 |
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.
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:
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.
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.
5.1.8.3 Raising Unwind Exceptions
The mechanism used to raise an
unwind exception is described in detail in Section 5.2.
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.
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.
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:
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.
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).
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.
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.
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:
5.1.9.1 Invocation Order for Exception Handlers
When an exception
is raised, established exception handlers are invoked in a specific order.
Figure 5-3: Procedure Invocation Chain
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. |
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. |
This field contains the program counter (PC) where control left the establisher of the exception handler; that is, the PC of the call instruction or the instruction that caused the exception. This field can be updated by a handler. If a nested exception occurs during unwinding while the handler is still active, the value of the PC used for the establisher will be the updated value of ControlPC. This mechanism can be employed to retire nested exception handling scopes that are local to a procedure in order to assure that each is executed only once at most (even in the presence of a nested exception within such a handler). The ControlPC value must, however, always be an address within the procedure whose handler is executing.
This field is a quadword whose meaning is determined by the handler. Typically, a language-specific handler will write new values into this field as it processes nested scopes. If a colliding unwind occurs, the dispatcher sets collide_info to the value it had for the establisher. A handler knows to read this field when EXCEPTION_COLLIDED_UNWIND is 1. This field can be used in the same manner as the ControlPC field to retire nested exception scopes, but it does not have to be an address within the current procedure.
This field contains a pointer to the procedure descriptor for the establisher. The field is read-only to exception handlers, except for handlers for the exception dispatcher itself.
The effects of a handler-modifying passed exception information are
as follows:
If ExceptionContinueExecution is returned after the EXCEPTION_NONCONTINUABLE flag has been changed from 0 to 1, a nested
exception is raised with ExceptionCode equalling EXC_STATUS_NONCONTINUABLE_EXCEPTION, indicating that an attempt was made to continue from a noncontinuable
exception. This second exception is also noncontinuable.
However, an exception handler must not change the EXCEPTION_NONCONTINUABLE flag from 1 to 0.
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.
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.
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.
The rules for bounding the exception range are as follows:
Rationale: This rule is required because a standard
procedure is not allowed to handle traps that it might not have caused.
Rationale: This rule is required because handlers
established by previous invocations in the call chain might not be able to
handle exceptions from a procedure invocation that is no longer active.
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.
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.
This special signal handler gathers the software and/or hardware information
associated with a signal into an exception record where ExceptionCode.osf_facility is EXC_SIGNAL (ffe0003(hex)), ExceptionCode.code
is the signal value, and ExceptionInformation[0] contains any signal
qualifier. This record is passed to the exception-handling support code in
a form that can be processed by normal exception handlers. The exception-handling
code then proceeds with its normal search and invocation of procedures as
described in Section 5.1.2.
If any handler returns with ExceptionContinueExecution (as
described in Section 5.1.2), thread execution
resumes at the point where it was interrupted by the signal.
If no exception handlers are located or if all handlers reraise the
exception, the system's last chance handler is invoked with unpredictable (in this case, system-dependent) results.
If it is useful, applications and language run-time support code can
install exc_raise_signal_exception()
for other signals, such as SIGINT. However, such actions might not be appropriate for signals that
result from external autonomous events or signals, like SIGIO,
that are used for flow control.
Explicit unblocking is necessary if a handler itself might cause a blocked
signal to occur. Similarly, explicit unblocking might be needed if the same
signal is raised in two threads and must be processed by procedure-based exception
handling at the same time; for example, when one thread cannot wait for the
other thread to complete its exception handling.
This section discusses the following topics:
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.
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.
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.
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.
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.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.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.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.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.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.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:
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.
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.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.
exc_raise_signal_exception
(... system-defined-arguments ...)
5.2 Unwinding
The unwinding capabilities
specified in this section support the following:
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.5.2.2 Types of Unwind Operations
There are two types of unwind requests: general and exit. The following
sections describe each type.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.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.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.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.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.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. |
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.
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.
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.
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.
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.
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.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.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.5.2.6 Unwind Completion
When an unwind is completed,
the following conditions are in effect:
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.Note