Previous | Contents | Index |
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 and Figure 10-3 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 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.
Example 10-3 Execution of an ON-Unit |
---|
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; |
Figure 10-3 Execution of an ON-Unit
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:
If the call frame at which the program was entered did not specify the MAIN option, the default condition handling is as follows:
Example 10-4 and Figure 10-4 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:
Example 10-4 Search for an ON-Unit |
---|
A: PROCEDURE OPTIONS(MAIN); (4) ON ERROR BEGIN; (7) PUT SKIP LIST ('Caught the ERROR condition - in main'); END; CALL B; (3) B: PROCEDURE; CALL C; RETURN; (2) (6) END B; C: PROCEDURE; SIGNAL FIXEDOVERFLOW; RETURN; (1) (5) END C; END A; |
Figure 10-4 Search for an ON-Unit
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 and Figure 10-5 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.
Example 10-5 Multiple Conditions |
---|
A: PROCEDURE OPTIONS (MAIN); (1) CALL B; B: PROCEDURE; (2) ON ERROR BEGIN; (4) (5) END; CALL C; C: PROCEDURE; (3) ON FIXEDOVERFLOW BEGIN; (6) |
Figure 10-5 Effect of Multiple Conditions
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:
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; |
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 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 and Figure 10-7 illustrate the argument list and the arguments that can be accessed through this list for Kednos PL/I for OpenVMS VAX and Kednos PL/I for OpenVMS Alpha respectively.
Figure 10-6 The Argument List Passed to an ON-UNIT on OpenVMS VAX
Example 10-6 displays the text module $CHFDEF, which contains Kednos PL/I 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
Table 10-1 explains the contents of the OpenVMS Alpha mechanism array arguments shown in Figure 10-7. Example 10-7 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_SAVR nn | 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_SAVF nn | 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. |
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 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; (1) DECLARE X FIXED; CHF$ARGPTR = ONARGSLIST(); (2) /* Output number of signal arguments */ PUT SKIP LIST('Signal Arg Count',CHF$SIG_ARGS); (3) /* Output condition name argument and rest of signal arguments */ PUT SKIP LIST('Condition name', CHF$SIG_NAME); (4) PUT SKIP LIST(DIM(CHF$SIG_ARG,1), 'additional arguments:'); (5) 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); (6) PUT SKIP(2) LIST('r1:',CHF$MCH_SAVR1); END; |
Previous | Next | Contents | Index |