DocumentationEndless PL/I for OpenVMSUser Manual  ·  ESS-PFVUM-001

Chapter 10

Error Handling

In PL/I errors are signaled through ON conditions and handled by groups of statements called ON-units. An ON condition is any one of several named conditions that interrupt program execution. When an ON condition occurs, or is signaled, the corresponding ON-unit is executed.

This chapter discusses the following topics:

  • The RESIGNAL built-in subroutine

  • The actions that ON-units can take

  • The relationship of OpenVMS condition handling to PL/I condition handling

  • The search for ON-units when a condition is signaled, and the default handling performed when no ON-unit exists

  • The scope of ON-units

  • Some examples of ON-units

  • The condition-handling built-in functions (ONARGSLIST, ONCODE, ONFILE, and ONKEY)

See the Endless PL/I for OpenVMS Reference Manual for descriptions of the ON, REVERT, and SIGNAL statements and ON conditions.

10.1. RESIGNAL Built-In Subroutine

The RESIGNAL built-in subroutine is used in an ON-unit to pass a signaled condition, so that the run-time system will attempt to locate another ON-unit to handle the condition.

RESIGNAL works by setting up the internal mechanism for passing the signal. It does not by itself cause an exit from the ON-unit that calls it. Instead, it returns to the next statement in the ON-unit. Resignaling does not occur until execution of the ON-unit is completed.

The format of a statement calling the RESIGNAL built-in subroutine is as follows:

CALL RESIGNAL();

When an ON-unit has determined that it cannot or should not respond to a condition, RESIGNAL permits the ON-unit to pass the signal along.

This subroutine is not part of the standard PL/I language. It is provided specifically for use in the OpenVMS operating system environment.

10.2. ON-Unit Actions

During its execution, an ON-unit can take any of the following courses of action:

  • Handle the condition and return control to the point at which the condition was signaled

  • Resignal the condition and request PL/I to locate another ON-unit to handle it

  • Execute a nonlocal GOTO statement and cause PL/I to unwind the call stack

  • Stop the program

These courses of action are described individually in the following subsections.

10.2.1. Handling the Condition

A condition is assumed to be handled in PL/I when the ON-unit established for the condition completes execution without performing one of the following actions:

  • Executing a nonlocal GOTO

  • Calling the RESIGNAL built-in subroutine

  • Signaling another condition

  • Executing a STOP statement

When the condition is handled, PL/I continues execution of the program at the point of interruption. Normal completion of any ON-unit (except ERROR signaled as the default action) results in return of control either to the statement that caused the condition or to the statement immediately following the statement that caused the condition. However, the effects of normal return from ERROR, FIXEDOVERFLOW, OVERFLOW, UNDERFLOW, and ZERODIVIDE are generally unpredictable. Exceptions are cases of ERROR that are specifically documented to allow normal return, and ON-units that execute as a result of a SIGNAL statement. In the case of UNDERFLOW, return from the default PL/I condition handler continues execution unpredictably, with an undefined value as the result of the operation that caused the condition (the value is set to zero only if the UNDERFLOW option is not enabled).

10.2.2. Resignaling the Condition

In PL/I, an ON-unit can choose not to handle a condition and can request that, rather than returning control to the point of interruption, PL/I continue to search for another ON-unit to handle the condition. It does this by calling the RESIGNAL built-in subroutine as follows:

CALL RESIGNAL();

The RESIGNAL built-in subroutine has no arguments.

When an ON-unit calls RESIGNAL, PL/I resumes its search of the call stack starting at the call frame beneath the frame in which it located the current ON-unit. Example 10.1, “Resignaling the Condition” and Figure 10.1, “Resignaling a Condition” illustrate the effect of the RESIGNAL built-in subroutine. The callout numbers in the example indicate the order of execution.

Procedure B establishes an ANYCONDITION ON-unit that handles specific values. When the ON-unit is executed as a result of a signal in either procedure B or C, it tests the current value of ONCODE to see whether it is a value of interest. If not, procedure B calls RESIGNAL.

Example 10.1. Resignaling the Condition
A: PROCEDURE OPTIONS (MAIN);❶
ON FIXEDOVERFLOW BEGIN;

