MainframeCICSCICS Complete Reference

CICS Program Control: LINK, XCTL, RETURN — Complete Guide

TT
TopicTrick Team
CICS Program Control: LINK, XCTL, RETURN — Complete Guide

Introduction: CICS Program Control and the Call Stack

In batch COBOL, programs call each other with the CALL statement and return with STOP RUN or EXIT PROGRAM. In CICS, the program control model is similar but different in critical ways: programs must use EXEC CICS commands to invoke other CICS programs, and the concept of a "task" (rather than a process) governs the lifetime of all resources.

CICS Program Control provides three core commands:

  • EXEC CICS LINK — call another program, return to caller
  • EXEC CICS XCTL — transfer to another program, do not return
  • EXEC CICS RETURN — return to caller (or terminate the task)

Understanding when to use each command — and understanding the CICS call stack and COMMAREA passing mechanics — is essential for building modular, maintainable CICS applications.


EXEC CICS LINK: Calling a Subprogram

LINK is the CICS equivalent of a COBOL CALL statement. The calling program (the "linker") passes a COMMAREA, and the called program ("linkee") processes it and issues EXEC CICS RETURN to hand control back.

cobol
*── Caller: EMPMENU ────────────────────────────────────────────
PROCEDURE DIVISION.
    MOVE '000100' TO WS-LINK-CA-KEY
    INITIALIZE WS-LINK-CA-RESULT

    EXEC CICS LINK PROGRAM('EMPGET')
                   COMMAREA(WS-LINK-COMMAREA)
                   LENGTH(LENGTH OF WS-LINK-COMMAREA)
                   RESP(WS-RESP)
                   RESP2(WS-RESP2)
    END-EXEC

    *> Control returns here after EMPGET issues EXEC CICS RETURN
    EVALUATE WS-RESP
        WHEN DFHRESP(NORMAL)
            IF WS-LINK-CA-RESP = 'OK'
                MOVE WS-LINK-CA-EMP-NAME TO SCREEN-EMP-NAME
            ELSE
                MOVE WS-LINK-CA-ERR-MSG TO SCREEN-MSG
            END-IF
        WHEN DFHRESP(PGMIDERR)
            MOVE 'PROGRAM EMPGET NOT FOUND.' TO SCREEN-MSG
        WHEN OTHER
            PERFORM HANDLE-LINK-ERROR
    END-EVALUATE.
cobol
*── Called program: EMPGET ────────────────────────────────────
LINKAGE SECTION.
01  DFHCOMMAREA.
    05  LK-KEY      PIC X(6).
    05  LK-RESP     PIC X(2).
    05  LK-EMP-NAME PIC X(30).
    05  LK-ERR-MSG  PIC X(40).

PROCEDURE DIVISION.
    EXEC CICS READ FILE('EMPFILE')
                   RIDFLD(LK-KEY)
                   INTO(WS-EMP-REC)
                   RESP(WS-RESP)
    END-EXEC

    EVALUATE WS-RESP
        WHEN DFHRESP(NORMAL)
            MOVE 'OK' TO LK-RESP
            MOVE WS-EMP-NAME TO LK-EMP-NAME
        WHEN DFHRESP(NOTFND)
            MOVE 'NF' TO LK-RESP
            MOVE 'NOT FOUND' TO LK-ERR-MSG
        WHEN OTHER
            MOVE 'ER' TO LK-RESP
            MOVE 'READ ERROR' TO LK-ERR-MSG
    END-EVALUATE

    EXEC CICS RETURN END-EXEC.        *> Return to EMPMENU

LINK Chain Depth

CICS supports nested LINK chains (A LINKs to B, B LINKs to C, etc.) up to a depth of 255 levels. Each level in the chain is tracked by CICS. When the deepest program issues RETURN, control goes back one level. This is exactly analogous to the COBOL call stack.

Dynamic LINK: PROGRAM in a Variable

The program name in EXEC CICS LINK can be specified as a data area (variable) rather than a literal, enabling dynamic dispatch:

cobol
01  WS-PROG-NAME  PIC X(8).

PROCEDURE DIVISION.
    MOVE WS-CA-PROGRAM-NAME TO WS-PROG-NAME

    EXEC CICS LINK PROGRAM(WS-PROG-NAME)
                   COMMAREA(WS-LINK-CA)
                   LENGTH(LENGTH OF WS-LINK-CA)
                   RESP(WS-RESP)
    END-EXEC.

This is the CICS equivalent of a dynamic CALL and is used in routing tables, menu drivers, and generic transaction controllers.


EXEC CICS XCTL: Transfer of Control (No Return)

XCTL passes control to another program without returning. The current program terminates and its GETMAIN storage is freed. Use XCTL when:

  • A menu transaction navigates to a subsystem program
  • A transaction chains to a completion/confirmation screen that has no need to return
  • You want to "restart" a transaction by XCTLing to the same program
cobol
*── Navigate to main menu, no return expected ───────────────────
XCTL-TO-MENU.
    MOVE WS-CURRENT-USER TO WS-MENU-CA-USER
    MOVE 'EMP ' TO WS-MENU-CA-SUBSYS

    EXEC CICS XCTL PROGRAM('MAINMENU')
                   COMMAREA(WS-MENU-COMMAREA)
                   LENGTH(LENGTH OF WS-MENU-COMMAREA)
                   RESP(WS-RESP)
    END-EXEC

    *> Code below here is never reached
    MOVE 'XCTL FAILED' TO WS-ERR-MSG
    PERFORM HANDLE-ERROR.

Key difference from LINK: after EXEC CICS XCTL, your program is gone. You cannot write code that "expects to run after the XCTL" — it will never execute. Any code after the XCTL command is unreachable except for error handling in the case the XCTL itself fails (PGMIDERR, etc.).

