Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

### 9.9.2 Interaction Between Default and User-Supplied Handlers

Several results are possible after a routine signals, depending on a number of factors, such as the severity of the error, the method of generating the signal, and the action of the condition handlers you have defined and the default handlers. Given the severity of the condition and the method of signaling, Figure 9-12 lists all combinations of interaction between user condition handlers and default condition handlers.

Figure 9-12 Interaction Between Handlers and Default Handlers

## 9.10 Types of Actions Performed by Condition Handlers

When a condition handler returns control to the OpenVMS Condition Handling facility (CHF), the facility takes one of the following types of actions, depending on the value returned by the condition handler:

- Signal a condition
  Signaling a condition initiates the search for an established condition handler.
- Continue
  The condition handler may or may not be able to fix the problem, but the program can attempt to continue execution. The handler places the return status value SS$_CONTINUE in R0 and issues a RET instruction to return control to the dispatcher. If the exception was a fault, the instruction that caused it is reexecuted; if the exception was a trap, control is returned at the instruction following the one that caused it. A condition handler cannot continue if the exception condition was signaled by calling LIB$STOP.
  Section 9.12.1 contains more information about continuing.
- Resignal
  The handler cannot fix the problem, or this condition is one that it does not handle. It places the return status value SS$_RESIGNAL in R0 and issues a RET instruction to return control to the exception dispatcher. The dispatcher resumes its search for a condition handler. If it finds another condition handler, it passes control to that routine. A handler can alter the severity of the signal before resignaling.
  Section 9.12.2 contains more information about resignaling.
- Unwind
  The condition handler cannot fix the problem, and execution cannot continue while using the current flow. The handler issues the Unwind Call Stack (SYS$UNWIND) system service to unwind the call stack. Call frames can then be removed from the stack and the flow of execution modified, depending on the arguments to the SYS$UNWIND service.
  When a condition handler has already called SYS$UNWIND, any return status from the condition handler is ignored by the CHF. The CHF now unwinds the stack.
  Unwinding the routine call stack first removes call frames, starting with the frame in which the condition occurred, and then returns control to an earlier routine in the calling sequence. You can unwind the stack whether the condition was detected by hardware or signaled using LIB$SIGNAL or LIB$STOP. Unwinding is the only way to continue execution after a call to LIB$STOP.
  Section 9.12.3 describes how to write a condition handler that unwinds the call stack.
- Perform a nonlocal GOTO unwind
  On Alpha systems, a GOTO unwind operation is a transfer of control that leaves one procedure invocation and continues execution in a prior (currently active) procedure. This unified GOTO operation gives unterminated procedure invocations the opportunity to clean up in an orderly way. See Section 9.10.2 for more information about GOTO unwind operations.

### 9.10.1 Unwinding the Call Stack

One type of action a condition handler can take is to unwind the procedure call stack. The unwind operation is complex and should be used only when control must be restored to an earlier procedure in the calling sequence. Moreover, use of the SYS$UNWIND system service requires the calling condition handler to be aware of the calling sequence and of the exact point to which control is to return.

SYS$UNWIND accepts two optional arguments:

- The depth to which the unwind is to occur. If the depth is 1, the call stack is unwound to the caller of the procedure that incurred the exception. If the depth is 2, the call stack is unwound to the caller's caller, and so on. By specifying the depth in the mechanism array, the handler can unwind to the procedure that established the handler.
- The address of a location to receive control when the unwind operation is complete, that is, a PC to replace the current PC in the call frame of the procedure that will receive control when all specified frames have been removed from the stack.

If no argument is supplied to SYS$UNWIND, the unwind is performed to the caller of the procedure that established the condition handler that is issuing the SYS$UNWIND service. Control is returned to the address specified in the return PC for that procedure. Note that this is the default and the normal case for unwinding.

Another common case of unwinding is to unwind to the procedure that declared the handler. On VAX systems, this is done by using the depth value from the exception mechanism array (CHF$L_MCH_DEPTH) as the depth argument to SYS$UNWIND. On Alpha systems, this is done by using the depth value from the exception mechanism array (CHF$IS_MCH_DEPTH) as the depth argument to SYS$UNWIND.