❻

END;
⋮
CALL B;

B: PROCEDURE (X,Y);❷
ON ANYCONDDITION BEGIN;
IF (ONCODE()=SIGNAL_FOUND)! ❺
   (ONCODE()=SIGNAL_DONE) THEN
   BEGIN;

   END;/"begin block for IF statement"/
   ELSE CALL RESIGNAL();
END;/"ON-unit"/
CALL C;

C: PROCEDURE;❸

    ❹

   RETURN;
   END;

Figure 10.1. Resignaling a Condition
Search for an ON-Unit

When the FIXEDOVERFLOW condition is signaled in procedure C, B calls RESIGNAL and PL/I continues its search of the call stack. It locates the ON-unit for handling the FIXEDOVERFLOW condition in procedure A and executes it.

Note that the default condition handling performed by PL/I uses the resignaling capability to continue signals that are not handled within the program. PL/I default condition handling is described in Section 10.4, “Search Path for ON-Units”.

10.2.3. Unwinding the Call Stack

An ON-unit in a PL/I procedure can execute a nonlocal GOTO statement that transfers control to a previous block. In this case, PL/I releases call frames, beginning with the call frame created for the ON-unit, until it reaches the block containing the label specified in the GOTO statement.

The removal of call frames from the call stack is called an unwind. Example 10.2, “Unwinding the Call Stack” and Figure 10.2, “Unwinding the Call Stack” illustrate a situation in which an unwind occurs. The callout numbers in the example indicate the order of execution.

Procedure A establishes an ERROR ON-unit represented by the box drawn with broken lines in Figure 10.2, “Unwinding the Call Stack”. The ERROR ON-unit established in procedure A receives control when the ERROR condition is signaled in procedure C. This ON-unit executes the GOTO PRINT_MSG statement. The label PRINT_MSG is in procedure A. Thus, the call stack is unwound and the call frames for the ON-unit, procedure C, and procedure B, in that order, are removed from the stack, and execution continues at the label PRINT_MSG.

Example 10.2. Unwinding the Call Stack
A: PROCEDURE OPTIONS (MAIN);❶
       ON ERROR GOTO PRINT_MSG;

       ❹

       CALL B;
   PRINT_MSG;

   ❺

   END;

B: PROCEDURE;❷

   CALL C;

   RETURN;
   END;

C: PROCEDURE;❸

   RETURN;
   END;

Figure 10.2. Unwinding the Call Stack
Effect of Multiple Conditions

When an unwind occurs in the OpenVMS environment, each call frame in the calling sequence is examined to determine if a condition ON-unit exists for that frame. If so, the ON-unit is called with the condition value SS$_UNWIND, and the ON-unit has the chance to perform block- or procedure-specific cleanup operations.

10.2.4. Stopping the Program

An ON-unit can specify that the program is to be terminated by executing a STOP statement. For example:

ON UNDEFINEDFILE(INFILE) BEGIN;

    PUT EDIT('File',ONFILE(),'undefined. Error',ONCODE())
              (A,X,A,X,A,X,F(10));
    STOP;
    END;

The STOP statement performs the following actions:

  • It signals the FINISH condition.

  • It calls the SYS$EXIT system service to perform an image exit.

Thus, when a FINISH ON-unit that has been executed as a result of a STOP statement handles the condition, control returns to the STOP statement, which then terminates the image.

If no FINISH or ANYCONDITION ON-unit exists, the program is terminated.

Note that when a FINISH or ANYCONDITION ON-unit executes a STOP statement, the program enters an infinite loop.

10.3. Relationship of OpenVMS Condition Handlers to PL/I ON-Units

In the OpenVMS environment, an exception condition is a hardware- or software-detected condition that synchronously interrupts the execution of an image. A condition handler is a procedure that exists specifically to respond to one or more such conditions; each procedure in the program can establish a condition handler. It is usually the responsibility of each handler to determine the specific condition that was signaled, and to decide whether or not to handle it.

