I imagine it was an early release of OS/VS2 where they put pointers in
the CVT to often used TSO routines like IKJGETL, IKJPUTL, IKJPARS, etc.Â
And then when TSO/E came along they had lots more callable service
routines for folks to use so they gave TSO its own vector table (the
TSVT) and added just a single field to the CVT (CVTTVT) to point to it,
thereby minimising further CVT clutter from TSO. All good stuff.
So many/most/all of these routines are resident in LPA. Most of the
time they are in PLPA but there is nothing wrong with having a modified
version to try out in MLPA. But that's okay because the address placed
in the CVT and/or TSVT (when it exists) is the active copy that the
system would get for you if you were doing a normal module invocation
via a normal program management macro such as LINK or LOAD, so the
control block pointer will be "correct" for this IPL.
https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.ikjb700/ikjb700_When_to_use_the_CALLTSSR_.htm
lists some of the TSO service routines that you can call these days in
z/OS, in this case with the CALLTSSR macro. The macro checks the
control block pointer and uses it as a branch target if non-zero, or if
zero issues a LINK to invoke the routine. After all, local site admin
may have decided that they do not want to waste common storage on TSO
service routines, and therefore moved them to somewhere in the linklist.
Authors of programs that invoke system-supplied routines may like to
have their programs find the routine to invoke with minimum overhead and
so will search the active LPA CDE chain, the PLPA directory, perhaps
even the JPA, and then do a BLDL to see if it is around anywhere before
attempting to invoke it. (Note that current systems do not create a CDE
for the LPAQ for "active" PLPA modules, but use the chain only for MLPA,
FLPA and what could be called the DLPA "pre-Q" Q (my term).)
So, for example, when you issue a TSO command under REVIEW/RFE, rather
than create an S806 abend if the command does not exist, the module is
first searched for to see if it exists. If it does not exist then the
command is assumed to be for a CLIST.
I guess it is one thing to say whether a program of a given name is
anywhere to be found - but it is another thing to say which copy the
system would use when a program of that name is found in multiple
places. The order of precedence is published, but rather than try to
mimic it, the advice for z/OS is to just issue the LOAD request with an
ERRET to handle errors such as "program not found". These days, the OS
assumes that if you have an ERRET then you do not need an abend WTO
message. For MVS 3.8, you will get the abend WTO message but the ERRET
can still be used to prevent abnormal task termination.
In my view a "decent" 3GL for the MVS environment needs a way to be able
to make a general call to a program specified by its name. PL/I has
FETCH (these days, anyway), and COBOL has its "dynamic links" (I've
heard) and C? Well, don't ask me, I can barely spell C.
So, usermod ZP60038 supplies a version of IKJCT441 for MVS 3.8 which
ends up being link edited into the whole TSO I/O routine morass. (Check
out that JCLIN! And then there's the SYSGEN support to be updated...)Â
I envisaged callers simply issuing a LINK macro to invoke it, with a
LOAD-BALR-DELETE combo being equally valid, of course. But if you want
to check the whole, JPA, MLPA, PLPA, linklist thing, I'm not going to
stop you.
In REVIEW I just search the LPAQ "manually" because I expect that's what
the system would have to do (I should check that one day). To search
the PLPA directory the system has a hashing routine which should make it
much more efficient than the full sequential search - as if that matters
on you own herc box.
The code in REVIEW is very much like:
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REGS 0 AND 1 - CONTAIN NAME
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REG 3Â Â Â Â Â Â Â - CVT
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REGS 7 8 9Â Â - WORK REGS
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REG 14Â Â Â Â Â Â - RETURN - BAD RETURN 4(14)
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REG 15Â Â Â Â Â Â - ENTRY POINT
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â REG 0Â Â Â Â Â Â Â - POINTS TO LPDE AFTER GOOD RETURN
        SPACE
TSOPLPAÂ LMÂ Â Â R0,R1,BLDLNAME
        STM  R14,R12,12(R13)
        L    R3,CVTPTR(,0)              POINT TO THE CVT
        L    R15,CVTLPDSR-CVT(,R3)      GET ROUTINE ENTRY POINT
        BASR R14,R15                    CALL IEAVVMSR
        B    TSOPLPAX                   FOUND IN PLPA
        LM   R14,R12,12(R13)            NOT IN PLPA, DO BLDL
        ...
TSOPLPAX LMÂ Â Â R14,R12,12(R13)
Last time I pasted code it was a scrambled mess, so apologies if the
result is the same this time.
Code like that works from MVS 3.8 (actually, I bet it works on 3.7 and
maybe even earlier) to at least z/OS 2.3 where support for RMODE=64 was
added and LPDE control blocks grew by 8 bytes. In z/OS 2.2 LPDEs were
the same size as they are in MVS 3.8. Naturally, you need to know the
LPDE size if you are stepping through the PLPA directory sequentially.
Cheers,
Greg