Therefore, it follows that the default unwind (no depth specified) is equivalent to specifying CHF$L_MCH_DEPTH plus 1 on VAX systems. On Alpha systems, the default unwind (no depth specified) is equivalent to specifying CHF$IS_MCH_DEPTH plus 1. In certain instances of nested exceptions, however, this is not the case. Compaq recommends that you omit the depth argument when unwinding to the caller of the routine that established the condition handler.

Figure 9-13 illustrates an unwind situation and describes some of the possible results.

The unwind operation consists of two parts:

1. In the call to SYS$UNWIND, the return PCs saved in the stack are modified to point into a routine within the SYS$UNWIND service, but the entire stack remains present.
2. When the handler returns, control is directed to this routine by the modified PCs. It proceeds to return to itself, removing the modified stack frames, until the stack has been unwound to the proper depth.

For this reason, the stack is in an intermediate state directly after calling SYS$UNWIND. Handlers should, in general, return immediately after calling SYS$UNWIND.

During the actual unwinding of the call stack, the unwind routine examines each frame in the call stack to see whether a condition handler has been declared. If a handler has been declared, the unwind routine calls the handler with the status value SS$_UNWIND (indicating that the call stack is being unwound) in the condition name argument of the signal array. When a condition handler is called with this status value, it can perform any procedure-specific cleanup operations required. For example, the handler should deallocate any processwide resources that have been allocated. Then, the handler returns control to the OpenVMS Condition Handling facility. After the handler returns, the call frame is removed from the stack.

When a condition handler is called during the unwinding operation, the condition handler must not generate a new signal. A new signal would result in unpredictable behavior.

Thus, in Figure 9-13, handler B can be called a second time, during the unwind operation. Note that handler B does not have to be able to interpret the SS$_UNWIND status value specifically; the RET instruction merely returns control to the unwind procedure, which does not check any status values.

Handlers established by the primary, secondary, or last-chance vector are not called, because they are not removed during an unwind operation.

While it is unwinding the stack, the OpenVMS Condition Handling facility ignores any function value returned by a condition handler. For this reason, a handler cannot both resignal and unwind. Thus, the only way for a handler to both issue a message and perform an unwind is to call LIB$SIGNAL and then call $UNWIND. If your program calls $UNWIND before calling LIB$SIGNAL, the result is unpredictable.

When the OpenVMS Condition Handling facility calls the condition handler that was established for each frame during unwind, the call is of the standard form, described in Section 9.2. The arguments passed to the condition handler (the signal and mechanism argument vectors) are shown in Section 9.8.2 , Section 9.8.3 , and Section 9.8.4 .

On VAX systems, if the handler is to specify the function value of the last function to be unwound, it should modify the saved copies of R0 and R1 (CHF$L_MCH_SAVR0 and CHF$L_MCH_SAVR1) in the mechanism argument vector.

On Alpha systems, the handler should modify the saved copies of R0 and R1 (CHF$IH_MCH_SAVRnn).

R0 and R1 are restored from the mechanism argument vector at the end of the unwind.

Figure 9-13 Unwinding the Call Stack

### 9.10.2 GOTO Unwind Operations (Alpha Only)

On Alpha systems, a current procedure invocation is one in whose context the thread of execution is currently executing. At any instant, a thread of execution has exactly one current procedure. If code in the current procedure calls another procedure, then the called procedure becomes the current procedure. As each stack frame or register frame procedure is called, its invocation context is recorded in a procedure frame. The invocation context is mainly a snapshot of process registers at procedure invocation. It is used during return from the called procedure to restore the calling procedure's state. The chain of all procedure frames starting with the current procedure and going all the way back to the first procedure invocation for the thread is called the call chain. While a procedure is part of the call chain, it is called an active procedure.

When a current procedure returns to its calling procedure, the most recent procedure frame is removed from the call chain and used to restore the now current procedure's state. As each current procedure returns to its calling procedure, its associated procedure frame is removed from the call chain. This is the normal unwind process of a call chain.