Most high-level languages establish condition handlers by calling the VAX Run-Time Library procedure LIB$ESTABLISH. The PL/I language, however, has in the ON-unit a condition handler defined to handle a specific condition. By using the keyword condition names defined by PL/I and the extensions provided by PL/I, you can write ON-units to handle any possible condition specific to OpenVMS. Each procedure can establish separate ON-units for each of several possible conditions that the procedure wishes to handle.

You should never use LIB$ESTABLISH to establish a condition handler in a PL/I call frame.

10.5. Scope of ON-Units

After an ON-unit is established, it remains in effect for the activation of the current block and all its dynamically descendent blocks, unless one of the following situations occurs:

  • Another ON statement is specified for the same condition in a descendent block. The ON-unit established within the descendent block remains in effect as long as the descendent block is active.

  • A REVERT statement is executed for the specified condition. A REVERT statement nullifies the most recent ON-unit for the specified condition.

  • Another ON statement is specified for the same condition within the current block. Within the same block, an ON statement for a specific condition cancels the previous ON-unit.

  • The block or procedure within which the ON-unit is established terminates. When a block exits, any ON-units it has established are canceled.

10.6. ON-Unit Examples

The following examples illustrate some typical ON-units. The first example establishes an ON-unit for the FINISH condition. The ON-unit ensures that two files are closed properly, and calls a routine that stops a timer in an orderly fashion.

ON FINISH BEGIN;
     CLOSE FILE(INFILE);
     CLOSE FILE(OUTFILE);
     CALL TIMER_END;
     END;

Normally, the FINISH ON-unit should be declared in the main procedure; however, it will be executed on image exit if it is established in any block that is active when that occurs.

The next example contains an ERROR ON-unit that will terminate a program in an orderly fashion, should some error occur that is not handled by a specific ON-unit.

DECLARE STATUS FIXED BINARY(31);
⋮
ON ERROR BEGIN;
    CLOSE FILE (INFILE);
    CLOSE FILE (OUTFILE);
    STATUS = ONCODE();
    GOTO FINIS;
    END;
⋮
FINIS: RETURN (STATUS);

The ERROR ON-unit provides a cleanup procedure to ensure that the files identified as INFILE and OUTFILE are properly closed before the image exits. The ON-unit saves the value returned by ONCODE in the variable STATUS, and transfers control to a RETURN statement that returns the numeric value to the caller. If the procedure was invoked by a RUN command, this value is returned to the command interpreter, which in turn displays on the terminal the mnemonic code for the error and the error message.

The next example contains an ON-unit that changes the value of a bit variable when end-of-file is encountered.

DECLARE STATE_PTR POINTER,
        STATE_FILE FILE,
        EOF BIT(1) STATIC INIT('0'B);

ON ENDFILE(STATE_FILE) EOF = '1'B;

        OPEN FILE(STATE_FILE) INPUT SEQUENTIAL;
        READ FILE(STATE_FILE) SET(STATE_PTR);
        DO WHILE (^EOF);
            ⋮
            READ FILE(STATE_FILE) SET(STATE_PTR);
            END;

The procedure reads the records in the file STATE_FILE until it encounters end-of-file. At that point, the ON-unit executes and changes the value of EOF from 0 to 1. This action causes the test in the DO WHILE statement to fail, terminating the loop that reads the records.

Following is an example of an ON-unit that consists of a sequence of statements in a begin block.

ON ENDFILE (SYSIN) BEGIN;
   CLOSE FILE (TEMP);
   CALL PRINT_STATISTICS(TEMP);
   END;

This ON-unit consists of CLOSE and CALL statements that request special processing when the end-of-file condition occurs during reading of the default system input file, SYSIN.

Following is an example of a null statement specified for an ON-unit.

ON ENDPAGE(SYSPRINT);

This ON-unit causes PL/I to continue output on a terminal regardless of the number of lines already output. The null statement indicates that no processing is to occur when the condition occurs. Program execution continues as if the condition had been handled.

Chapter 6, Record Input/Output demonstrates an ON-unit that handles errors encountered during record I/O operations.

10.7. Condition-Handling Built-In Functions

The following sections discuss the four PL/I built-in functions that are useful for condition handling: ONARGSLIST, ONCODE, ONFILE, and ONKEY.

