Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

### 9.12.1 Continuing Execution

To continue execution from the instruction following the signal, with no error messages or traceback, the handler returns with the function value SS$_CONTINUE (bit <0> = 1). If, however, the condition was signaled with a call to LIB$STOP, the SS$_CONTINUE return status causes an error message (Attempt To Continue From Stop), and the image exits. The only way to continue from a call to LIB$STOP is for the condition handler to request a stack unwind.

If execution is to continue after a hardware fault (such as a reserved operand fault), the condition handler must correct the cause of the condition before returning the function value SS$_CONTINUE or requesting a stack unwind. Otherwise, the instruction that caused the fault executed again.

Note On most VAX systems, hardware floating-point traps have been changed to hardware faults. If you still want floating-point exception conditions to be treated as traps, use LIB$SIM_TRAP to simulate the action of floating-point traps.

On Alpha systems, LIB$SIM_TRAP is not supported. Table 9-4 lists the run-time library routines that are supported and not supported on Alpha systems.

### 9.12.2 Resignaling

Condition handlers check for specific errors. If the signaled condition is not one of the expected errors, the handler resignals. That is, it returns control to the OpenVMS Condition Handling facility with the function value SS$_RESIGNAL (with bit <0> clear). To alter the severity of the signal, the handler modifies the low-order 3 bits of the condition value and resignals.

For an example of resignaling, see Section 9.8.5.

### 9.12.3 Unwinding the Call Stack

A condition handler can dismiss the signal by calling the system service SYS$UNWIND. The stack unwind is initiated when a condition handler that has called SYS$UNWIND returns to OpenVMS Condition Handling facility. For an explanation of unwinding, see Section 9.10.1; for an example of using SYS$UNWIND to return control to the program, see Section 9.12.4.5.

### 9.12.4 Example of Writing a Condition Handler

The operating system passes two arrays to a condition handler. Any condition handler that you write should declare two dummy arguments as variable-length arrays, as in the following:

    INTEGER*4 FUNCTION HANDLER (SIGARGS,
    2                           MECHARGS)

    INTEGER*4 SIGARGS(*),
    2         MECHARGS(*)
       .
       .
       .

#### 9.12.4.1 Signal Array

The first dummy argument, the signal array, describes the signaled condition codes that indicate which error occurred and the state of the process when the condition code was signaled. For the structure of the signal array, see Section 9.8.2.

#### 9.12.4.2 Mechanism Array

The second dummy argument, the mechanism array, describes the state of the process when the condition code was signaled. Typically, a condition handler references only the call depth and the saved function value. Currently, the mechanism array contains exactly five elements; however, because its length is subject to change, you should declare the dummy argument as a variable-length array. For the structure of the mechanism array, see Section 9.8.3.

Usually you write a condition handler in anticipation of a particular set of condition values. Because a handler is invoked in response to any signaled condition code, begin your handler by comparing the condition code passed to the handler (element 2 of the signal array) against the condition codes expected by the handler. If the signaled condition code is not one of the expected codes, resignal the condition code by equating the function value of the handler to the global symbol SS$_RESIGNAL.

#### 9.12.4.3 Comparing the Signaled Condition with an Expected Condition

You can use the RTL routine LIB$MATCH_COND to compare the signaled condition code to a list of expected condition values. The first argument passed to LIB$MATCH_COND is the signaled condition code, the second element of the signal array. The rest of the arguments passed to LIB$MATCH_COND are the expected condition values. LIB$MATCH_COND compares the first argument with each of the remaining arguments and returns the number of the argument that matches the first one. For example, if the second argument matches the first argument, LIB$MATCH_COND returns a value of 1. If the first argument does not match any of the other arguments, LIB$MATCH_COND returns 0.

The following condition handler determines whether the signaled condition code is one of four Compaq Fortran I/O errors. If it is not, the condition handler resignals the condition code. Note that, when a Compaq Fortran I/O error is signaled, the signal array describes operating system's condition code, not the Compaq Fortran error code.

    INTEGER FUNCTION HANDLER (SIGARGS,
    2                         MECHARGS)

    ! Declare dummy arguments
    INTEGER*4 SIGARGS(*),
    2         MECHARGS(*)
    INCLUDE '($FORDEF)'   ! Declare the FOR$_ symbols
    INCLUDE '($SSDEF)'    ! Declare the SS$_ symbols
    INTEGER INDEX
    ! Declare procedures
    INTEGER LIB$MATCH_COND
    INDEX = LIB$MATCH_COND (SIGARGS(2),
    2                       FOR$_FILNOTFOU,
    2                       FOR$_OPEFAI,
    2                       FOR$_NO_SUCDEV,
    2                       FOR$_FILNAMSPE)
    IF (INDEX .EQ. 0) THEN
      ! Not an expected condition code, resignal
      HANDLER = SS$_RESIGNAL
    ELSE IF (INDEX .GT. 0) THEN
      ! Expected condition code, handle it
       .
       .
       .
    END IF

    END

