Error Handling

Error Handlers

In addition to handling an error locally with an iferr block, it is also possible to handle an error globally by posting an error handling procedure. The purpose of posting an error handling procedure is to restore the computer to a known state when a program exits abnormally with an error. Error handlers can be posted with onerror or xwhen. Error handlers posted with onerror are called whatever the type of error that occurred. Also, the program will not continue executing after an error handler is called. Error handlers posted with xwhen are associated with a particular error code and execution of the program will continue after the error handler exits.

Table 3.3: Error Handlers.

The procedure onerror() has a single argument, the name of the error handling procedure. The error handling procedure must be declared external with the extern statement. If an error occurs in the program after the error handling procedure is posted, the error handling procedure will be called before the normal program cleanup. The error handling procedure will be passed a single argument, the error code passed to the error procedure. Other information necessary for the error handling procedure should be passed through the common block.

The following example shows how an error handling procedure is posted by onerror and what it looks like. The first procedure, term_init, opens the terminal for reading and writing and puts the terminal in raw mode. The second procedure, term_end, closes the terminal and restores the terminal from raw mode. Since leaving the terminal in raw mode after the program exits will cause a lot of problems, term_init posts an error handling routine to restore the terminal. The error handling routine simply calls the normal exit procedure, term_end. Note the file descriptors are set to NULL after they are closed. This is so that if an error occurs in the program after term_end is called, the error handling routine will not try to close the same file descriptors twice.

There are two kinds of errors that can occur during the execution of a program, synchronous and asynchronous errors. Synchronous errors occur when the task calls the error() procedure. These are synchronous errors because the task is in a known state when the error condition occurs. As a result, error handling is relatively simple. Synchronous errors can be caught by an iferr block, as described previously. Asynchronous errors, also known as exceptions, occur when the hardware detects an illegal condition. Because these errors are detected by the hardware and not by the program, the program is in an unknown state when the error occurs. This makes error handling more difficult. IRAF divides all asynchronous errors into four kinds: access violations, arithmetic errors, interrupts, and interprocess communication errors. IRAF has a default exception handler for all asynchronous errors. The default exception handler does a non-local jump to the IRAF main routine, prints an error message, performs task cleanup such as closing files, and exits normally. If this default behavior is not sufficient, a program can post its own error handler by calling xwhen.

xwhen takes three arguments. The first two are inputs and the third is an output. The two inputs are a symbolic constant indicating the error to be trapped and the address of the error handling procedure. The symbolic constants are defined in xwhen.h. The address of a procedure is computed from the function locpr. The output is the address of the old error handling procedure. This is provided so that the program can restore the old error handler later or so that it can chain error handlers by calling the old error handler when the error handler exits. The error handling procedure has two arguments. The first is an input, the symbolic constant representing the error code. The second is an output, the address of error handler to call after the error handler returns. If the error handler does not chain to another error handler, the second parameter should be set to the symbolic constant X_IGNORE.

Usually an error handler resumes execution of a program by performing a non-local jump. A non-local jump is performed by calling two procedures, zsvjmp and zdojmp. Zsvjmp saves the current state of the computer in an array. The length of this array is hardware dependent and is specified by a symbolic constant in config.h. Zdojmp takes the array generated by zsvjmp and uses it to restore the computer state to what it was when zsvjmp was called. Thus the program calls zdojmp and returns from zsvjmp. Zsvjmp has a second argument, status, which indicates whether the return from zsvjmp is a normal return or a result of a call of zdojmp. The value returned from zsvjmp is the second argument of zdojmp or OK if zdojmp was not called. When using non-local jumps, the condition which caused the error must not be repeated or the program will go into an infinite loop.

Example 3.7 shows how to post an error handler with xwhen. Only two of the four asynchronous errors are trapped, access violations and arithmetic errors. The old error handlers are saved in local variables so that they can be restored at the end of the subroutine. The system state is saved by procedure zsvjmp. The length of the array is given by a symbolic constant defined in the header file config.h. The procedure then calls do_cmp, which executes the command read from the file. If an access violation or arithmetic error occurs while the command is being executed, the program will call err_cmd. This procedure restores the system state by calling zdojmp. The array with the system state is passed through a common block. The program then returns from zdojmp and prints the error message.

Table 3.3: - Error Handlers.

Generated with CERN WebMaker