Showing posts with label GOBACK. Show all posts
Showing posts with label GOBACK. Show all posts

Sunday, 22 September 2013

COBOL Program Termination and Reentry: State and Run Units

A subprogram that executes GOBACK can be called again with its changed Working-Storage still present. Returning control and resetting program state are separate events, which is the central rule behind COBOL program termination and reentry.

COBOL program termination and reentry showing main program subprogram and next-call state
Termination selects the return path; INITIAL, CANCEL, and storage sections determine state on the next call.

Main program, subprogram, and run unit

The first COBOL program in a run unit is the main program. Programs it calls are subprograms; no source declaration permanently marks a separately compiled program as one or the other. The same program can therefore behave differently depending on how it is entered. See COBOL application structure for the calling hierarchy.

Two questions: when a program ends, determine where control must go. When it is called again, determine whether Working-Storage should retain its last-used values or return to its initial values.

Termination statements compared

StatementIn a main programIn a subprogramScope
GOBACKReturns to the caller of the main program, often the operating system.Returns to the statement after the active CALL.Adapts to the program's role.
EXIT PROGRAMNo action.Returns to the calling program without ending the run unit.Called-program return only.
STOP RUNTerminates the run unit and returns to the caller of the main program.Terminates the run unit rather than returning one CALL level.Whole run unit or Language Environment enclave.

GOBACK works in both roles

PROCEDURE DIVISION USING LK-REQUEST LK-RESULT. PERFORM CALCULATE-RESULT GOBACK.

In a called program, GOBACK returns to the instruction after the active CALL. In a main program, it behaves like program termination and returns to the main program's caller. Statements placed after an executed GOBACK are not run, so keep it last in the path.

The dedicated COBOL EXIT and GOBACK guide owns detailed statement syntax. This page concentrates on return scope and reentry state.

EXIT PROGRAM returns from a subprogram

IF LK-REQUEST-VALID = 'N' MOVE 12 TO RETURN-CODE EXIT PROGRAM END-IF

EXIT PROGRAM returns from a called program without ending the run unit. In a main program it has no effect. When a called program reaches its end with no next executable statement, Enterprise COBOL supplies an implicit EXIT PROGRAM, but an explicit termination path is easier to review.

STOP RUN ends the run unit

MOVE 8 TO RETURN-CODE STOP RUN.

STOP RUN closes files in programs belonging to the run unit, terminates the run unit, and returns using the current RETURN-CODE value according to IBM's documented rules. If a subprogram executes STOP RUN, control does not simply return to its immediate caller.

CICS boundary: IBM states that STOP RUN in a CICS environment terminates the entire transaction and its programs. Use the application framework's normal return design; the CICS transaction-flow guide explains task completion.

For statement-specific details, use the separate COBOL STOP RUN page.

Why a returned subprogram can keep old values

IDENTIFICATION DIVISION. PROGRAM-ID. COUNTER1. WORKING-STORAGE SECTION. 01 WS-CALL-COUNT PIC 9(4) VALUE ZERO. LINKAGE SECTION. 01 LK-CALL-COUNT PIC 9(4). PROCEDURE DIVISION USING LK-CALL-COUNT. ADD 1 TO WS-CALL-COUNT MOVE WS-CALL-COUNT TO LK-CALL-COUNT GOBACK.

A normally returned subprogram is usually left in its last-used state. Two calls to COUNTER1 in the same run unit can therefore return 1 and then 2. Return points for performed ranges are reset, but ordinary Working-Storage values can persist.

This is different from Working-Storage versus Local-Storage: Local-Storage is allocated for each invocation and its VALUE clauses are applied on entry.

Three ways to obtain initial state

Use IS INITIAL on PROGRAM-ID

PROGRAM-ID. COUNTER1 IS INITIAL.

The program and its contained programs enter initial state whenever called. Items with VALUE clauses are restored, altered GO TO and PERFORM state is reset, and non-EXTERNAL files are closed as part of initial-state handling.