#### 9.12.4.4 Exiting from the Condition Handler

You can exit from a condition handler in one of three ways:

- Continue execution of the program---If you equate the function value of the condition handler to SS$_CONTINUE, the condition handler returns control to the program at the statement that signaled the condition (fault) or the statement following the one that signaled the condition (trap). The RTL routine LIB$SIGNAL generates a trap so that control is returned to the statement following the call to LIB$SIGNAL.
  In the following example, if the condition code is one of the expected codes, the condition handler displays a message and then returns the value SS$_CONTINUE to resume program execution. ( Section 9.11 describes how to display a message.)

      INTEGER FUNCTION HANDLER (SIGARGS,
      2                         MECHARGS)

      ! Declare dummy arguments
      INTEGER*4 SIGARGS(*),
      2         MECHARGS(*)
      INCLUDE '($FORDEF)'
      INCLUDE '($SSDEF)'
      INTEGER*4 INDEX,
      2         LIB$MATCH_COND
      INDEX = LIB$MATCH_COND (SIGARGS(2),
      2                       FOR$_FILNOTFOU,
      2                       FOR$_OPEFAI,
      2                       FOR$_NO_SUCDEV,
      2                       FOR$_FILNAMSPE)
      IF (INDEX .GT. 0) THEN
         .
         .
         .
                    ! Display the message
         .
         .
         .
        HANDLER = SS$_CONTINUE
      END IF

- Resignal the condition code---If you equate the function value of the condition handler to SS$_RESIGNAL or do not specify a function value (function value of 0), the handler allows the operating system to execute the next condition handler. If you modify the signal array or mechanism array before resignaling, the modified arrays are passed to the next condition handler.
  In the following example, if the condition code is not one of the expected codes, the handler resignals:

      INDEX = LIB$MATCH_COND (SIGARGS(2),
      2                       FOR$_FILNOTFOU,
      2                       FOR$_OPEFAI,
      2                       FOR$_NO_SUCDEV,
      2                       FOR$_FILNAMSPE)

      IF (INDEX .EQ. 0) THEN
        HANDLER = SS$_RESIGNAL
      END IF

- Continue execution of the program at a previous location---If you call the SYS$UNWIND system service, the condition handler can return control to any point in the program unit that incurred the exception, the program unit that invoked the program unit that incurred the exception, and so on back to the program unit that established the condition handler.

#### 9.12.4.5 Returning Control to the Program

Your handlers should return control either to the program unit that established the handler or to the program unit that invoked the program unit that established the handler.

To return control to the program unit that established the handler, invoke SYS$UNWIND and pass the call depth (third element of the mechanism array) as the first argument with no second argument.

    ! Declare dummy arguments
    INTEGER*4 SIGARGS(*),
    2         MECHARGS(*)
       .
       .
       .
    CALL SYS$UNWIND (MECHARGS(3),)

To return control to the caller of the program unit that established the handler, invoke SYS$UNWIND without passing any arguments.

    ! Declare dummy arguments
    INTEGER*4 SIGARGS(*),
    2         MECHARGS(*)
       .
       .
       .
    CALL SYS$UNWIND (,)

The first argument SYS$UNWIND specifies the number of program units to unwind (remove from the stack). If you specify this argument at all, you should do so as shown in the previous example. (MECHARGS(3) contains the number of program units that must be unwound to reach the program unit that established the handler that invoked SYS$UNWIND.) The second argument SYS$UNWIND contains the location of the next statement to be executed. Typically, you omit the second argument to indicate that the program should resume execution at the statement following the last statement executed in the program unit that is regaining control.

Each time SYS$UNWIND removes a program unit from the stack, it invokes any condition handler established by that program unit and passes the condition handler the SS$_UNWIND condition code. To prevent the condition handler from resignaling the SS$_UNWIND condition code (and so complicating the unwind operation), include SS$_UNWIND as an expected condition code when you invoke LIB$MATCH_COND. When the condition code is SS$_UNWIND, your condition handler might perform necessary cleanup operations or do nothing.