10.7.1. ONARGSLIST Built-In Function

Within the context of the PL/I language, an ON-unit resembles a procedure that has no parameters. However, in the OpenVMS environment, a condition handler or ON-unit is called with an argument list. The argument list consists of two pointer values, each of which points to a structure containing values that provide information about the condition.

In PL/I, you can access these arguments with the ONARGSLIST built-in function; this built-in function returns a pointer to the argument list passed to the most recent ON-unit. Figure 10.6, “The Argument List Passed to an ON-UNIT on OpenVMS VAX” and Figure 10.7, “The Argument List Passed to an ON-Unit on OpenVMS Alpha” illustrate the argument list and the arguments that can be accessed through this list for Endless PL/I V3.9 for OpenVMS VAX and Endless PL/I V5.0 for OpenVMS Alpha respectively.

Figure 10.6. The Argument List Passed to an ON-UNIT on OpenVMS VAX
The Argument List Passed to an ON-UNIT on OpenVMS VAX

Example 10.6, “Definitions for VAX Signal Array and Mechanism Array Arguments” displays the text module $CHFDEF, which contains Endless PL/I V3.9 for OpenVMS VAX declarations of these structures:

Example 10.6. Definitions for VAX Signal Array and Mechanism Array Arguments
/* Definitions for Signal Array and Mechanism Array arguments for VAX */
DECLARE CHF$ARGPTR POINTER;
DECLARE 1 CHF$ARGLIST BASED (CHF$ARGPTR),
    2 CHF$COUNT FIXED BINARY(31), /* always 2 */
    2 CHF$SIGARGLST POINTER,
    2 CHF$MCHARGLST POINTER;
DECLARE 1 CHF$SIGNAL_ARRAY BASED (CHF$SIGARGLST),
    2 CHF$SIG_ARGS FIXED BINARY(31),      /* argument count */
    2 CHF$SIG_NAME FIXED BINARY(31),      /* condition name */
    2 CHF$SIG_ARG (CHF$SIG_ARGS-3) FIXED BINARY(31),
    2 CHF$PC FIXED BINARY(31),
    2 CHF$PSL FIXED BINARY(31),
  1 CHF$MECH_ARRAY BASED (CHF$MCHARGLST),
    2 CHF$MCH_ARGS FIXED BINARY(31),      /* always 4 */
    2 CHF$MCH_FRAME FIXED BINARY(31),
    2 CHF$MCH_DEPTH FIXED BINARY(31),
    2 CHF$MCH_SAVR0 FIXED BINARY(31),
    2 CHF$MCH_SAVR1 FIXED BINARY(31);

This module is in the default PL/I text library PLI$STARLET.TLB. You can include this module in a PL/I program by specifying the following %INCLUDE statement:

%INCLUDE $CHFDEF;

The PL/I compiler locates this module in PLI$STARLET.TLB when it compiles the source program.

Figure 10.7. The Argument List Passed to an ON-Unit on OpenVMS Alpha
The Argument List Passed to an ON-Unit on OpenVMS Alpha

Table 10.1, “Contents of the OpenVMS Alpha Mechanism Array (MECH) Arguments” explains the contents of the OpenVMS Alpha mechanism array arguments shown in Figure 10.7, “The Argument List Passed to an ON-Unit on OpenVMS Alpha”. Example 10.7, “Definitions for OpenVMS Alpha Signal Array and Mechanism Array Arguments” shows the definitions for OpenVMS Alpha signal and mechanism array arguments.

Table 10.1. Contents of the OpenVMS Alpha Mechanism Array (MECH) Arguments
Field NameContents
CHF$IS_MCH_ARGSCount of quadwords in this array starting from the next quadword (CHF$IS_MCH_FRAME) (not counting the first quadword that contains this longword). This value is always 43.
CHF$IS_MCH_FLAGS

Flag bits <31:0> for related argument mechanism information defined as follows:

CHF$V_FPREGS_VALID

Bit 0. When set, the process has already performed a floating point operation and the floating point registers stored in this structure are valid.

If this bit is clear, the process has not yet performed any floating point operations and the values in the floating point register slots in this structure are unpredictable.

