In addition to handling exceptions, exception handlers are used to clean up resources during the execution of a nonlocal GOTO instruction or during thread termination. (A nonlocal GOTO instruction jumps to a label outside the current procedure. The label is a procedure address or an address within a procedure that is on the stack, higher in the call frame chain.)
DosUnwindException calls and removes exception handlers from a thread's chain of registered exception handlers up to, but not including, a specified exception handler. This is known as an unwind operation. DosUnwindException can also be used to unwind all exception handlers from the thread's exception handler chain and to terminate the thread.
For example, with the C language setjmp() and longjmp() routines, the setjmp() would save the address of the current exception handler structure, along with any other information that is necessary to perform the longjmp() routine. (The address of the current exception handler structure is obtained from the head of the exception handler chain. A pointer to the head of the chain is located in the Thread Information Block.)
The longjmp() routine would initiate the unwind of procedure call frames by calling DosUnwindException and passing to it the saved address of the EXCEPTIONREGISTRATIONRECORD data structure. If the address of the EXCEPTIONREGISTRATIONRECORD data structure is not found in the chain, then the XCPT_INVALID_UNWIND_TARGET exception is raised, and the chain is not unwound.
The machine state at the time of the call to DosUnwindException is captured in ContextRecord. The EH_UNWINDING flag is set in the exception flags field of the EXCEPTIONREPORTRECORD data structure. The EH_EXIT_UNWIND flag is also set if the EXCEPTIONREGISTRATIONRECORD parameter is set to 0 (if the application does not provide its own EXCEPTIONREPORTRECORD parameter OS/2 will construct one). A backward walk through the procedure call frames is then performed to find the target of the unwind operation.
Note: Even though a ContextRecord is used to capture the state of the machine, unwinding is not considered an exception. It is simply delivered through the exception mechanism.
The first parameter to DosUnwindException is the address of an exception handler's EXCEPTIONREGISTRATIONRECORD. DosUnwindException will unwind exception handlers up to, but not including that exception handler. If a -1 is passed to DosUnwindException for this parameter, DosUnwindException will unwind all the exception handlers on the chain. If a 0 is passed to DosUnwindException for this parameter, DosUnwindException will unwind all the exception handlers on the chain and exit.
There is no return from a call to DosUnwindException, unless the stack is invalid. Control is transferred to the specified instruction pointer address. If DosUnwindException encounters an error during its processing, it raises another exception rather than return control to the caller.
If the target call frame is reached and an exit unwind is not being performed (that is, an EXCEPTIONREGISTRATIONRECORD is not 0), then the computed machine state is restored from ContextRecord and control is transferred to the address specified by the target-IP address parameter. Note that the stack pointer is not restored, making it possible to transfer information on the stack. It is the responsibility of the code at the target address to reset the stack pointer as necessary.
DosUnwindException is called with C language calling conventions, which permits the use of a variable number of arguments. Thus, the caller can pass any amount of information on the stack, to be picked up at the target-IP address.
If an exit unwind is being performed (the EXCEPTIONREGISTRATIONRECORD parameter is 0), then all call frames are unwound until the base of the stack is reached.
If the EXCEPTIONREPORTRECORD parameter is specified, then each exception handler encountered during the unwind operation is called, using the specified record. If this parameter is not specified, then DosUnwindException constructs an EXCEPTIONREPORTRECORD that specifies the exception XCPT_UNWIND.
Colliding Unwinds
During an unwind operation, it is possible for one unwind to collide with
a previous unwind. This occurs when the scope of the second unwind overlaps
the scope of the first unwind. Following are two situations:
Either of these situations could occur during the following scenarios:
In the first scenario, the second unwind is attempting to unwind to an invalid target. This causes the exception XCPT_INVALID_UNWIND_TARGET to be raised.
In the second scenario, the first unwind is abandoned, and the second unwind continues to its target. The second scenario is far more likely.
Note: A user program that uses high level language exception mechanisms must never call DosUnwindException, because this could create conflicts with the runtime exception strategy of the high level language. Unwind operations in this case are performed through language-supported facilities such as the C language longjmp() routine.