In the following example, if the condition code is SS$_UNWIND, no action is performed. If the condition code is another of the expected codes, the handler displays the message and then returns control to the program unit that called the program unit that established the condition handler.

    INTEGER FUNCTION HANDLER (SIGARGS,
    2                         MECHARGS)

    ! Declare dummy arguments
    INTEGER*4 SIGARGS(*),
    2         MECHARGS(*)
    INCLUDE '($FORDEF)'
    INCLUDE '($SSDEF)'
    INTEGER*4 INDEX,
    2         LIB$MATCH_COND
    INDEX = LIB$MATCH_COND (SIGARGS(2),
    2                       SS$_UNWIND,
    2                       FOR$_FILNOTFOU,
    2                       FOR$_OPEFAI,
    2                       FOR$_NO_SUCDEV,
    2                       FOR$_FILNAMSPE)
    IF (INDEX .EQ. 0) THEN
      ! Unexpected condition, resignal
      HANDLER = SS$_RESIGNAL
    ELSE IF (INDEX .EQ. 1) THEN
      ! Unwinding, do nothing
    ELSE IF (INDEX .GT. 1) THEN
       .
       .
       .
                  ! Display the message
       .
       .
       .
      CALL SYS$UNWIND (,)
    END IF

### 9.12.5 Example of Condition-Handling Routines

The following example shows two procedures, A and B, that have declared condition handlers. The notes describe the sequence of events that would occur if a call to a system service failed during the execution of procedure B.

    /* PGMA */

    #include <stdio.h>
    #include <ssdef.h>

    unsigned int sigargs[],mechargs[];

    main() {
            unsigned int status, vector=0, old_handler;

            old_handler = LIB$ESTABLISH( handlera );               (1)

            status = pgmb (arglst);                                (2)
       .
       .
       .
    }

    /* PGMB */

    #include <stdio.h>
    #include <ssdef.h>

    main() {

     old_handler = LIB$ESTABLISH( handlerb );                      (3)
       .
       .
       .

    }                                                              (4)

    /* Handler A */                                                (5)

    int handlera( sigargs, mechargs ) {

    /* Compare condition value signalled with expected value */
                                                                   (6)
                            if (sigargs[2] != SS$_SSFAIL)
                                    goto no_fail;
       .
       .
       .
    /* Signal to continue */

                            return SS$_CONTINUE;

    /* Signal to resignal */
    no_fail:
                            return SS$_RESIGNAL;

    }

    /* Handler B */

    int handlerb( sigargs, mechargs ) {

    /* Compare condition value signalled with expected value */
                            if (sigargs[2] != SS$_BREAK)              (7)
                                    goto no_fail;
       .
       .
       .
                            return SS$_CONTINUE;

    no_fail:
                            return SS$_RESIGNAL;

    }

1. Procedure A executes and establishes condition handler HANDLERA. HANDLERA is set up to respond to exceptions caused by failures in system service calls.
2. During its execution, procedure A calls procedure B.
3. Procedure B establishes condition handler HANDLERB. HANDLERB is set up to respond to breakpoint faults.
4. While procedure B is executing, an exception occurs caused by a system service failure.
5. The dispatcher returns control to procedure B, and execution of procedure B resumes at the instruction following the system service failure.
6. The exception dispatcher resumes its search for a condition handler and calls HANDLERA.
7. HANDLERA handles the system service failure exception, corrects the condition, places the return value SS$_CONTINUE in R0, and returns control to the exception dispatcher.

## 9.13 Debugging a Condition Handler

You can debug a condition handler as you would any subprogram, except that you cannot use the DEBUG command STEP/INTO to enter a condition handler. You must set a breakpoint in the handler and wait for the debugger to invoke the handler.

Typically, to trace execution of a condition handler, you set breakpoints at the statement in your program that should signal the condition code, at the statement following the one that should signal, and at the first executable statement in your condition handler.

The SET BREAK debugger command with the /HANDLER qualifier causes the debugger to scan the call stack and attempt to set a breakpoint on every established frame-based handler whenever the program being debugged has an exception. The debugger does not discriminate between standard RTL handlers and user-defined handlers.

## 9.14 Run-Time Library Condition-Handling Routines

The following sections present information about Alpha systems RTL jacket handlers, and RTL routines that can be either established as condition handlers or called from a condition handler to handle signaled exception conditions.

### 9.14.1 RTL Jacket Handlers (Alpha Only)

On Alpha systems, many RTLs establish a jacket RTL handler on a frame where the user program has defined its own handler. This RTL jacket does some setup and argument manipulation before actually calling the handler defined by the user. When processing the exception, the debugger sets the breakpoint on the jacket RTL jacket handler, because that is the address on the call stack. If the debugger suspends program execution at a jacket RTL handler, it is usually possible to reach the user-defined handler by entering a STEP/CALL command followed by a STEP/INTO command. Some cases might require that additional sequences of STEP/CALL and STEP/INTO commands be entered. For more information on frame-based handlers, see OpenVMS Calling Standard.

If the jacket RTL handler is part of an installed shared image such as ALPHA LIBOTS, the debugger cannot set a breakpoint on it. In this case, activate the RTL as a private image by defining the RTL as a logical name, as in the following example:

    $DEFINE LIBOTS SYS$SHARE:LIBOTS.EXE;

Note In the previous example, the trailing semicolon (;) is required.