You can bypass the normal return path by forcibly unwinding the call chain. The Unwind Call Chain (SYS$UNWIND) system service allows a condition handler to transfer control from a series of nested procedure invocations to a previous point of execution, bypassing the normal return path. The Goto Unwind (SYS$GOTO_UNWIND) system service allows any procedure to achieve the same effect. SYS$GOTO_UNWIND restores saved register context for each nested procedure invocation, calling the condition handler, if any, for each procedure frame that it unwinds. Restoring saved register context from each procedure frame from the most recent one to the target procedure frame ensures that the register context is correct when the target procedure gains control. Also, each condition handler called during unwind can release any resources acquired by its establishing procedure.

For information about the GOTO unwind operations and how to use the SYS$GOTO_UNWIND system service, see the OpenVMS Calling Standard and the OpenVMS System Services Reference Manual.

## 9.11 Displaying Messages

The standard format for a message is as follows:

`%facility-l-ident, message-text`

facility | Abbreviated name of the software component that issued the message
l | Indicator showing the severity level of the exception condition that caused the message
ident | Symbol of up to nine characters representing the message
message-text | Brief definition of the cause of the message

The message can also include up to 255 formatted ASCII output (FAO) arguments. These arguments can be used to display variable information about the condition that caused the message. In the following examples, the file specification is an FAO argument:

    %TYPE-W-OPENIN, error opening _DB0:[FOSTER]AUTHOR.DAT; as input

For information about specifying FAO parameters, see Section 9.11.4.3.

Signaling

Signaling provides a consistent and unified method for displaying messages. This section describes how the OpenVMS Condition Handling facility translates the original signal into intelligible messages.

Signaling is used to signal exception conditions generated by Compaq software. When software detects an exception condition, it signals the exception condition to the user by calling LIB$SIGNAL or LIB$STOP. The signaling routine passes a signal argument list to these run-time library routines. This signal argument list is made up of the condition value and a set of optional arguments that provide information to condition handlers.

You can use the signaling mechanism to signal messages that are specific to your application. Further, you can chain your own message to a system message. For more information, see Section 9.11.3.

LIB$SIGNAL and LIB$STOP copy the signal argument list and use it to create the signal argument vector. The signal argument vector serves as part of the input to the user-established handlers and the system default handlers.

If all intervening handlers have resignaled, the system default handlers take control. The system-supplied default handlers are the only handlers that should actually issue messages, whether the exception conditions are signaled by Compaq software or your own programs. That is, a routine should signal exception conditions rather than issue its own messages. In this way, other applications can call the routine and override its signal in order to change the messages. Further, this technique decides formatting details, and it also keeps wording centralized and consistent.

The system default handlers pass the signal argument vector to the Put Message (SYS$PUTMSG) system service. SYS$PUTMSG formats and displays the information in the signal argument vector.

SYS$PUTMSG performs the following steps:

1. Interprets the signal argument vector as a series of one or more message sequences. Each message sequence starts with a 32-bit, systemwide condition value that identifies a message in the system message file. SYS$PUTMSG interprets the message sequences according to type defined by the facility of the condition.
2. Obtains the text of the message using the Get Message (SYS$GETMSG) system service. The message text definition is actually a SYS$FAO control string. It may contain embedded FAO directives. These directives determine how the FAO arguments in the signal argument vector are formatted. (For more information about SYS$FAO, see the OpenVMS System Services Reference Manual.)
3. Calls SYS$FAO to format the message, substituting the values from the signal argument list.
4. Issues the message on device SYS$OUTPUT. If SYS$ERROR is different from SYS$OUTPUT, and the severity field in the condition value is not success, $PUTMSG also issues the message on device SYS$ERROR.

You can use the signal array that the operating system passes to the condition handler as the first argument of the SYS$PUTMSG system service. The signal array contains the condition code, the number of required FAO arguments for each condition code, and the FAO arguments (see Figure 9-14). The OpenVMS System Services Reference Manual contains complete specifications for SYS$PUTMSG.

See Section 9.11.2 for information about how to create and suppress messages on a running log using SYS$PUTMSG.