Compile with the INITIAL option

The compiler option makes the program and its nested programs behave as if IS INITIAL were coded. The focused COBOL INITIAL compiler-option guide covers scope and defaults.

CANCEL an inactive dynamically called program

CALL WS-PROGRAM-NAME USING WS-REQUEST WS-RESULT CANCEL WS-PROGRAM-NAME CALL WS-PROGRAM-NAME USING WS-REQUEST WS-RESULT

A valid CANCEL breaks the program's logical connection so the next call enters initial state. IBM notes that no action is taken when the target has not been dynamically called in the run unit. Do not cancel an active program, a caller above the current program, or a target still active on another thread.

Caller and subprogram example

01 WS-PGM-NAME PIC X(8) VALUE 'COUNTER1'. 01 WS-COUNT PIC 9(4). CALL WS-PGM-NAME USING WS-COUNT DISPLAY 'FIRST=' WS-COUNT CALL WS-PGM-NAME USING WS-COUNT DISPLAY 'SECOND=' WS-COUNT CANCEL WS-PGM-NAME CALL WS-PGM-NAME USING WS-COUNT DISPLAY 'AFTER CANCEL=' WS-COUNT

With the preceding counter subprogram and a dynamic call, typical values are 1, 2, and then 1 after CANCEL. The COBOL CALL statement guide covers USING modes and exception phrases.

Common termination and reentry mistakes

  • Using EXIT PROGRAM in the main program: it performs no termination action there.
  • Using STOP RUN as a subprogram return: it ends the run unit rather than one call level.
  • Assuming Working-Storage resets on every CALL: a returned subprogram is normally in last-used state.
  • Confusing INITIALIZE with IS INITIAL: INITIALIZE changes selected data items; IS INITIAL controls program state on entry.
  • Canceling after every call for performance: dynamic load and initialization work can add overhead; use CANCEL when lifecycle requirements call for it.
  • Ignoring open resources: design file, Db2, and CICS cleanup around the actual termination scope.

Official IBM references

Frequently asked questions

What is the safest COBOL termination statement for both main programs and subprograms?

GOBACK is commonly used because it returns appropriately from either a main program or a called subprogram. The required behavior and site standards still determine the final choice.

Does EXIT PROGRAM end a main COBOL program?

No. EXIT PROGRAM has no effect when executed in a main program. It returns control from a called subprogram without ending the run unit.

Does Working-Storage reset when a COBOL subprogram is called again?

Usually not. A normally returned subprogram is generally reentered in its last-used state. IS INITIAL, the INITIAL compiler option, or a valid CANCEL can cause initial-state entry; LOCAL-STORAGE is allocated afresh for each invocation.

What does STOP RUN do in a COBOL subprogram?

STOP RUN ends the run unit rather than returning only one level to the immediate caller. In CICS it terminates the transaction, so it is not a substitute for a normal subprogram return.

Review rule: choose the return scope first, then document whether a later CALL must see last-used Working-Storage or initial state.

COBOL Called Subprogram: LINKAGE and USING Example

CALL 'CALCTAX' USING WS-GROSS-PAY WS-TAX
    ON EXCEPTION
        DISPLAY 'CALCTAX IS NOT AVAILABLE'
END-CALL

A COBOL called subprogram receives control when the caller executes CALL. In this example, the calling program passes gross pay and tax fields by reference. The subprogram describes those arguments in its LINKAGE SECTION, names them in PROCEDURE DIVISION USING, calculates the tax, and returns control with GOBACK.

COBOL Called Subprogram LINKAGE and USING Example showing CALL, LINKAGE SECTION, and GOBACK flow
The caller passes arguments with CALL USING; the subprogram maps them in LINKAGE and returns with GOBACK.

Complete calling-program example