XCTL vs. LINK: Which to Use

ScenarioUse
Calling a submodule that returns a resultLINK
Navigating from a menu to a subsystemXCTL
Chaining to next step in a workflow with no returnXCTL
Calling a common validation or formatting routineLINK
Re-starting the same programXCTL (to self)
Invoking a help program, returning to callerLINK

EXEC CICS RETURN: Terminating or Returning

RETURN has two distinct behaviours depending on whether TRANSID is specified:

RETURN without TRANSID — terminates the current program and returns to the caller (if called via LINK) or ends the task entirely (if this is the top-level program). This is used in subprograms and in top-level programs that are done with the transaction.

cobol
*── Subprogram: return to caller ────────────────────────────────
EXEC CICS RETURN END-EXEC.

*── Top-level: end the task and show natural next message ────────
EXEC CICS RETURN END-EXEC.

RETURN with TRANSID and COMMAREA — ends the current task but schedules a new task start for the specified TRANSID when the terminal user provides input. Used exclusively for pseudo-conversational state saving.

cobol
*── Pseudo-conversational: save state and wait for next input ────
EXEC CICS RETURN
          TRANSID(EIBTRNID)
          COMMAREA(WS-COMMAREA)
          LENGTH(LENGTH OF WS-COMMAREA)
          RESP(WS-RESP)
END-EXEC.

RETURN with TRANSID only (no COMMAREA) — same as above but no state is saved. The next task starts with EIBCALEN = 0. Used when the current interaction is complete but the transaction should be ready for a fresh start.

cobol
*── After a completed transaction: reset for fresh start ─────────
EXEC CICS RETURN
          TRANSID('EMPI')
          RESP(WS-RESP)
END-EXEC.

EXEC CICS LOAD and RELEASE: Loading Data Tables

LOAD is used to load a non-executable module (a data table, parameter block, or message table) into memory and obtain its base address:

cobol
WORKING-STORAGE SECTION.
01  WS-TABLE-POINTER USAGE IS POINTER.
01  WS-TABLE-LEN     PIC S9(8) COMP VALUE +0.

LINKAGE SECTION.
01  LK-MSG-TABLE.
    05  LK-MSG-ENTRY OCCURS 100 TIMES.
        10  LK-MSG-CODE  PIC X(4).
        10  LK-MSG-TEXT  PIC X(60).

PROCEDURE DIVISION.
LOAD-MESSAGE-TABLE.
    EXEC CICS LOAD PROGRAM('MSGTBL01')
                   SET(WS-TABLE-POINTER)
                   LENGTH(WS-TABLE-LEN)
                   RESP(WS-RESP)
    END-EXEC

    IF WS-RESP = DFHRESP(NORMAL)
        SET ADDRESS OF LK-MSG-TABLE TO WS-TABLE-POINTER
        PERFORM LOOKUP-MESSAGE
    ELSE
        MOVE 'MSG TABLE LOAD FAILED.' TO WS-ERR-MSG
    END-IF.

RELEASE-TABLE.
    EXEC CICS RELEASE PROGRAM('MSGTBL01')
                      RESP(WS-RESP)
    END-EXEC.

LOAD is particularly useful for large reference tables (country codes, product codes, error message texts) that should not be embedded in every program's WORKING-STORAGE.


EXEC CICS ABEND: Intentional Task Termination

While not strictly a Program Control command, EXEC CICS ABEND is used to terminate a task immediately with a specific ABEND code when an unrecoverable error occurs:

cobol
HANDLE-FATAL-ERROR.
    EXEC CICS WRITEQ TS
              QUEUE('ERRLOG')
              FROM(WS-ERROR-DETAILS)
              LENGTH(LENGTH OF WS-ERROR-DETAILS)
    END-EXEC

    EXEC CICS ABEND ABCODE('EMPE')
                    NODUMP
    END-EXEC.

Use NODUMP for expected, managed error conditions to avoid generating a large SVC dump. Omit NODUMP for unexpected conditions that require a full memory dump for debugging.


Common Program Control Mistakes

Mistake 1: Coding logic after EXEC CICS XCTL. After XCTL executes, your program no longer exists. Any paragraph or statement after the XCTL will never run (except in the unlikely event the XCTL itself fails). Structure your code to perform XCTL as the last action in a processing path.

Mistake 2: Using CALL instead of LINK for CICS subprograms. Subprograms that issue EXEC CICS commands must be invoked via LINK. Using CALL causes an ASRA (program interruption) because the EIB is not set up for the called program.

Mistake 3: Not checking RESP after LINK for PGMIDERR. If the linked program is not defined in CICS (not installed, misspelled name), LINK returns DFHRESP(PGMIDERR). Without RESP checking, CICS ABENDs the task with PGMI. Always check RESP after LINK.

Mistake 4: LINKing to the same program recursively. Recursive LINK chains consume one stack level per call. Recursion to a depth of 255 causes an AEIV ABEND. If you genuinely need recursive logic, implement it with EVALUATE/PERFORM loops instead.


Key Takeaways

CICS Program Control — LINK, XCTL, and RETURN — maps cleanly to the COBOL programming mental model. LINK = CALL (with return), XCTL = CALL without return, RETURN = EXIT PROGRAM or STOP RUN. The COMMAREA on LINK and XCTL is the parameter-passing mechanism. The TRANSID and COMMAREA on RETURN is the pseudo-conversational state-saving mechanism. Master these three commands and their options and you have the complete toolkit for building modular, scalable CICS application architectures.

For understanding how CICS sends and receives terminal data, continue with CICS SEND and RECEIVE. For the complete CICS course, visit the CICS Mastery Course.