The last two array elements, the PC and PSL, are not FAO arguments and should be deleted before the array is passed to SYS$PUTMSG. Because the first element of the signal array contains the number of longwords in the array, you can effectively delete the last two elements of the array by subtracting 2 from the value in the first element. Before exiting from the condition handler, you should restore the last two elements of the array by adding 2 to the first element in case other handlers reference the array.

In the following example, the condition handler uses the SYS$PUTMSG system service and then returns a value of SS$_CONTINUE so that the default handler is not executed.

    INTEGER*4 FUNCTION SYMBOL (SIGARGS,
    2                          MECHARGS)
       .
       .
       .
    INDEX = LIB$MATCH_COND (SIGARGS(2),
    2                       LIB$_NOSUCHSYM)
    IF (INDEX .GT. 0) THEN
      ! If condition code is LIB$_NOSUCHSYM,
      ! change the severity to informational
      CALL MVBITS (STS$K_INFO,
    2              0,
    2              3,
    2              SIGARGS(2),
    2              0)

      ! Display the message
      SIGARGS(1) = SIGARGS(1) - 2   ! Subtract last two elements
      CALL SYS$PUTMSG (SIGARGS,,,)
      SIGARGS(1) = SIGARGS(1) + 2   ! Restore last two elements

      ! Continue program execution;
      SYMBOL = SS$_CONTINUE
    ELSE
      ! Otherwise, resignal the condition
      SYMBOL = SS$_RESIGNAL
    END IF

    END

Each message sequence in the signal argument list produces one line of output. Figure 9-14 illustrates the three possible message sequence formats.

Figure 9-14 Formats of Message Sequences

OpenVMS RMS system services return two related completion values: the completion code and the associated status value. The completion code is returned in R0 using the function value mechanism. The same value is also placed in the Completion Status Code field of the RMS file access block (FAB) or record access block (RAB) associated with the file (FAB$L_STS or RAB$L_STS). The status value is returned in the Status Value field of the same FAB or RAB (FAB$L_STV or RAB$L_STV). The meaning of this secondary value is based on the corresponding STS (Completion Status Code) value. Its meaning could be any of the following:

- An operating system condition value of the form SS$_...
- An RMS value, such as the size of a record that exceeds the buffer size
- Zero

Rather than have each calling program determine the meaning of the STV value, SYS$PUTMSG performs the necessary processing. Therefore, this STV value must always be passed in place of the FAO argument count. In other words, an RMS message sequence always consists of two arguments (passed by immediate value): an STS value and an STV value.

### 9.11.1 Chaining Messages

You can use a condition handler to add condition values to an originally signaled condition code. For example, if your program calculates the standard deviation of a series of numbers and the user only enters one value, the operating system signals the condition code SS$_INTDIV when the program attempts to divide by zero. (In calculating the standard deviation, the divisor is the number of values entered minus 1.) You could use a condition handler to add a user-defined message to the original message to indicate that only one value was entered.

To display multiple messages, pass the condition values associated with the messages to the RTL routine LIB$SIGNAL. To display the message associated with an additional condition code, the handler must pass LIB$SIGNAL the condition code, the number of FAO arguments used, and the FAO arguments. To display the message associated with the originally signaled condition codes, the handler must pass LIB$SIGNAL each element of the signal array as a separate argument. Because the signal array is a variable-length array and LIB$SIGNAL cannot accept a variable number of arguments, when you write your handler you must pass LIB$SIGNAL more arguments than you think will be required. Then, during execution of the handler, zero the arguments that you do not need (LIB$SIGNAL ignores zero values), as described in the following steps:

1. Declare an array with one element for each argument that you plan to pass LIB$SIGNAL. Fifteen elements are usually sufficient.

       INTEGER*4 NEWSIGARGS(15)

2. Transfer the condition values and FAO information from the signal array to your new array. The first element and the last two elements of the signal array do not contain FAO information and should not be transferred.
3. Fill any remaining elements of your new array with zeros.