CHF$PH_MCH_FRAMEContains the frame pointer in the procedure context of the establisher.
CHF$IS_MCH_DEPTHPositive count of the number of procedure activation stack frames between the frame in which the exception occurred and the frame depth that established the handler being called (See the OpenVMS Calling Standard manual for more information.)
CHF$IS_MCH_RESVD1Reserved.
CHF$PH_MCH_DADDRAddress of the handler data quadword if the exception handler data field is present (as indicated by PDSC$V_HANDLER_DATA_VALID), otherwise contains zero.
CHF$PH_MCH_ESF_ADDRAddress of the exception stack frame (See the Alpha Architecture Reference Manual).
CHF$PH_MCH_SIG_ADDRAddress of the signal array. The signal array is a 32-bit wide (longword) array.
CHF$IH_MCH_SAVRnnContain a copy of the saved integer registers at the time of the exception. The following registers are saved: R0, R1, and R16 through R28. Registers R2 through R15 are implicitly saved in the call chain.
CHF$FH_MCH_SAVFnnContain a copy of the saved floating point registers at the time of the exception, or are unpredictable as described at field CHF$IS_MCH_FLAGS. If the floating-point register fields are valid, the following registers are saved: F0, F1, and F10 through F30. Registers F2 through F9 are implicitly saved in the call chain.

Example 10.7. Definitions for OpenVMS Alpha Signal Array and Mechanism Array Arguments
1 chf$mech_array based (chf$mcharglst),
  2 CHF$R_MCH_ARGS_DESC union,
    3 CHF$IS_MCH_ARGS fixed bin(31),  /*NUMBER OF MECHANISM ARGUMENTS     */
  2 CHF$R_MCH_FLAGS_DESC union,
    3 CHF$IS_MCH_FLAGS fixed bin(31), /*Flags                             */
    3 CHF$R_MCH_FLAGS_BITS ,          /*Flags bits.                       */

      4 CHF$V_FPREGS_VALID bit(1),     /*FP registers stored in MCH.       */
      4 CHF$V_FILL_37 bit(7),
  2 CHF$R_MCH_FRAME_DESC union,
    3 CHF$PH_MCH_FRAME (2) pointer,   /*ESTABLISHER FRAME ADDRESS         */
  2 CHF$R_MCH_DEPTH_DESC union,
    3 CHF$IS_MCH_DEPTH fixed bin(31), /*FRAME DEPTH OF ESTABLISHER        */
    3 CHF$IH_MCH_DEPTH fixed binary(31), /*temp                           */
  2 CHF$IS_MCH_RESVD1 fixed bin(31), /*reserved, paired with DEPTH       */
  2 CHF$PH_MCH_DADDR (2) pointer,    /*ESTABLISHER HANDLER DATA CELL     */
  2 CHF$PH_MCH_ESF_ADDR (2) pointer, /*ESTABLISHER EXCEPTION STACK FRAME */
  2 CHF$PH_MCH_SIG_ADDR (2) pointer, /*ESTABLISHER EXCEPTION STACK FRAME */
  2 CHF$R_MCH_SAVR0_DESC union,
    3 CHF$R_FILL_33 union,
      4 CHF$IH_MCH_SAVR0 (2) fixed bin(31), /*SAVED REGISTER R0            */
      4 CHF$R_FILL_34 ,
5 CHF$IL_MCH_SAVR0_LOW fixed binary(31), /*LOW ORDER 32 BITS        */
5 CHF$IL_MCH_SAVR0_HIGH fixed binary(31), /*HIGH ORDER 32 BITS      */
  2 CHF$R_MCH_SAVR1_DESC union,
    3 CHF$R_FILL_35 union,
      4 CHF$IH_MCH_SAVR1 (2) fixed bin(31), /*SAVED REGISTER R1            */
      4 CHF$R_FILL_36 ,
