|
technical: Control Blocks
for Beginners Pt 2: z/OS Control Blocks.
In the first part of
this two part series, we introduced control blocks: what they
are, how to access them and how they can be useful. In this
second article, we talk about z/OS control blocks: the basic
control blocks and how to write programs to access them.
Introduction
In the previous article in this series, we introduced control
blocks: what they are, why they're used, and how to look at
them. In this article, we're going to look closer at z/OS
control blocks. We'll look at some of the basic control blocks
that every Systems Programmer needs to know, and coding examples
to access these control blocks in Assembler, PL/1 and COBOL.
The Two Basic z/OS control blocks
If you're looking for control blocks in z/OS, the chances
are that you'll start looking for them by referring to the
two basic z/OS control blocks that point to almost everything:
The PSA and CVT.
PSA - Prefixed Save Area
The PSA is the first control block you need. It holds the
basic information z/OS needs when scheduling work on a Central
Processor (CP), which is why there's one for every CP. And
the PSA is easy to find - it's always at address zero.
The big things that PSA gives Systems Programmers are:
- FLCCVT - A pointer to the CVT (more on the CVT in a moment).
- PSAAOLD - A pointer to the Address Space Control Block
(ASCB) of the address space currently scheduled on this
CP. The ASCB holds basic information about an address space,
including Jobname and Address Space ID. More information
is held in the Address Space Extension Block (ASXB), which
is pointed to by the ASCB.
- PSATOLD - A pointer to the Task Control Block (TCB) of
the task currently scheduled on this CP. The TCB holds information
on a specific task.
CVT - Communication Vector Table
The CVT is a great control block. You can find pointers to
a whole lot of other control blocks from here, including all
ASCBs, SSVTs (Subsystem Vector Table - information on subsystems)
and UCBs (Unit Control Blocks - information on hardware units
like DASD and tape). Think of the CVT as an index to all the
other z/OS control blocks.
So these basic control blocks are linked like this:

Accessing Control Blocks in Assembler
So now that we've been introduced to the basic z/OS control
blocks, let's start using them. Look at the Assembler (HLASM)
example below:
* --- Get the CVT Address --------------------
L R1,FLCCVT-PSA(0) R1 -> CVT
* --- Get the SMCA Address -------------------
L R1,CVTSMCA-CVT(R1) R1 -> SMCA
* --- Get the z/OS SMFID --------------------
USING SMCABASE,R1
MVC ZOSNAME(L'SMCASID),SMCASID
* --- DSECTs we need for these control blocks --
IHAPSA , Map PSA
CVT DSECT=YES Map CVT
IEESMCA DSECT=YES Map SMCA
Figure 1: HLASM Code Fragment |
This fragment gets the name of the z/OS image - the SMFID.
Looking at this fragment, you can see that we
- get the address of the CVT from the PSA
- get the address of a control block called the SMCA (used
to store SMF related information)
- get the the SMFID from the SMCA.
You can also see that we include z/OS macros to include DSECTS
that map these control blocks at the bottom.
Control Blocks from High Level Languages
But you don't have to program in Assembler to access control
blocks. Suppose we want to get the Jobname and Address Space
where we're running. Check out the following PL/1, C, COBOL
and REXX examples.
/*=============================================
Storage Definitions
==============================================*/
/* --- Map PSA ------------------------------------------ */
Dcl 1 psa Based(psap),
3 psastuff char(548), /* fill 548 bytes */
3 psaaold Pointer;
/* (ignore rest of PSA) */
/* --- Map ASCB------------------------------------------ */
Dcl 1 ascb Based(psaaold),
3 ascbstuff char(172), /* fill 172 bytes */
3 ascbjbni Pointer,
3 ascbjbns Pointer;
/* (ignore rest of ASCB) */
Dcl STCName char(8) Based(ascbjbns);
Dcl JobName char(8) Based(ascbjbni);
/*=============================================
Main Program
==============================================*/
psap = null();
Display ('(DZSPLI) STC: ' || STCName);
Display ('(DZSPLI) Job: ' || JobName);
End DZSPLI;
Figure 2: PL/1 Code Fragment |
DATA DIVISION.
Linkage Section.
* --- Map PSA --------------------------------------
01 PSA.
02 filler pic x(548).
02 PSAAOLD pointer.
* --- Map ASCB -------------------------------------
01 ASCB.
02 filler pic x(172).
02 ASCBJBNI pointer.
02 ASCBJBNS pointer.
01 STCNAME pic x(8).
01 JOBNAME pic x(8).
PROCEDURE DIVISION.
SET ADDRESS OF PSA TO NULL.
SET ADDRESS OF ASCB TO PSAAOLD.
SET ADDRESS OF JOBNAME TO ASCBJBNI.
SET ADDRESS OF STCNAME TO ASCBJBNS.
DISPLAY "(DZSCOB1) " STCNAME ", " JOBNAME.
GOBACK.
Figure 3: COBOL Code Fragment |
/*=============================================
Map z/OS Control Blocks
==============================================*/
/* --- Map PSA --------------------------------- */
struct psa {
int psastuff[4]; /* 4 bytes before CVT Ptr*/
struct cvt *psacvt;
/* Ignore the rest of the PSA */
};
/* --- Map ASCB -------------------------------- */
struct ascb {
char ascbstuff[172]; /* 140 bytes before ptr */
char *ascbjbni; /* Jobname (if any) */
char *ascbjbns; /* STC Name */
/* Ignore the rest of the CVT */
};
struct psa *psa_ptr = 0; /* PSA is at address 0 */
char stcname[10], jobname[10];
/*=============================================
Main Program
==============================================*/
strncpy(jobname,psa_ptr->psaaold->ascbjbni,8);
strncpy(stcname,psa_ptr->psaaold->ascbjbns,8);
printf("Jobname: %s, STCName: %s\n", jobname, stcname);
Figure 4: C Code Fragment |
/* Rexx */
/* --- Get Address of ASCB ----------------------- */
ASCB_Addr = C2D(Storage(224,4)) /* Get address of ASCB */
/* --- First check ASCBJBNI for Jobname ------------------- */
Interpret "JobAddr = Storage("D2X(ASCB_ADDR+172)",4)"
If C2D(JobAddr) = 0 Then
/* --- Not in initiator, so get jobname from ASCBJBNS -- */
Interpret "JobAddr = Storage("D2X(ASCB_ADDR+176)",4)"
Interpret "Job = Storage("C2X(JobAddr)",8)"
say "Jobname: " Job
exit
Figure 5: REXX Code Fragment |
All of these programs use the PSAAOLD field in the PSA to
get the address of the current ASCB, then get both the Jobname
(which will only exist if the code is running in a batch job
or something similar that runs in an initiator) and the started
task name.
The problem with using high level languages is that IBM doesn't
supply a way of mapping the control blocks in these languages
- only Assembler. So you need to map them yourself, and we've
done this in the above examples. However if you're using the
IBM C compiler, there is a batch utility that converts Assembler
macros to C defines.
Summary
Many z/OS control blocks are chained off two basic blocks:
the PSA and CVT. You can quite easily access these control
blocks not only from Assembler programs, but from High Level
languages like C, PL/1 and COBOL.
David Stephens
|