HP OpenVMS Systems Documentation
OpenVMS Calling Standard
6.7 Request to Unwind from a Signal
To unwind, the handler or any procedure that it calls can make a call to SYS$UNWIND. The format is as follows:
Function Value Returned:
The depadr argument specifies the address of the longword that contains the number of presignal frames (depth) to be removed. The deepest procedure invocation whose frame is not removed is called the target invocation of the unwind. If that number is less than or equal to 0, nothing is to be unwound. The default (address = 0) is to return to the caller of the procedure that established the handler that issued the $UNWIND service. To unwind to the establisher, specify the depth from the call to the handler, which can be found in the CHF$IS_MCH_DEPTH field of the Mechanism Array. When the handler is at depth 0, it can achieve the equivalent of an unwind operation to an arbitrary place in its establisher by altering the PC in its signal_args vector and returning with SS$_CONTINUE, or SS$_CONTINUE64 if the 64-bit signal vector is altered, instead of performing an unwind.
The new_PC argument specifies the location to receive control when the unwinding operation is complete. The default is to continue at the instruction following the call to the last procedure activation that is removed from the stack.
The function value success either is a standard success code (SS$_NORMAL) or it indicates failure with one of the following return status condition values:
If SYS$UNWIND is invoked by a handler that has already invoked SYS$UNWIND, then the effect of the second invocation is undefined.
The unwinding operation occurs when the handler returns to the CHF. Unwinding is done by scanning back through the stack and calling each handler associated with a frame. The handler is called with the exception SS$_UNWIND to perform any application-specific cleanup. If the depth specified includes unwinding the establisher's frame, the current handler is recalled with this unwind exception.
When the target invocation is reached on Alpha systems, unwind completion depends on the PDSC$V_TARGET_INVO flag of the associated procedure descriptor. If that flag is set to 1, then the handler for that procedure invocation is called; otherwise, no handler is called. Control then resumes in the target invocation.
The call to the handler takes the same form as described in Section 6.5.1 with the following values:
After each handler is called, the stack is logically cut back to the previous frame.
On Alpha systems, the stack is not actually cut back until after the last handler is called.
The exception vectors are not checked because they are not being removed. Any function value from the handler is ignored.
To specify the value of the top-level function being unwound, the handler should modify the appropriate saved register locations in the mechanism_args vector. They are restored from the mechanism_args vector at the end of the unwind.
Depending on the arguments to SYS$UNWIND, the unwinding operation is terminated as follows:
The only recommended values for depth are the default (address of 0), which unwinds to the caller of the establisher, and the value of depth taken from the mechanism vector, which unwinds to the establisher. Other values depend on implementation details that can change at any time.
You can call SYS$UNWIND whether the condition was a software exception
signaled by calling LIB$SIGNAL or LIB$STOP or was a hardware exception.
Calling SYS$UNWIND is the only way to continue execution after a call
On VAX systems, to find registers R2 through FP, a scan of stack frames must be performed starting with the current frame and ending with the call to the handler. During the scan, the last frame found to save a register contains that register's contents at the time of the exception. If no frame saved the register, the register is still active in the current procedure. The frame of the call to the handler can be identified by the return address of SYS$CALL_HANDL+4. In this case, the registers are in the following states:
On VAX systems, the values that exist in R0 and R1 when the unwind completes are the values passed implicitly to the unwinder in the mechanism array (see Section 18.104.22.168). If desired, these values can be modified by an exception handler before the unwind is initiated.
On Alpha systems, the values that exist in R0, R1, F0, and F1 when the
unwind completes are the values passed implicitly to the unwinder in
the mechanism array (see Section 22.214.171.124). If desired, these values can
be modified by an exception handler before the unwind is initiated.
Note that, unlike VAX systems, an Alpha system does not use R1 for
returning any type of return values.
A GOTO unwind is a transfer of control that leaves one procedure invocation and continues execution in a prior, currently active procedure invocation. Modular and reliable support of the nonlocal GOTO requires procedure invocations that are terminated to have an opportunity to clean up in an orderly way (just like a procedure that is terminated as a result of an unwind from a condition handler).
Performing a GOTO unwind operation in a thread causes a transfer of control from the location at which the GOTO unwind operation is initiated to a target location in a target invocation. This transfer of control also 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 being terminated. These handlers are invoked with an indication of an unwind in progress. This gives each procedure invocation being terminated the chance to perform cleanup processing before its context is lost.
When the target invocation is reached, unwind completion depends on the PDSC$V_TARGET_INVO flag of the associated procedure descriptor. If that flag is set to 1, then the handler for that procedure invocation is called; otherwise, no handler is called.
After 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.
A GOTO unwind procedure can be initiated while an exception is active (from within a condition handler) or while no exception is active. If the GOTO unwind transfers control out of an exception handler (resulting in the termination of current handler invocation), it also terminates handling of the corresponding condition (like SYS$UNWIND).
A GOTO unwind operation in which a target invocation is not specified is called an exit unwind. An exit unwind is just like a GOTO unwind except that every procedure invocation in the currently executing thread is terminated. An exit unwind is the only standard way to terminate execution of the currently executing thread (other than a normal return from the topmost procedure of the thread).
Condition Value Returned:
When a GOTO unwind is initiated, control usually 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 is
invoked by a handler that has already invoked SYS$UNWIND, then the
effect of calling SYS$GOTO_UNWIND is undefined.
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 (see Sections 3.4.2 and 3.4.5.) These handlers are invoked in the reverse order from which they were established.
Since 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 or exit unwind procedure, each handler that is invoked is called with two arguments as follows:
When an unwind completes, the following conditions are true:
6.9 Multiple Active Signals
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 Alpha 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).
For both Alpha and VAX 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 processor, 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 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
During an unwind operation (resulting from either SYS$GOTO_ UNWIND or SYS$UNWIND), another unwind operation can be initiated (using either 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 6.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.