The following example demonstrates steps 2 and 3:

    DO I = 1, 15

      IF (I .LE. SIGARGS(1) - 2) THEN
        NEWSIGARGS(I) = SIGARGS(I+1)  ! Start with SIGARGS(2)
        ELSE
        NEWSIGARGS(I) = 0             ! Pad with zeros
      END IF

    END DO

Because the new array is a known-length array, you can specify each element as an argument to LIB$SIGNAL.

The following condition handler ensures that the signaled condition code is SS$_INTDIV. If it is, the user-defined message ONE_VALUE is added to SS$_INTDIV, and both messages are displayed.

    INTEGER FUNCTION HANDLER (SIGARGS,
    2                         MECHARGS)

    ! Declare dummy arguments
    INTEGER SIGARGS(*),
    2       MECHARGS(*)
    ! Declare new array for SIGARGS
    INTEGER NEWSIGARGS (15)
    ! Declare index variable for LIB$MATCH_COND
    INTEGER INDEX
    ! Declare procedures
    INTEGER LIB$MATCH_COND
    ! Declare condition codes
    EXTERNAL ONE_VALUE
    INCLUDE '($SSDEF)'
    INDEX = LIB$MATCH_COND (SIGARGS(2),
    2                       SS$_INTDIV)
    IF (INDEX .GT. 0) THEN

      DO I=1,15
        IF (I .LE. SIGARGS(1) - 2) THEN
          NEWSIGARGS(I) = SIGARGS(I+1)  ! Start with SIGARGS(2)
        ELSE
          NEWSIGARGS(I) = 0             ! Pad with zeros
        END IF
      END DO

        ! Signal messages
      CALL LIB$SIGNAL (%VAL(NEWSIGARGS(1)),
    2                  %VAL(NEWSIGARGS(2)),
    2                  %VAL(NEWSIGARGS(3)),
    2                  %VAL(NEWSIGARGS(4)),
    2                  %VAL(NEWSIGARGS(5)),
    2                  %VAL(NEWSIGARGS(6)),
    2                  %VAL(NEWSIGARGS(7)),
    2                  %VAL(NEWSIGARGS(8)),
    2                  %VAL(NEWSIGARGS(9)),
    2                  %VAL(NEWSIGARGS(10)),
    2                  %VAL(NEWSIGARGS(11)),
    2                  %VAL(NEWSIGARGS(12)),
    2                  %VAL(NEWSIGARGS(13)),
    2                  %VAL(NEWSIGARGS(14)),
    2                  %VAL(NEWSIGARGS(15)),
    2                  %VAL(%LOC(ONE_VALUE)),
    2                  %VAL(0))

      HANDLER = SS$_CONTINUE
    ELSE
      HANDLER = SS$_RESIGNAL

    END IF

    END

A signal argument list may contain one or more condition values and FAO arguments. Each condition value and its FAO arguments is "chained" to the next condition value and its FAO arguments. You can use chained messages to provide more specific information about the exception condition being signaled, along with a general message.

The following message source file defines the exception condition PROG__FAIGETMEM:

         .FACILITY     PROG,1 /PREFIX=PROG__

         .SEVERITY     FATAL
         .BASE     100

         FAIGETMEM   <failed to get !UL bytes of memory>/FAO_COUNT=1

         .END

This source file sets up the exception message as follows:

- The .FACILITY directive specifies the facility, PROG, and its number, 1. It also adds the /PREFIX qualifier to determine the prefix to be used in the message.
- The .SEVERITY directive specifies that PROG__FAIGETMEM is a fatal exception condition. That is, the SEVERITY field in the condition value for PROG__FAIGETMEM is set to severe (bits <0:3> = 4).
- The BASE directive specifies that the condition identification numbers in the PROG facility will begin with 100.
- FAIGETMEM is the symbol name. This name is combined with the prefix defined in the facility definition to make the message symbol. The message symbol becomes the symbolic name for the condition value.
- The text in angle brackets is the message text. This is actually a SYS$FAO control string. When $PUTMSG calls the $FAO system service to format the message, $FAO includes the FAO argument from the signal argument vector and formats the argument according to the embedded FAO directive (!UL).
- The .END statement terminates the list of messages for the PROG facility.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_030.HTML