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.
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;
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.
A: PROCEDURE OPTIONS (MAIN);❶ ON ERROR GOTO PRINT_MSG; ❹ CALL B; PRINT_MSG; ❺ END; B: PROCEDURE;❷ CALL C; RETURN; END; C: PROCEDURE;❸ RETURN; END;
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:
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.4. Search Path for ON-Units
When a condition is signaled in the OpenVMS environment, the OpenVMS condition-handling facility searches the call stack, beginning with the call frame within which the condition was signaled, for a condition handler. If there is no handler, or if no handler handles the condition, a system default handler is executed.
In PL/I the search rules are different. PL/I searches each call frame in the calling sequence for ON-units in a specific sequence. If it reaches the call frame at which the program was entered without locating an ON-unit, it performs default condition handling. The default handling depends on whether or not the call frame at which the procedure was entered specified the MAIN option.
Example 10.3, “Execution of an ON-Unit” and Figure 10.3, “Execution of an ON-Unit” illustrate the call frames established for the execution of a series of procedures. The callout numbers in the example indicate the order of execution.
The box drawn with broken lines in Figure 10.3, “Execution of an ON-Unit” represents the ON-unit established in procedure A for a FIXEDOVERFLOW condition. Procedure A establishes an ON-unit for the FIXEDOVERFLOW condition, and procedure B establishes an ON-unit for an UNDEFINEDFILE condition for the file PRINTFILE. When a FIXEDOVERFLOW condition is signaled in procedure C, PL/I locates the ON-unit established in procedure A and activates the corresponding ON-unit. When PL/I activates an ON-unit, it creates an activation record for the ON-unit and places the ON-unit on the call stack for execution, as if it were a unique block activation.
A: PROCEDURE OPTIONS (MAIN); ON FIXEDOVERFLOW BEGIN; END; CALL B; B: PROCEDURE; ON UNDEFINEDFILE (PRINTFILE) OPEN FILE(PRINTFILE) TITLE("SYS$OUTPUT"); CALL C: C: PROCEDURE; RETURN; END;
10.4.1. Default Handling for Main Procedures
If the program was entered at a procedure with the MAIN option, PL/I searches for ON-units and performs default condition handling as follows:
PL/I searches for specific ON-units in the following order:
If one of these ON-units exists, it is executed and the search is ended. If the ON-unit completes execution by handling the condition, the program continues at the point at which the condition was signaled.
If none of the above are found in any call frame, the default PL/I condition handler performs one of the following:
If the signal is the ENDPAGE condition, the default PL/I handler executes a PUT PAGE for the file, and then continues the program at the point at which ENDPAGE was signaled.
If the signal is the ERROR condition and the severity is fatal, the default handler signals the FINISH condition. Then, one of the following occurs:
If a FINISH ON-unit is found, its execution is attempted. If it executes a nonlocal GOTO or signals another condition, program execution continues.
If no FINISH ON-unit is found, or if a FINISH ON-unit completes execution by handling the condition, then PL/I resignals the condition to the default OpenVMS condition handler. This handler prints a message, displays a traceback, and terminates the program.
If the signal is UNDERFLOW, a message is printed; continued execution is unpredictable, and the value that caused the condition is replaced by an undefined value. (The value would be set to zero only if OPTIONS (UNDERFLOW) were not specified on the PROCEDURE statement; and it must be specified for UNDERFLOW to be signaled.)
If the signal is any condition other than ENDPAGE, ERROR with a fatal severity, or UNDERFLOW, the default PL/I handler signals the ERROR condition with the severity of the original condition. Then, one of the following occurs:
If an ERROR ON-unit is found, it is executed. If it completes execution by handling the condition, the program continues.
If an ERROR ON-unit is not found, the default PL/I handler resignals the condition. If this resignaling results in control returning to the system, the default OpenVMS condition handler prints a message and a traceback. If the error is a fatal error, the default handler terminates the program; if the error is nonfatal, the program continues.
10.4.2. Default Handling for Non-Main Procedures
If the call frame at which the program was entered did not specify the MAIN option, the default condition handling is as follows:
PL/I searches for specific ON-units in the following order:
If one of these ON-units exists, it is executed and the search is ended. If the ON-unit completes execution by handling the condition, the program continues at the point at which the condition was signaled.
If no ON-units are found in any call frame, the condition is signaled to the caller. If the resignal results in return of control to the system, the default OpenVMS condition handler issues a message and prints a traceback. If the error was a fatal error, the default OpenVMS handler terminates the program. Otherwise, the program continues.
Example 10.4, “Search for an ON-Unit” and Figure 10.4, “Search for an ON-Unit” illustrate a search for an ON-unit that will handle a decimal overflow condition. The numbers in the example indicate the sequence in which the search takes place.
PL/I takes the following actions:
- ❶
Searches the call frame in which the condition was signaled for three specific ON-units: VAXCONDITION(SS$_DECOV_F), FIXEDOVERFLOW, and ANYCONDITION
- ❷
Searches the previous call frame for the same three ON-units
- ❸
Reaches the main procedure and searches it for the three ON-units
- ❹
Signals the ERROR condition
- ❺
Searches the call frame in which the condition was signaled for an ERROR ON-unit
- ❻
Searches the previous call frame for an ERROR ON-unit
- ❼
Locates the ERROR ON-unit in the main procedure and executes it
A: PROCEDURE OPTIONS(MAIN); ❹ ON ERROR BEGIN; ❼ PUT SKIP LIST ('Caught the ERROR condition - in main'); END; CALL B; ❸ B: PROCEDURE; CALL C; RETURN; ❷ ❻ END B; C: PROCEDURE; SIGNAL FIXEDOVERFLOW; RETURN; ❶ ❺ END C; END A;
10.4.3. Multiple Conditions
If a second condition is signaled during the execution of an ON-unit, PL/I searches for an ON-unit that will handle the second condition, beginning in the call frame in which the second condition was signaled. This handling of multiple conditions in PL/I differs from the standard behavior of the OpenVMS condition-handling facility (which skips the call frames that were searched for the current ON-unit). For information on OpenVMS condition handling, see the Introduction to the VMS Run-Time Library.
Example 10.5, “Multiple Conditions” and Figure 10.5, “Effect of Multiple Conditions” illustrate the search sequence followed when a second condition occurs during the execution of an ON-unit. The numbers in the example indicate the order of execution. The ERROR condition in procedure C is handled by the ON-unit established in procedure B. During the execution of this ON-unit, a FIXEDOVERFLOW condition is signaled. PL/I locates the ON-unit established for FIXEDOVERFLOW conditions in procedure C and gives it control. The box drawn with broken lines represents the ERROR ON-unit established by procedure B.
A: PROCEDURE OPTIONS (MAIN); ❶ CALL B; B: PROCEDURE; ❷ ON ERROR BEGIN; ❹ ❺ END; CALL C; C: PROCEDURE; ❸ ON FIXEDOVERFLOW BEGIN; ❻
Note that if the second condition is the same condition as the first, and the ON-unit does not establish another ON-unit, the same ON-unit will be executed repeatedly as the condition is signaled. A similar situation results when a STOP statement is executed within a FINISH or ANYCONDITION ON-unit-that is, the program will enter an infinite loop when the STOP statement executes. The STOP statement signals FINISH, the current ON-unit is reexecuted, the STOP statement is executed again, and so on.
In a PL/I program, an ANYCONDITION ON-unit or a VAXCONDITION ON-unit established specifically to handle the SS$_UNWIND condition is invoked during the unwind. The following example illustrates a VAXCONDITION ON-unit:
DECLARE SS$_UNWIND GLOBALREF VALUE FIXED BINARY(31); ON VAXCONDITION(SS$_UNWIND) BEGIN; CLOSE FILE(DATA_REC_TEMP) ENVIRONMENT( DELETE(NO) ); END;
When an ON-unit that is handling the unwind condition completes execution, the unwind continues.
Note that when an ANYCONDITION ON-unit executes a nonlocal GOTO statement, the nonlocal GOTO causes an unwind, and the first ON-unit that is given control is the ANYCONDITION ON-unit itself. Thus, an infinite loop occurs. To avoid this situation, an ANYCONDITION ON-unit can contain the following lines:
ON ANYCONDITION BEGIN; DECLARE SS$_UNWIND GLOBALREF VALUE FIXED; IF ONCODE() = SS$_UNWIND THEN GOTO OKAY; ⋮ OKAY: END;
This check for the condition SS$_UNWIND ensures that if a nonlocal GOTO is executed in this ON-unit, it will not cause the ON-unit to be reexecuted.
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.
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:
/* 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.
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.
| Field Name | Contents | ||
|---|---|---|---|
| CHF$IS_MCH_ARGS | Count 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$PH_MCH_FRAME | Contains the frame pointer in the procedure context of the establisher. | ||
| CHF$IS_MCH_DEPTH | Positive 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_RESVD1 | Reserved. | ||
| CHF$PH_MCH_DADDR | Address 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_ADDR | Address of the exception stack frame (See the Alpha Architecture Reference Manual). | ||
| CHF$PH_MCH_SIG_ADDR | Address of the signal array. The signal array is a 32-bit wide (longword) array. | ||
CHF$IH_MCH_SAVRnn | Contain 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_SAVFnn | Contain 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. |
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.
%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.
| PL/I Condition | VMS Global Symbol Name[a] |
|---|---|
| AREA | See the Endless PL/I for OpenVMS Reference Manual and Chapter 15, Storage Allocation of this manual for a discussion of allocation in areas. |
| CONDITION | PLI$_CONDITION |
| CONVERSION | PLI$_CONVERSION if a SIGNAL CONVERSION statement was executed, otherwise PLI$_ONCNVPOS (PLI$_ONCNVPOS could change in a future release of PL/I) |
| ENDFILE | PLI$_ENDFILE |
| ENDPAGE | PLI$_ENDPAGE |
| ERROR | A specific status value associated with the error that caused the condition to be signaled[b] |
| FINISH | PLI$_FINISH |
| FIXEDOVERFLOW | SS$_DECOVF or SS$_INTOVF |
| KEY | RMS$_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] |
| OVERFLOW | SS$_FLTOVF or SS$_FLTOVF_F |
| STORAGE | The value returned by LIB$GET_VM |
| STRINGRANGE | PLI$_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) |
| SUBSCRIPTRANGE | PLI$_SUBRANGE or PLI$_SUBRANGEn (where n is a number in the range 1 through 8 indicating the subscript number) |
| UNDEFINEDFILE | RMS$_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] |
| UNDERFLOW | SS$_FLTUND or SS$_FLTUND_F |
| VAXCONDITION | Any user-defined condition value that was signaled |
| ZERODIVIDE | SS$_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.