Cancel handlers provide an important function by allowing you to get control for clean-up and recovery actions when call stack entries are terminated by something other than a normal return. For example, you might want one to get control when a procedure ends via a system request '2', or because an inquiry message was answered with 'C' (Cancel).
The Register Call Stack Entry Termination User Exit Procedure (CEERTX) and the Call Stack Entry Termination User Exit Procedure (CEEUTX) ILE bindable APIs provide a way of dynamically registering a user-defined routine to be run when the call stack entry for which it is registered is cancelled. Once registered, the cancel handler remains in effect until the call stack entry is removed, or until CEEUTX is called to disable it. For more information on these ILE bindable APIs, see the CL and APIs section of the Programming category in the System i Information Center at this Web site - http://www.ibm.com/systems/i/infocenter/.
Figure 145 shows an example of enabling and coding a cancel handler for a subprocedure. (Cancel handlers can also be enabled for cycle-main procedures in the same way.)
*-----------------------------------------------------------------
* Define the prototype for the cancel handler. This procedure is
* a local procedure.
*-----------------------------------------------------------------
D CanHdlr PR
D pMsg *
*-----------------------------------------------------------------
* Define the prototype for a subprocedure to enable the cancel
* handler.
*-----------------------------------------------------------------
D Enabler PR
*-----------------------------------------------------------------
* Define the prototype for a subprocedure to call Enabler
*-----------------------------------------------------------------
D SubProc PR
*-----------------------------------------------------------------
* Main procedure. Call SubProc three times.
*-----------------------------------------------------------------
C CALLP SubProc
C CALLP SubProc
C CALLP SubProc
C SETON LR
*-----------------------------------------------------------------
* Procedure SubProc. Call Enabler. Since this call will fail,
* define a local *PSSR subroutine to handle the error.
*-----------------------------------------------------------------
P SubProc B
C CALLP Enabler
*-----------------------------------------------------------------
* The PSSR has a RETURN operation, so the call from the main
* procedure to SubProc will not fail.
*-----------------------------------------------------------------
C *PSSR BEGSR
C 'Subproc PSSR'DSPLY
C RETURN
C ENDSR
P SubProc E
*-----------------------------------------------------------------
* Procedure Enabler. This procedure enables a cancel handler,
* then gets an error which causes Enabler to be canceled.
*-----------------------------------------------------------------
P Enabler B
* Local variables
D Handler S * PROCPTR INZ(%PADDR('CANHDLR'))
D Msg S 20A
D pMsg S * INZ(%ADDR(Msg))
D Zero S 5P 0 INZ(0)
D Count S 5I 0 INZ(0) STATIC
D Array S 1A DIM(2)
*-----------------------------------------------------------------
* Enable the cancel handler. When this procedure gets canceled,
* procedure 'CANHDLR' will be called.
*-----------------------------------------------------------------
C CALLB 'CEERTX'
C PARM Handler
C PARM pMsg
C PARM *OMIT
*-----------------------------------------------------------------
* This procedure will be called three times. The first two times
* will get an error while the cancel handler is enabled.
*-----------------------------------------------------------------
C EVAL Count = Count + 1
C SELECT
C WHEN Count = 1
C EVAL Msg = 'Divide by zero'
C EVAL Zero = Zero / Zero
C WHEN Count = 2
C EVAL Msg = 'String error'
C 'A' SCAN 'ABC':Zero Zero
*-----------------------------------------------------------------
* On the third call, disable the cancel handler. The array index
* error will cause the procedure to fail, but the handler will
* not be invoked.
*-----------------------------------------------------------------
C WHEN Count = 3
C CALLB 'CEEUTX'
C PARM Handler
C PARM *OMIT
C EVAL Msg = 'Array index error'
C EVAL Array(Zero) = 'x'
C ENDSL
P Enabler E
*-----------------------------------------------------------------
* Define the cancel handler. The parameter is a pointer to the
* 'communication area', a message to be displayed.
*-----------------------------------------------------------------
P CanHdlr B
D CanHdlr PI
D pMsg *
*-----------------------------------------------------------------
* Define a field based on the input pointer pMsg.
*-----------------------------------------------------------------
D Msg S 20A BASED(pMsg)
*-----------------------------------------------------------------
* Display the message set by the procedure that enabled the
* handler.
*-----------------------------------------------------------------
C 'Cancel Hdlr 'DSPLY Msg
P CanHdlr E
The following is the output from program CANHDLR. Note that the *PSSR of the procedure SubProc is called three times but the cancel handler is only called twice because it was disabled before the third error.
DSPLY Cancel Hdlr Divide by zero
DSPLY Subproc PSSR
DSPLY Cancel Hdlr String error
DSPLY Subproc PSSR
DSPLY Subproc PSSR