|
HP OpenVMS systems documentation |
Previous | Contents | Index |
Arguments:
target_invo
Address of a location that contains a handle for the target invocation. If omitted or the address of the handle is zero, then the effect of the call is undefined. |
|
target_pc
Address of a location that contains the address at which execution should continue in the target invocation. If omitted or if the address is 0, then execution resumes at the location specified by the return address for the call frame of the target procedure invocation. If the target_invo argument is omitted or is 0, then this argument is ignored. In this case, a system-defined target PC is assumed. |
|
NewRetVal
Address of a location that contains the value to place in the saved RetVal location of the mechanism argument vector. The contents of this location are then loaded into RetVal at the time that execution continues in the target invocation. If this argument is omitted, then the contents of RetVal at the time of the call to SYS$GOTO_UNWIND_64 are used. This argument is called New_R0 in SYS$GOTO_UNWIND for compatibility with Alpha. |
|
NewRetVal2
Address of a location that contains the value to place in the saved RetVal2 location of the mechanism argument vector. The contents of this location are then loaded into RetVal2 at the time that execution continues in the target invocation. If this argument is omitted, then the contents of RetVal2 at the time of the call to SYS$GOTO_UNWIND_64 are used. This argument is called New_R1 in SYS$GOTO_UNWIND for compatibility with Alpha. |
Condition Value Returned:
SS$_ACCVIO
An invalid address was given. |
When a GOTO unwind is initiated, control almost never returns to the
point at which the unwind was initiated. Control returns with an error
status only if a GOTO unwind cannot be started. If SYS$GOTO_UNWIND_64
(or SYS$GOTO_UNWIND) is invoked by a handler that has already invoked
SYS$UNWIND, then the effect of calling SYS$GOTO_UNWIND_64 (or
SYS$GOTO_UNWIND) is undefined.
8.8.1 Handler Invocation During a GOTO Unwind
When an unwind operation takes place, all frame-based exception handlers are invoked that were established by any procedure invocation being terminated. In addition, the handler for the target procedure invocation is called if the PDSC$V_TARGET_INVO flag is set in the corresponding procedure descriptor or unwind information (see Sections 3.4.2, 3.4.5 and A.4.3.) These handlers are invoked in the reverse order from which they were established.
Because primary, last-chance handlers, and the system catchall handler are not associated with a normal procedure invocation, these handlers are never invoked during an unwind (but they are invoked if an exception is raised during the unwind operation).
For a GOTO unwind procedure, each handler that is invoked is called with two arguments as follows:
(* handler) (signal_args, mechanism_args) |
Argument | OpenVMS Usage | Type | Access | Mechanism |
---|---|---|---|---|
signal_args | signal vector | structure | modify | by reference |
mechanism_args | mechanism vector | structure | modify | by reference |
Arguments:
signal_args
Argument count of 2, followed by a condition value of SS$_UNWIND, followed by:
|
|
mechanism_args
Mechanism argument corresponding to the frame being unwound, as defined in Section 8.5.1.2. |
For information about signal argument and mechanism argument vectors,
see Sections 8.5.1.1 and 8.5.1.2.
8.8.2 Unwind Completion
When an unwind completes, the following conditions are true:
A signal is said to be active until the signaler gets control again or is unwound. A signal can occur while a condition handler or a procedure it has called is executing in response to a previous signal. For example, procedures A, B, and C establish condition handlers Ah, Bh, and Ch. If A calls B and B calls C, which signals S, and Ch resignals, then Bh gets control.
If Bh calls procedure X, and X calls procedure Y, and Y signals T, the stack is as follows:
The handlers are searched for in the following order: Yh, Xh, Bhh, Ah. Bh is not called again because it is not appropriate to assume that a routine is able to be its own handler. However, Bh can establish itself or another procedure as its handler (Bhh).
On VAX systems, Ch is not checked or called because it is a structural descendant of B.
On Alpha or I64 systems, the search does check handlers Ch and Bh between calling Bhh and Ah. These handlers will be reinvoked only if enabled by the HANDLER_REINVOCABLE flag of the establisher's procedure descriptor (see Sections 3.4.1 and 3.4.4) or unwind information (see Section A.4.3).
For all systems, the following algorithm is used on the second and subsequent signals that occur before the handler for the original signal returns to the Condition Handling Facility. The primary and secondary exception vectors are checked. However, the search backward in the process stack is then modified. On a VAX processor, the stack frames traversed in the first search are skipped, in effect, during the second search, while on an Alpha or I64 system, the stack frames are skipped unless they explicitly enable handler reinvocation. Therefore, the stack frame preceding the first condition handler, up to and including the frame of the procedure that has established the handler, is skipped. In the VAX environment, frames that are skipped are not counted in the depth. In the Alpha or I64 environment, all frames are counted in the depth.
For example, the stack frames traversed in the first and second searches are skipped in a third search. Note that if a condition handler signals, it is not automatically invoked recursively. However, if a handler itself establishes a handler, the second handler is invoked. Therefore, a recursive condition handler should start by establishing itself. Any procedures invoked by the handler are treated in the normal way; that is, exception signaling follows the stack up to the condition handler.
If an unwind operation is requested while multiple signals are active, all the intermediate handlers are called for the operation. For example, in the preceding diagram, if Ah specifies unwinding to A, the following handlers are called for the unwind: Yh, Xh, Bhh, Ch, and Bh.
For proper hierarchical operation, an exception that occurs during
execution of a condition handler established in an exception vector
should be handled by that handler rather than propagating up the
activation stack. To prevent such propagation, the vectored condition
handler should establish a handler in its stack frame to handle all
exceptions.
8.10 Multiple Active Unwind Operations
During an unwind operation (resulting from a call of SYS$GOTO_UNWIND_64, SYS$GOTO_UNWIND, or SYS$UNWIND), another unwind operation can be initiated (using SYS$GOTO_UNWIND_64, SYS$GOTO_UNWIND, or SYS$UNWIND). This can occur, for example, if a handler that is invoked for 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 initiates another unwind operation. However, SYS$UNWIND cannot be called from a handler that is invoked as part of an unwind (see Section 8.7), but it can be called from a handler for a nested exception.
An unwind that is initiated while a previous unwind is active is either a nested unwind or an overlapping unwind.
A nested unwind is an unwind that is initiated while a previous unwind is active and whose target invocation in the procedure invocation chain is not a predecessor of the most current active unwind handler. 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, and 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.
An overlapping unwind is an unwind that is initiated while a previous unwind is active and whose target invocation in the procedure invocation chain is a predecessor of the most current active unwind handler. An overlapping unwind terminates one or more procedure invocations that would have been terminated by the previously active unwind.
An overlapping unwind is detected when the most current active unwind handler is terminated. This detection of an overlapping unwind is termed an unwind collision.
When a GOTO unwind collides with a GOTO unwind, the later unwind supersedes the earlier unwind, which is abandoned. The later unwind then continues from the point of the collision.
The result of any other collision is undefined.
Stack unwinding is the process of tracing backwards through the stack of invocation contexts of a thread. Every active procedure has one invocation context. An invocation context has memory (a frame) on the register stack, the memory stack, or both. To trace backwards through the stack of invocation contexts, it must be possible to identify each invocation context and its associated frames. Exception handling often requires the ability to trace backwards through a number of invocation contexts and then to transfer control to an exception handling routine.
For the register stack, the state of the current register stack frame together with the AR.PFS register provides sufficient information to identify the previous frame. However, this works for only one level of nesting, because there is no hardware stack of AR.PFS registers. To make it possible to unwind the register stack, this calling standard defines a convention for saving and recovering the AR.PFS register in each frame.
For the memory stack, it is expected that most procedures will allocate a frame that does not change in size while the procedure is active. For these procedures, the fixed frame size is recorded in a static unwind table, and the instruction pointer (PC) is used as a key into this table.
To make it possible to unwind frames that vary in size, this calling standard defines a convention for saving and recovering the SP value for the previous frame on the stack.
As the register and memory stacks are unwound, it is also necessary to recover the values of preserved registers that were saved by each procedure for the following uses:
This calling standard defines a convention for saving and recovering the values of these preserved registers. This convention uses the PC as a key for locating a static unwind table entry that contains everything necessary for locating the following values:
Unwinding the stack is done using system routines (see Section 4.8.3) that can be called from the thread itself, from a debugger, or for exception handling. Stack unwinding operates on context records; the primary routine reconstructs the context for a previous frame given the context for its descendent frame.
This appendix describes the following topics:
The process of unwinding the stack begins with an initial context
record that describes the process state in the most recent procedure
invocation at the point of interruption. From this initial state, the
stack is unwound one invocation context at a time, using static
information generated by the compilers about each procedure to
reconstruct a context record that describes the previous procedure
(which is suspended at a point just after the procedure call or an
asynchronous interruption).
A.1.1 Initial Context
There is only one way to get an initial context: call
LIB$I64_GET_CURR_INVO_CONTEXT (see Section 4.8.3.7).
A.1.2 Step to Previous Frame
The unwind routines build a context record that corresponds to the next older frame on the stack. This context record can then be used to unwind to the previous frame on the stack. The following steps reconstruct the context for the previous frame using information in the unwind tables for the current frame:
The bottom of the call stack is identified by a BOTTOM_OF_STACK flag in the context block.
The information needed to execute these steps correctly is recorded in static unwind information that is associated with each code segment of the program itself. The structure of this information is described in Section A.4. Each code segment has an associated table of static unwind information, and the operating system provides an API for finding the unwind table, given a known PC (see Section A.6).
When a thread receives an asynchronous interruption, the thread context
is saved so that the thread can continue executing correctly once the
interruption has been handled. This context is saved on the memory
stack, and a new procedure frame is constructed for the interruption
handler. The first procedure frame in the interruption handler is
marked in such a way that the unwind routine can recognize that
unwinding past the point of interruption requires a restoration of the
full context.
A.2 Exception Handling Framework
The exception handling model for OpenVMS is partitioned into a language-independent component and a language-dependent component. The language-independent component is responsible for fielding an exception, searching for and dispatching to a condition handler and unwinding the stack. The run-time library of each source language that supports exception handling must provide a condition handler that implements the language-dependent component of this model.
For compatibility with the OpenVMS VAX and Alpha calling standards, this document uses the term condition handler, rather than the term personality routine. |
The exception handling model is oriented around procedure invocation contexts. Each invocation context corresponds to an activation of a procedure, which may or may not have associated exception handling requirements. A language typically uses a single condition handler for all procedures, but this is not a requirement.
Exceptions are signalled by invoking a routine in the language-independent component called the exception dispatcher, which initiates the process of handling the exception. Synchronous exceptions can be signalled directly by the application through a language-specific construct; asynchronous exceptions can be signalled in response to hardware-detected traps or faults.
The exception dispatcher walks the stack of invocation contexts non-destructively beginning with the most recent invocation, searching for the first invocation context with a condition handler. When a condition handler is found, the exception dispatcher invokes the condition handler.
A condition handler may perform the following actions:
If the condition handling facility finds a handler for the exception that requests an unwind, it invokes the dispatcher to walk the stack a second time. During the second walk, the dispatcher invokes the condition handler for each frame again to execute cleanup actions as necessary. When the dispatcher reaches the frame that contains the condition handler, control is transferred to the condition handler.
For more details about OpenVMS condition handling, see Chapter 8.
A.3 Coding Conventions for Reliable Unwinding
This section describes the coding conventions that must be observed to guarantee that the stacks can be unwound from every point in the program. For the purposes of unwinding, this calling standard divides every procedure into one or more regions, which are classified as either prologue or body regions.
A prologue region is one where the register stack and memory stack frames are established and where key registers are saved. To unwind correctly when the PC is one of these regions, the unwinder must have a detailed description of the order of operations within the region, so that it knows what state has changed, and which registers have been saved at any given point in that region.
A body region is one for which the register stack and
the memory stack are fully formed and initialized. Although a body
region can change the state of the stack frame and save and restore
preserved registers (for example, to shrink-wrap the
save and restore of a register), the unwind data structures are tuned
for body regions that have few such operations.
A.3.1 Requirements for Unwinding the Stack
Certain constraints must be met in order to unwind the stack successfully at any time, both by standard procedure calls as described in Chapter 4, and by special-purpose calling conventions. Appendix B describes the format of the unwind data structures. To meet the needs of the stack unwind mechanism, the following rules must be followed at all times:
The following sections provide detailed conventions for satisfying
these requirements.
A.3.2 Conventions for Prologue Regions
A typical prologue region performs some or all of the following steps:
The unwinder must also know where preserved registers are saved in the memory stack frame, because it must reconstruct the values of these registers as it unwinds the stack. The conventions for the spill area are discussed in Section A.3.5.
A prologue region can contain code that is irrelevant to the unwind process. However, for efficiency during the unwind process, observe the following guidelines:
When OpenVMS semantics apply (see Section A.4.1), a condition handler will not be called for an exception that occurs in a prologue or epilogue because the procedure is not current (see Section 4.8.1), but a condition handler of the caller will be considered. Therefore, a prologue region can not occur in the interior of a procedure, except for a zero-length prologue that describes the initial state for noncontiguous code segments. General unwind descriptors must be used in the interior of a procedure instead of prologue descriptors (see Section A.4.1.3) to describe needed changes in unwind state.
For a routine that has no condition handler, there is no restriction on the use of prologue descriptors, even interior to the body.
Previous | Next | Contents | Index |