5 CHF$IL_MCH_SAVR1_LOW fixed binary(31), /*LOW ORDER 32 BITS        */
5 CHF$IL_MCH_SAVR1_HIGH fixed binary(31), /*HIGH ORDER 32 BITS      */
  2 CHF$IH_MCH_SAVR16 (2) fixed bin(31), /*SAVED REGISTER R16            */
  2 CHF$IH_MCH_SAVR17 (2) fixed bin(31), /*SAVED REGISTER R17            */
  2 CHF$IH_MCH_SAVR18 (2) fixed bin(31), /*SAVED REGISTER R18            */
  2 CHF$IH_MCH_SAVR19 (2) fixed bin(31), /*SAVED REGISTER R19            */
  2 CHF$IH_MCH_SAVR20 (2) fixed bin(31), /*SAVED REGISTER R20            */
  2 CHF$IH_MCH_SAVR21 (2) fixed bin(31), /*SAVED REGISTER R21            */
  2 CHF$IH_MCH_SAVR22 (2) fixed bin(31), /*SAVED REGISTER R22            */
  2 CHF$IH_MCH_SAVR23 (2) fixed bin(31), /*SAVED REGISTER R23            */
  2 CHF$IH_MCH_SAVR24 (2) fixed bin(31), /*SAVED REGISTER R24            */
  2 CHF$IH_MCH_SAVR25 (2) fixed bin(31), /*SAVED REGISTER R25            */
  2 CHF$IH_MCH_SAVR26 (2) fixed bin(31), /*SAVED REGISTER R26            */
  2 CHF$IH_MCH_SAVR27 (2) fixed bin(31), /*SAVED REGISTER R27            */
  2 CHF$IH_MCH_SAVR28 (2) fixed bin(31), /*SAVED REGISTER R28            */
  2 CHF$FH_MCH_SAVF0 bit(64) aligned, /*SAVED REGISTER F0                */
  2 CHF$FH_MCH_SAVF1 bit(64) aligned, /*SAVED REGISTER F1                */
  2 CHF$FH_MCH_SAVF10 bit(64) aligned, /*SAVED REGISTER F10              */
  2 CHF$FH_MCH_SAVF11 bit(64) aligned, /*SAVED REGISTER F11              */
  2 CHF$FH_MCH_SAVF12 bit(64) aligned, /*SAVED REGISTER F12              */
  2 CHF$FH_MCH_SAVF13 bit(64) aligned, /*SAVED REGISTER F13              */
  2 CHF$FH_MCH_SAVF14 bit(64) aligned, /*SAVED REGISTER F14              */
  2 CHF$FH_MCH_SAVF15 bit(64) aligned, /*SAVED REGISTER F15              */
  2 CHF$FH_MCH_SAVF16 bit(64) aligned, /*SAVED REGISTER F16              */
  2 CHF$FH_MCH_SAVF17 bit(64) aligned, /*SAVED REGISTER F17              */
  2 CHF$FH_MCH_SAVF18 bit(64) aligned, /*SAVED REGISTER F18              */
  2 CHF$FH_MCH_SAVF19 bit(64) aligned, /*SAVED REGISTER F19              */
  2 CHF$FH_MCH_SAVF20 bit(64) aligned, /*SAVED REGISTER F20              */
  2 CHF$FH_MCH_SAVF21 bit(64) aligned, /*SAVED REGISTER F21              */
  2 CHF$FH_MCH_SAVF22 bit(64) aligned, /*SAVED REGISTER F22              */
  2 CHF$FH_MCH_SAVF23 bit(64) aligned, /*SAVED REGISTER F23              */
  2 CHF$FH_MCH_SAVF24 bit(64) aligned, /*SAVED REGISTER F24              */
  2 CHF$FH_MCH_SAVF25 bit(64) aligned, /*SAVED REGISTER F25              */
  2 CHF$FH_MCH_SAVF26 bit(64) aligned, /*SAVED REGISTER F26              */
  2 CHF$FH_MCH_SAVF27 bit(64) aligned, /*SAVED REGISTER F27              */
  2 CHF$FH_MCH_SAVF28 bit(64) aligned, /*SAVED REGISTER F28              */
  2 CHF$FH_MCH_SAVF29 bit(64) aligned, /*SAVED REGISTER F29              */
  2 CHF$FH_MCH_SAVF30 bit(64) aligned; /*SAVED REGISTER F30              */

