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
|