Previous | Contents | Index |
An exception condition, as the term is used in this chapter, is an event, usually an error, that occurs during the execution of a program and is detected by system hardware or software or by logic in a user application program. To resolve exception conditions, you can create a condition-handler routine.
This chapter addresses error handling only as it relates to the creation and use of condition-handler routines. Condition-handler routines are specific to the OpenVMS operating system. For a general discussion of error handling, see Chapter 7.
Examples of the types of exception conditions detected by system hardware and software are as follows:
When an exception condition is detected by system hardware or software or by your program, that condition is signaled (by means of a signal call) to the OpenVMS Condition-Handling Facility (CHF). The CHF then invokes one or more condition-handler routines that will attempt to either resolve the condition or terminate the processing in an orderly fashion.
The CHF allows a main program and each subprogram that follows it, regardless of call depth, to establish a condition-handler routine (one per program unit). Each of these condition-handler routines can potentially handle any or all software or hardware events that are treated as exception conditions by the user program or by the system hardware or software. More than one condition handler for a given condition can be established by different program units in the call stack (see the OpenVMS Programming Concepts Manual).
The address of the condition handler for a particular program unit is placed in the call frame for that unit in the run-time call stack.
When the program unit returns to its caller, the call frame is removed and the condition handler for that program unit can no longer be accessed by the CHF. Multiple condition handlers can be accessed by the CHF in the processing of a single exception condition signal. A process-wide handler can be established using the SYS$SETEXV system service.
Throughout this chapter, the term program unit refers to an executable Fortran main program, subroutine, or function.
For More Information:
The Condition-Handling Facility (CHF) receives control and coordinates processing of all exception conditions that are signaled to it. The signals are issued under the following circumstances:
In cases where the default condition handling is insufficient (see Section 14.2), you can develop your own handler routines and use the Compaq Fortran intrinsic function LIB$ESTABLISH to identify your handlers to the CHF. Typically, your needs for special condition handling are limited to the following types of operations:
When an exception condition is detected by a system hardware or software component or by a component in the user application program, the component calls the CHF by means of a signal routine (LIB$SIGNAL or LIB$STOP), passing a value to the CHF that identifies the condition. The CHF takes program control away from the routine that is currently executing and begins searching for a condition-handler routine to call. If it finds one, it establishes a call frame on the run-time call stack and then invokes the handler. The handler routine then attempts to deal with the condition.
The sections that follow describe the CHF in detail---how it operates, how user programs can interact with it, and how users can code their own condition-handling routines:
When the system creates a Compaq Fortran user process, it establishes a system-defined condition handler that will be invoked by the CHF under the following circumstances:
When establishing the default handler, the system has two handlers to choose from: the traceback handler and the catchall handler.
The /DEBUG and /TRACEBACK qualifiers---on the FORTRAN and LINK command lines, respectively---determine which default handler is enabled. If you take the defaults for these qualifiers, the traceback handler is established as the default handler. To establish the catchall handler as the default, specify /NODEBUG or /DEBUG=NOTRACEBACK on the FORTRAN command line and /NOTRACEBACK on the LINK command line.
Use the FORTRAN command /SYNCHRONOUS_EXCEPTIONS qualifier to ensure precise exception reporting.
For More Information:
User-program interactions with the CHF are strictly optional and application-dependent. In each program unit, you have the option of establishing (and removing) a single condition handler to handle exceptions that may occur in that program unit or in subsequent subprograms (regardless of call depth). Once a program unit returns to its caller, its call frame is removed and any condition handler that the program unit has established becomes inaccessible.
The condition handler established by the user program can be coded to handle an exception condition signaled either by system hardware, a Compaq Fortran system software component, or the user program itself. User-program signals are issued by means of the LIB$STOP and LIB$SIGNAL routines described in Section 14.3.2.
Although condition handlers offer a convenient and structured approach to handling exception conditions, they can have a significant impact on run-time performance when a condition handler is actually used. For commonly occurring application-specific conditions within a loop, for example, it may be wise to use other methods of dealing with the conditions. The best use of the facility is in large applications in which occasional exception conditions requiring special handling are anticipated.
The following sections describe how to establish and remove condition
handlers and how to signal exception conditions.
14.3.1 Establishing and Removing Condition Handlers
To establish a condition handler, call the LIB$ESTABLISH intrinsic function. (For compatibility with Compaq Fortran 77 for OpenVMS VAX Systems, Compaq Fortran provides the LIB$ESTABLISH and LIB$REVERT routines as intrinsic functions.)
The form of the call can be as a subroutine or a function reference, as follows:
CALL LIB$ESTABLISH (new-handler) old-handler=LIB$ESTABLISH(new-handler) |
new-handler
Specifies the name of the routine to be set up as a condition handler.old-handler
Receives the address of the previously established condition handler.
LIB$ESTABLISH moves the address of the condition-handling routine into the appropriate process context and returns the previous address of a previously established condition handler.
The handler itself could be user-written or selected from a list of utility functions provided with Compaq Fortran. The following example shows how a call to establish a user-written handler might be coded:
EXTERNAL HANDLER CALL LIB$ESTABLISH(HANDLER) |
In the preceding example, HANDLER is the name of a Fortran function subprogram that is established as the condition handler for the program unit containing these source statements. A program unit can remove an established condition handler in two ways:
The LIB$REVERT call has no arguments and can be a subroutine or a function reference, as follows:
CALL LIB$REVERT old-handler=LIB$REVERT() |
The use of old-handler for the LIB$REVERT call is the same as for the LIB$ESTABLISH call.
This call removes the condition handler established in the current program unit. Like LIB$ESTABLISH, LIB$REVERT is provided as an intrinsic function.
When the program unit returns to its caller, the condition handler
associated with that program unit is automatically removed (the program
unit's stack frame, which contains the condition handler address, is
removed from the stack).
14.3.2 Signaling a Condition
When a prescribed condition requiring special handling by a condition handler is detected by logic in your program, you issue a condition signal in your program in order to invoke the CHF. A condition signal consists of a call to one of the two system-supplied signal routines in the following forms:
EXTERNAL LIB$SIGNAL, LIB$STOP CALL LIB$SIGNAL(condition-value, arg, ..., arg) CALL LIB$STOP(condition-value, arg, ..., arg) |
condition-value
An INTEGER (KIND=4) value that identifies a particular exception condition (see Section 14.3.3) and can only be passed using the %VAL argument-passing mechanism.arg
Optional arguments to be passed to user-established condition handlers and the system default condition handlers. These arguments consist of messages and formatted-ASCII-output arguments (see the OpenVMS Run-Time Library Routines Volume.
The CHF uses these parameters to build the signal argument array SIGARGS (see Section 14.5) before passing control to a condition handler.
Whether you issue a call to LIB$SIGNAL or LIB$STOP depends on the following considerations:
Figure 14-1 lists all of the possible effects of a LIB$SIGNAL or LIB$STOP call.
Figure 14-1 Effects of Calls to LIB$SIGNAL or LIB$STOP
In Figure 14-1, "cannot continue" indicates an error that results in the following message:
IMPROPERLY HANDLED CONDITION, ATTEMPT TO CONTINUE FROM STOP |
To pass the condition value, you must use the %VAL argument-passing mechanism (see Section 10.2.3). Condition values are usually expressed as condition symbols (see Section 10.7.1). Condition symbols have either of the following forms:
fac$_symbol (Compaq-defined) |
fac__symbol (user-defined) |
fac
A facility name prefix.symbol
Identifies a specific condition. (See Table 7-1 for a list of Compaq Fortran condition symbols.)
In the following example, a signal call passes a condition symbol used to report a missing required privilege.
CALL LIB$SIGNAL(%VAL(SS$_NOSYSPRV) |
You can include additional arguments to provide supplementary information about the error. System symbols such as SS$_NOSYSPRV are defined in the library module $SSDEF.
When your program issues a condition signal, the CHF searches for a
condition handler by examining the preceding call frames, in order,
until it either finds a procedure that handles the signaled condition
or reaches the default condition handler. Condition handling procedures
should use SS$_RESIGNAL for conditions they are not intended to handle.
14.3.3 Condition Values and Symbols Passed to CHF
The OpenVMS system uses condition values to indicate that a called procedure has either executed successfully or failed, and to report exception conditions. Condition values are INTEGER (KIND=4) values (see the OpenVMS Programming Concepts Manual and the OpenVMS Calling Standard for details). They consist of fields that indicate which software component generated the value, the reason the value was generated, and the severity of the condition. A condition value has the following fields:
The facility number field identifies the software component that generated the condition value. Bit 27 = 1 indicates a user-supplied facility; bit 27 = 0 indicates a system facility.
The message number field identifies the condition that occurred. Bit 15 = 1 indicates that the message is specific to a single facility; bit 15 = 0 indicates a system-wide message.
Table 14-1 gives the meanings of values in the severity code field.
Code (Symbolic Name) | Severity | Response |
---|---|---|
0 (STS$K_WARNING) | Warning | Execution continues, unpredictable results |
1 (STS$K_SUCCESS) | Success | Execution continues, expected results |
2 (STS$K_ERROR) | Error | Execution continues, erroneous results |
3 (STS$K_INFORMATION) | Information | Execution continues, informational message displayed |
4 (STS$K_SEVERE) | Severe error | Execution terminates, no output |
5 - 7 | -- | Reserved for use by Compaq |
The symbolic names for the severity codes are defined in the $STSDEF library module in the Compaq Fortran Symbolic Definition Library, FORSYSDEF.
A condition handler can alter the severity code of a condition value---either to allow execution to continue or to force an exit, depending on the circumstances.
The condition value is passed in the second element of the array SIGARGS. (See Section 14.5 for detailed information about the contents and use of the array SIGARGS.) In some cases, you may require that a particular condition be identified by an exact match; each bit of the condition value (31:0) must match the specified condition. For example, you may want to process a floating overflow condition only if its severity code is still 4 (that is, only if a previous handler has not changed the severity code).
In many cases, however, you may want to respond to a condition regardless of the value of the severity code. To ignore the severity and control fields of a condition value, use the LIB$MATCH_COND routine (see Section 14.7).
The FORSYSDEF library contains library modules that define condition symbols. When you write a condition handler, you can specify any of the following library modules, as appropriate, with an INCLUDE statement:
CHF$_xxxxxxx |
For example:
CHF$_IH_MCH_SAVR0 |
FOR$_error |
For example:
FOR$_INPCONERR |
LIB$_condition |
For example:
LIB$_INSVIRMEM |
MTH$_condition |
For example:
MTH$_SQUROONEG |
SS$_status |
For example:
SS$_BADPARAM |
For More Information:
A condition handler responds to an exception by analyzing arguments passed to it and by taking appropriate action. Possible actions taken by condition handlers are as follows:
First, the handler must determine whether it can correct the condition identified by the condition code passed by the signal call. If possible, the handler takes the appropriate corrective action and execution continues. If it cannot correct the condition, the handler can resignal the condition; it can request that another condition handler (associated with an earlier program unit in the call stack) attempt to process the exception.
Condition reporting performed by handlers can involve one or more of the following actions:
Execution can be affected in a number of ways, such as:
For More Information:
A Compaq Fortran condition handler is an INTEGER (KIND=4) function that has two argument arrays passed to it by the CHF. To meet these requirements, you could define a condition handler as follows:
INCLUDE '($CHFDEF)' INTEGER (KIND=4) FUNCTION HANDLER(SIGARGS,MECHARGS) INTEGER (KIND=4) SIGARGS(*) RECORD /CHFDEF2/ MECHARGS |
The CHF creates the signal and mechanism argument arrays SIGARGS and MECHARGS and passes them to the condition handler. Note that the mechanism vector block differs on Alpha systems from OpenVMS VAX systems (see the OpenVMS Calling Standard).
The signal array (SIGARGS) is used by condition handlers to obtain information passed as arguments in the LIB$SIGNAL or LIB$STOP signal call. The contents of SIGARGS are as follows:
Array Element | CHFDEF1 Field Name | Contents |
---|---|---|
SIGARGS(1) | CHF$IS_SIG_ARGS | Argument count (n) |
SIGARGS(2) | CHF$IS_SIG_NAME | Condition code |
SIGARGS(3 to
n-1)
. . |
CHF$IS_SIG_ARG1 (first argument) | Zero or more additional arguments, specific to the condition code in SIGARGS(2) |
SIGARGS( n) | None | PC (program counter) |
SIGARGS( n+1) | None | PS (processor status), lower 32-bits of the 64-bit OpenVMS Alpha processor status |
A condition handler is usually written in anticipation of a particular condition code or set of condition codes. Because handlers are invoked as a result of any signaled condition code, you should begin your handler routine by comparing the condition code passed to the handler (element 2 of SIGARGS) with the condition codes expected by the handler. If the signaled condition code is not an expected code, you should resignal the condition code by equating the function value of the handler to the global symbol SS$_RESIGNAL (see Section 14.6).
The mechanism array (MECHARGS) is used to obtain information about the procedure activation of the program unit that established the condition handler. MECHARGS is a 88-element array, but only integer registers (Rn) and floating-point registers (Fn) are contained beyond element 12 (R0 is in elements 13 and 14 and all registers are 64 bits). The contents of MECHARGS are as follows:
INTEGER (KIND=4) Array Element | CHFDEF2 Field Name | Contents |
---|---|---|
MECHARGS(1) | CHF$IS_MCH_ARGS | Argument count |
MECHARGS(2) | CHF$IS_MCH_FLAGS | Flags |
MECHARGS(3), MECHARGS(4) | CHF$PH_MCH_FRAME | Frame address pointer |
MECHARGS(5) | CHF$IS_MCH_DEPTH | Call depth |
MECHARGS(6) | CHF$IS_MCH_RESVD1 | Not used |
MECHARGS(7), MECHARGS(8) | CHF$PH_MCH_DADDR | Handler data address |
MECHARGS(9), MECHARGS(10) | CHF$PH_MCH_ESF_ADDR | Exception stack frame address |
MECHARGS(11), MECHARGS(12) | CHF$PH_MCH_SIG_ADDR | Signal array address |
MECHARGS(13), MECHARGS(14) |
CHF$IH_MCH_SAVR0
CHF$IL_MCH_SAVR0_LOW CHF$IL_MCH_SAVR0_HIGH |
R0
low-order 32 bits high-order 32 bits |
MECHARGS(15), MECHARGS(16) |
CHF$IH_MCH_SAVR1
CHF$IL_MCH_SAVR1_LOW CHF$IL_MCH_SAVR10_HIGH |
R1
low-order 32 bits high-order 32 bits |
MECHARGS(17) to MECHARGS(42) | CHF$IH_MCH_SAVR nn | R16-R28 |
MECHARGS(43), MECHARGS(44) | CHF$FH_MCH_SAVF0(2) | F0 |
MECHARGS(45), MECHARGS(46) | CHF$FH_MCH_SAVF1(2) | F1 |
MECHARGS(47) to MECHARGS(88) | CHF$IH_MCH_SAVF nn(2) | F10-F30 |
Inside a condition handler, you can use any other variables that you need. If they are shared with other program units (for example, in common blocks), make sure that they are declared volatile. This will ensure that compiler optimizations do not invalidate the handler actions. See Section 5.7.3 and the Compaq Fortran Language Reference Manual for more information on the VOLATILE statement.
For More Information:
Previous | Next | Contents | Index |