Example 10.8, “Displaying Arguments Passed to a Condition Handler (VAX)” illustrates a procedure that displays values obtained from the signal array arguments and the mechanism array arguments.

Example 10.8. Displaying Arguments Passed to a Condition Handler (VAX)
%INCLUDE $CHFDEF;    ❶
DECLARE X FIXED;
            CHF$ARGPTR = ONARGSLIST();    ❷
/* Output number of signal arguments */
            PUT SKIP LIST('Signal Arg Count',CHF$SIG_ARGS);    ❸
/* Output condition name argument and rest of signal arguments */
            PUT SKIP LIST('Condition name', CHF$SIG_NAME);    ❹
            PUT SKIP LIST(DIM(CHF$SIG_ARG,1),
                         'additional arguments:');    ❺
                DO X = 1 TO DIM(CHF$SIG_ARG,1);
                    PUT SKIP LIST(CHF$SIG_ARG(X));
                    END;
/* Output RO and R1 */
            PUT SKIP(2) LIST('r0:',CHF$MCH_SAVR0);    ❻
            PUT SKIP(2) LIST('r1:',CHF$MCH_SAVR1);
END;

The following notes are keyed to Example 10.8, “Displaying Arguments Passed to a Condition Handler (VAX)”:

❶

The procedure includes the module $CHFDEF from the default system library.

❷

The ONARGSLIST built-in function assigns a value to the pointer CHF$ARGPTR, declared in $CHFDEF.

❸

Using the CHF$SIG_ARGS field in the signal array, the procedure prints the number of arguments in the signal array.

❹

It displays the contents of the first argument, that is, the condition value.

❺

Because the number of arguments is variable, the procedure uses the DIM built-in function to determine the number of elements in the array CHF$SIG_ARG (this array always contains three fewer members than arguments in the array, because the condition name, PC, and PSL arguments are always present).

❻

After displaying the signal arguments, the procedure displays the contents of R0 and R1 from the mechanism array.

For more detailed information on the argument lists passed to a condition handler and for descriptions of the values in the signal array and mechanism array, see the OpenVMS System Services Reference Manual. Note that the PL/I run-time system signals conditions using the conventions for specifying signal arguments. Specifically, it passes arguments following the requirements described for the SYS$PUTMSG procedure. This procedure is described in the Introduction to the VMS Run-Time Library.

10.7.2. ONCODE Built-In Function

You can use the built-in function ONCODE to obtain the specific 32-bit status value that describes any condition that is signaled. The low-order three bits of this value contain the severity of the condition (success, warning, error, or fatal). The severity of a condition is important only when no ON-unit exists for a condition, and default condition handling is performed by either PL/I or the system (see Section 10.4, “Search Path for ON-Units”).

All OpenVMS-defined conditions have symbolic names associated with them. Table 10.2, “ONCODE Values for PL/I ON Conditions” lists the PL/I keyword condition names and the global symbol names for the OpenVMS condition values associated with them. If the ONCODE built-in function is invoked in an ON-unit for the related PL/I condition name, it returns the value of the indicated global symbol.