The caller owns the actual storage for WS-GROSS-PAY and WS-TAX. Because BY REFERENCE is the default, CALCTAX can update the caller's tax field directly.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PAYROLL1.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-GROSS-PAY       PIC S9(7)V99 COMP-3
                              VALUE +0025000.00.
       01  WS-TAX             PIC S9(7)V99 COMP-3
                              VALUE ZERO.

       PROCEDURE DIVISION.
           CALL 'CALCTAX' USING WS-GROSS-PAY WS-TAX
               ON EXCEPTION
                   DISPLAY 'CALCTAX IS NOT AVAILABLE'
                   MOVE ZERO TO WS-TAX
           END-CALL

           DISPLAY 'GROSS PAY: ' WS-GROSS-PAY
           DISPLAY 'TAX:       ' WS-TAX
           GOBACK.

The literal 'CALCTAX' names the target program. Whether a literal call is static or dynamic depends on compiler and link-edit choices such as DYNAM, NODYNAM, and DLL handling. This article keeps the focus on the source contract between the caller and callee; the COBOL static-call guide owns the binding and performance intent.

Complete called-subprogram example

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CALCTAX.

       DATA DIVISION.
       LINKAGE SECTION.
       01  LK-GROSS-PAY       PIC S9(7)V99 COMP-3.
       01  LK-TAX             PIC S9(7)V99 COMP-3.

       PROCEDURE DIVISION USING LK-GROSS-PAY LK-TAX.
           COMPUTE LK-TAX ROUNDED = LK-GROSS-PAY * 0.20
           GOBACK.

The LINKAGE SECTION describes the fields supplied by another program. It does not allocate storage for these arguments. At entry, PROCEDURE DIVISION USING maps the first caller argument to LK-GROSS-PAY and the second to LK-TAX. The names do not need to match across programs, but their positions and data descriptions must be compatible.

Contract check: compare caller and callee definitions side by side. For this example, both sides use signed packed decimal fields with PIC S9(7)V99 COMP-3.

How CALL USING maps arguments

PositionCaller argumentSubprogram parameterRequired check
1WS-GROSS-PAYLK-GROSS-PAYSame business value and compatible size, sign, scale, and USAGE.
2WS-TAXLK-TAXWritable output passed BY REFERENCE with a compatible packed-decimal definition.

COBOL associates the lists by position, not by data-name. Reversing the two arguments can produce a wrong calculation even though the statement compiles. A different length or USAGE can make the called program read the wrong bytes, overwrite adjacent storage, or raise a runtime condition.

Do not add a LINKAGE item to the PROCEDURE DIVISION USING list unless the caller supplies the matching position. Likewise, do not add a caller argument without updating the callee contract. When programs are maintained in separate source libraries, document the shared interface in a copybook or interface specification and rebuild every affected component.

BY REFERENCE, BY CONTENT, and BY VALUE

BY REFERENCE is assumed when no mode is coded. The called program works with the caller's storage, which is why CALCTAX can place the result in WS-TAX.

CALL 'CALCTAX'
    USING BY REFERENCE WS-GROSS-PAY WS-TAX
END-CALL

BY CONTENT gives the subprogram a copy for that parameter. Changes to the corresponding callee data item do not change the caller's argument. Passing WS-TAX BY CONTENT would therefore lose the intended output when control returns.

BY VALUE passes a value rather than a reference to the sending field. It is common when the target follows a non-COBOL linkage convention, and COBOL-to-COBOL use requires compatible BY VALUE handling in the subprogram header. For the full comparison and syntax, use the COBOL CALL parameter modes guide.

Literal and identifier calls

01  WS-PROGRAM-NAME     PIC X(8) VALUE 'CALCTAX'.

CALL WS-PROGRAM-NAME USING WS-GROSS-PAY WS-TAX
    ON EXCEPTION
        DISPLAY 'PROGRAM NOT FOUND: ' WS-PROGRAM-NAME
END-CALL

A CALL identifier chooses the program name at run time and is dynamic in Enterprise COBOL for z/OS. It is useful when configuration or record content selects one of several subprograms. Validate the identifier value before the call and ensure the resulting program object is available through the site's runtime search path.