### 9.14.2 Converting a Floating-Point Fault to a Floating-Point Trap (VAX Only)

On VAX systems, a trap is an exception condition that is signaled after the instruction that caused it has finished executing. A fault is an exception condition that is signaled during the execution of the instruction. When a trap is signaled, the program counter (PC) in the signal argument vector points to the next instruction after the one that caused the exception condition. When a fault is signaled, the PC in the signal argument vector points to the instruction that caused the exception condition. See the VAX Architecture Reference Manual for more information about faults and traps.

LIB$SIM_TRAP can be established as a condition handler or be called from a condition handler to convert a floating-point fault to a floating-point trap. After LIB$SIM_TRAP is called, the PC points to the instruction after the one that caused the exception condition. Thus, your program can continue execution without fixing up the original condition. LIB$SIM_TRAP intercepts only floating-point overflow, floating-point underflow, and divide-by-zero faults.

### 9.14.3 Changing a Signal to a Return Status

When it is preferable to detect errors by signaling but the calling routine expects a returned status, LIB$SIG_TO_RET can be used by the routine that signals. For instance, if you expect a particular condition code to be signaled, you can prevent the operating system from invoking the default condition handler by establishing a different condition handler. LIB$SIG_TO_RET is a condition handler that converts any signaled condition to a return status. The status is returned to the caller of the routine that established LIB$SIG_TO_RET. You may establish LIB$SIG_TO_RET as a condition handler by specifying it in a call to LIB$ESTABLISH.

On Alpha systems, LIB$ESTABLISH is not supported, though high-level languages may support it for compatibility.

LIB$SIG_TO_RET can also be called from another condition handler. If LIB$SIG_TO_RET is called from a condition handler, the signaled condition is returned as a function value to the caller of the establisher of that handler when the handler returns to the OpenVMS Condition Handling facility. When a signaled exception condition occurs, LIB$SIG_TO_RET routine does the following:

- Places the signaled condition value in the image of R0 that is saved as part of the mechanism argument vector.
- Calls the Unwind (SYS$UNWIND) system service with the default arguments. After returning from LIB$SIG_TO_RET (when it is established as a condition handler) or after returning from the condition handler that called LIB$SIG_TO_RET (when LIB$SIG_TO_RET is called from a condition handler), the stack unwinds to the caller of the routine that established the handler.

Your calling routine can now both test R0, as if the called routine had returned a status, and specify an error recovery action.

The following paragraphs describe how to establish and use the system-defined condition handler LIB$SIG_TO_RET, which changes a signal to a return status that your program can examine.

To change a signal to a return status, you must put any code that might signal a condition code into a function where the function value is a return status. The function containing the code must perform the following operations:

- Declare LIB$SIG_TO_RET---Declare the condition handler LIB$SIG_TO_RET.
- Establish LIB$SIG_TO_RET---Invoke the run-time library procedure LIB$ESTABLISH to establish a condition handler for the current program unit. Specify the name of the condition handler LIB$SIG_TO_RET as the only argument.
- Initialize the function value---Initialize the function value to SS$_NORMAL so that, if no condition code is signaled, the function returns a success status to the invoking program unit.
- Declare necessary dummy arguments---If any statement that might signal a condition code is a subprogram that requires dummy arguments, pass the necessary arguments to the function. In the function, declare each dummy argument exactly as it is declared in the subprogram that requires it and specify the dummy arguments in the subprogram invocation.

If the program unit GET_1_STAT in the following function signals a condition code, LIB$SIG_TO_RET changes the signal to the return status of the INTERCEPT_SIGNAL function and returns control to the program unit that invoked INTERCEPT_SIGNAL. (If GET_1_STAT has a condition handler established, the operating system invokes that handler before invoking LIB$SIG_TO_RET.)

    FUNCTION INTERCEPT_SIGNAL (STAT,
    2                          ROW,
    2                          COLUMN)

    ! Dummy arguments for GET_1_STAT
    INTEGER STAT,
    2       ROW,
    2       COLUMN
    ! Declare SS$_NORMAL
    INCLUDE '($SSDEF)'
    ! Declare condition handler
    EXTERNAL LIB$SIG_TO_RET
    ! Declare user routine
    INTEGER GET_1_STAT
    ! Establish LIB$SIG_TO_RET
    CALL LIB$ESTABLISH (LIB$SIG_TO_RET)
    ! Set return status to success
    INTERCEPT_SIGNAL = SS$_NORMAL
    ! Statements and/or subprograms that
    ! signal expected error condition codes
    STAT = GET_1_STAT (ROW,
    2                  COLUMN)

    END

When the program unit that invoked INTERCEPT_SIGNAL regains control, it should check the return status (as shown in Section 9.5.1) to determine which condition code, if any, was signaled during execution of INTERCEPT_SIGNAL.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_032.HTML