Table 10.2. ONCODE Values for PL/I ON Conditions
PL/I ConditionVMS Global Symbol Name[a]
AREASee the Endless PL/I for OpenVMS Reference Manual and Chapter 15, Storage Allocation of this manual for a discussion of allocation in areas.
CONDITIONPLI$_CONDITION
CONVERSIONPLI$_CONVERSION if a SIGNAL CONVERSION statement was executed, otherwise PLI$_ONCNVPOS (PLI$_ONCNVPOS could change in a future release of PL/I)
ENDFILEPLI$_ENDFILE
ENDPAGEPLI$_ENDPAGE
ERRORA specific status value associated with the error that caused the condition to be signaled[b]
FINISHPLI$_FINISH
FIXEDOVERFLOWSS$_DECOVF or SS$_INTOVF
KEYRMS$_name, where name is one of the following specific RMS condition names that describe a key error: RMS$_RNF, RMS$_DUP, RMS$_KEY, RMS$_MRN, RMS$_REX; or, PLI$_name, where name describes a PL/I run-time error, for example PLI$_CNVERR[b]
OVERFLOWSS$_FLTOVF or SS$_FLTOVF_F
STORAGEThe value returned by LIB$GET_VM
STRINGRANGEPLI$_STRRANGE, or PLI$_SUBSTRn (where n is 2 or 3, indicating the 2nd or 3rd argument of the SUBSTR built-in function), or PLI$_BIFSTAPOS (indicating an out-of-range starting position for an INDEX, SEARCH, or VERIFY built-in function)
SUBSCRIPTRANGEPLI$_SUBRANGE or PLI$_SUBRANGEn (where n is a number in the range 1 through 8 indicating the subscript number)
UNDEFINEDFILERMS$_name, where name indicates a specific status value associated with an RMS error; or, PLI$_name, where name describes a PL/I run-time error[b]
UNDERFLOWSS$_FLTUND or SS$_FLTUND_F
VAXCONDITIONAny user-defined condition value that was signaled
ZERODIVIDESS$_FLTDIV, SS$_INTDIV, or SS$_FLTDIV_F

[a] If a PL/I condition is explicitly specified in a SIGNAL statement, the ONCODE value corresponds to the condition message associated with the condition, for example, PLI$_UNDFILE, PLI$_KEY, and so on.

[b] These names correspond to the identification fields in the run-time messages. The RMS messages are listed in the OpenVMS Record Management Services Reference Manual. PL/I messages are listed in Appendix A, PL/I Messages.


When you write an ON-unit to handle one or more conditions, you can refer specifically to the values returned by the ONCODE built-in function using system global symbol names. Table 10.2, “ONCODE Values for PL/I ON Conditions” lists, where appropriate, the specific system global symbol for a condition name.

All symbolic names associated with OpenVMS condition values are defined as system global symbols. Thus, you can declare the names for these values in a PL/I program using the GLOBALREF and VALUE attributes, and refer to them symbolically. The linker will automatically locate the definitions of the symbols in the default system libraries when the procedure is linked.

For example, the FIXEDOVERFLOW condition can be signaled for either of two conditions. An ON-unit can determine which condition was actually signaled by testing the value of ONCODE as follows:

DECLARE SS$_DECOVF GLOBALREF VALUE FIXED BINARY(31);
ON FIXEDOVERFLOW BEGIN;
     IF ONCODE() = SS$_DECOVF THEN
            PUT LIST ('Decimal overflow');
         ELSE
            PUT LIST ('Integer overflow');
     END;

In this example, the global symbol SS$_DECOVF is declared with the GLOBALREF and VALUE attributes. The ON-unit established for the FIXEDOVERFLOW condition determines, from the value returned by ONCODE, whether the condition was specifically a decimal overflow or an integer overflow.

10.7.3. ONFILE Built-In Function

The ONFILE built-in function returns the name of the file constant for which the current file-related condition was signaled. Its format is given in the Endless PL/I for OpenVMS Reference Manual.

This built-in function can be used in any of the following ON-units:

  • An ON-unit established for the KEY, ENDFILE, ENDPAGE, and UNDEFINEDFILE conditions

  • A VAXCONDITION ON-unit established for I/O errors that can occur during file processing

  • An ERROR ON-unit that receives control as a result of the default PL/I action for file-related errors, which is to signal the ERROR condition

The returned value is a varying-length character string. If referenced outside an ON-unit or within an ON-unit that is executed as a result of a SIGNAL statement, the ONFILE function returns a null string.

10.7.4. ONKEY Built-In Function

The ONKEY built-in function returns the key value that caused the KEY condition to be signaled during an I/O operation to a file that is being accessed by key. Its format is given in the Endless PL/I for OpenVMS Reference Manual.

This built-in function can be used in an ON-unit established for these conditions:

  • The KEY, ENDFILE, or UNDEFINEDFILE conditions

  • An ERROR ON-unit that receives control as a result of the default PL/I action for the KEY condition, which is to signal the ERROR condition

The returned key value is a varying-length character string. If referenced outside an ON-unit, or within an ON-unit executed as a result of the SIGNAL statement, the ONKEY built-in function returns a null string.