Unplanned loops can be divided into those that can be detected by CICS®, and those that cannot. In turn, the loops that CICS can detect can be classified into tight loops and non-yielding loops.
Figure 15 gives an example of code containing a simple tight loop.
PROCEDURE DIVISION.
EXEC CICS
HANDLE CONDITION ERROR(ERROR-EXIT)
ENDFILE(END-MSG)
END-EXEC.
ROUTE-FILE.
EXEC CICS
ROUTE INTERVAL(0)
LIST(TERM-ID)
END-EXEC.
NEW-LINE-ATTRIBUTE.
GO TO NEW-LINE-ATTRIBUTE.
MOVE LOW-VALUES TO PRNTAREA.
MOVE DFHBMPNL TO PRNTAREA.
CICS can detect some looping tasks by comparing the length of time the tasks have been running with the runaway time interval, ICVR, that you code in the system initialization table. If a task runs for longer than the interval you specify, CICS regards it as "runaway" and causes it to abend with an abend code of AICA.
However, in some cases, CICS requests that are contained in the looping code can cause the timer to be reset. Not every CICS request can do this; it can only happen if the request can cause the task to be suspended. Thus, if the looping code contains such a request, CICS cannot detect that it is looping.
The properties of the different types of loop, and the ways you can investigate them, are described in the sections that follow.
Tight loops and non-yielding loops are both characterized by the fact that the looping task can never be suspended within the limits of the loop. This makes them detectable by CICS, which compares the time they have been running continually with the runaway time interval, ICVR, that you code in the system initialization table. If the tasks run for longer than the interval you specify, CICS regards them as "runaway" and causes them to abend with an abend code of AICA.
A tight loop is one involving a single program, where the same instructions are executed repeatedly and control is never returned to CICS. In the extreme case, there could be a single instruction in the loop, causing a branch to itself.
A non-yielding loop is also contained in a single program, but it differs from a tight loop in that control is returned temporarily from the program to CICS. However, the CICS routines that are invoked are ones that neither suspend the program nor pass control to the dispatcher. The CICS commands that do not cause tasks to wait include (but are not restricted to) ASKTIME, DEQ, ENQ, ENTER TRACENUM, FREEMAIN, HANDLE, RELEASE, TRACE ON/OFF. Whether a command allows the ICVR to be reset might also depend on other factors. For instance, a FREEMAIN might reset the ICVR if the storage lock is held. A READ might also not wait if the desired record is already in a VSAM buffer. There is, therefore, no point at which the task can be suspended, and so the ICVR cannot be reset.
Figure 16 shows an example of code that contains a simple non-yielding loop. In this case, the loop contains only one CICS command, EXEC CICS ASKTIME.
PROCEDURE DIVISION. EXEC CICS HANDLE CONDITION ERROR(ERROR-EXIT) ENDFILE(END-MSG) END-EXEC. ROUTE-FILE. EXEC CICS ROUTE INTERVAL(0) LIST(TERM-ID) END-EXEC. NEW-LINE-ATTRIBUTE. EXEC CICS ASKTIME END-EXEC. GO TO NEW-LINE-ATTRIBUTE. MOVE LOW-VALUES TO PRNTAREA. MOVE DFHBMPNL TO PRNTAREA.
If you have a transaction that repeatedly abends with an abend code of AICA, first make sure the ICVR value has not been set too low. If the value seems reasonable, read Investigating loops that cause transactions to abend with abend code AICA for advice on determining the limits of the loop.
If you have a stalled CICS region, diagnose the problem using the techniques in What to do if CICS has stalled. Check if the ICVR value has been set to zero. If it has, change the value and try to cause a transaction to abend with a code of AICA.
Yielding loops are characterized by returning control at some point to a CICS routine that can suspend the looping task. However, the looping task is eventually resumed, and so the loop continues.
CICS is unable to use the runaway task timer to detect yielding loops, because the timer is reset whenever the task is suspended. Thus, the runaway task time is unlikely ever to be exceeded, and so the loop goes undetected by the system.
Yielding loops typically involve a number of programs. The programs might be linked to and returned from, or control might be transferred from one program to another in the loop. A yielding loop can also be confined to just one program, in which case it must contain at least one wait-enabling CICS command.
Figure 17 shows a specific example of a yielding loop within a single program. This code issues the SUSPEND command, which is always a yielding type of command. Every time SUSPEND is issued, the dispatcher suspends the task issuing the request, and sees if any other task of higher priority can run. If no such task is ready, the program that issued the SUSPEND is resumed.
PROCEDURE DIVISION.
EXEC CICS
HANDLE CONDITION ERROR(ERROR-EXIT)
ENDFILE(END-MSG)
END-EXEC.
ROUTE-FILE.
EXEC CICS
ROUTE INTERVAL(0)
LIST(TERM-ID)
END-EXEC.
NEW-LINE-ATTRIBUTE.
EXEC CICS
SUSPEND
END-EXEC.
GO TO NEW-LINE-ATTRIBUTE.
MOVE LOW-VALUES TO PRNTAREA.
MOVE DFHBMPNL TO PRNTAREA.
You can detect a yielding loop only by circumstantial evidence such as repetitive output, or excessive use of storage. A fuller description of what to look out for is given in Loops.
If you suspect that you have a yielding loop, turn to Investigating loops that are not detected by CICS for further guidance.