Do not mix assumptions: a literal target is not automatically static. Compiler options and binding determine how a literal call is resolved; an identifier call is dynamic.

Return control with GOBACK

In a called program, GOBACK returns control to the statement following the active CALL. EXIT PROGRAM also returns from a called program, while STOP RUN ends the run unit rather than performing an ordinary subprogram return.

A called program usually retains its WORKING-STORAGE state after GOBACK or EXIT PROGRAM. If a counter must start at zero on every invocation, initialize it explicitly, use LOCAL-STORAGE where suitable, or apply an approved INITIAL/CANCEL design. See Working Storage versus Local Storage and COBOL program termination and reentry for those separate lifecycle decisions.

Handle an unavailable dynamic subprogram

ON EXCEPTION handles a failure to make a dynamically called program available on its initial load. Typical checks include the program-name value, binder NAME or ALIAS, load-library concatenation, deployment member, and access to the library.

Boundary: ON EXCEPTION does not catch a data exception, protection exception, or application error after CALCTAX begins executing. Use normal validation, runtime diagnostics, and site error handling for failures inside the called program.

Common called-subprogram failures

SymptomLikely causePractical check
Output remains zeroOutput passed BY CONTENT or callee never moved/computed itConfirm BY REFERENCE and trace the matching callee parameter.
Numeric data exception or corrupted fieldCaller and callee definitions disagreeCompare order, byte length, PICTURE, USAGE, sign, and scale.
ON EXCEPTION executesDynamic target cannot be made availableCheck identifier value, binder name, load library, deployment, and access.
ON EXCEPTION does not catch an abendTarget loaded, then failed during executionRead the Language Environment and system diagnostics for the actual failure.
Second call starts with old valuesSubprogram WORKING-STORAGE retained its last-used stateInitialize state or review LOCAL-STORAGE, INITIAL, and CANCEL behavior.
Caller never resumesSubprogram executes STOP RUN or branches incorrectlyUse GOBACK or EXIT PROGRAM for an ordinary return and trace the final path.

Caller and subprogram checklist

  • Define one clear interface and keep the CALL and PROCEDURE DIVISION USING lists in the same order.
  • Match PICTURE, USAGE, sign, scale, and expected length for every position.
  • Use BY REFERENCE for outputs that the callee must return through an argument.
  • Use END-CALL to make the scope clear when ON EXCEPTION is present.
  • Return from the subprogram with GOBACK or EXIT PROGRAM, not STOP RUN.
  • Confirm how compiler and binder options resolve literal calls.
  • Place dynamically called program objects in the approved runtime library.
  • Test first-call and repeated-call behavior so retained state is visible.

The COBOL application-structure guide explains how main programs, subprograms, and the run unit fit together.

Official IBM references

COBOL called subprogram FAQ

Does a COBOL called subprogram allocate storage for LINKAGE items?

No. LINKAGE SECTION entries describe data made available by the caller; they do not reserve storage for those arguments. The PROCEDURE DIVISION USING list establishes addressability when the subprogram is entered.

Must CALL USING arguments match PROCEDURE DIVISION USING parameters?

Yes. They correspond by position, so keep the count, order, size, PICTURE, USAGE, and sign compatible. A mismatch can corrupt data or cause a runtime failure even when both programs compile.

Is CALL BY REFERENCE the default in Enterprise COBOL?

Yes. When no passing mode is stated, BY REFERENCE is assumed. The called program works with the caller's storage, so changes to an output parameter are visible after control returns.

What does ON EXCEPTION handle on a dynamic CALL?

It handles failure to make the called program available on its initial load, such as when the program object cannot be located. It does not catch an abend or application error that occurs after the called program begins running.

When a CALL fails in production, compare the two parameter lists before changing program logic; one wrong position or data definition can explain the entire failure.

New In-feed ads