Learn the technique that enables the operating system programs to achieve this task.
In IBM i and its ancestors, an active job at the operating system level has an associated MI process, which is identified by a Process Control Space (PCS) MI object. The system pointer to a PCS object (with MI type/subtype code hex 1AEF) is used as the operand that identifies an MI process in process management MI instructions—for example, the Materialize Process Attributes (MATPRATR) instruction. Several other process-related MI instructions also expect a PCS pointer as an operand (or part of an operand) that identifies an MI process—for example, the Materialize Process Locks (MATPRLK) instruction, and the Transfer Object Lock (XFRLOCK) instruction. Thus, to use these MI instructions we need to first obtain a system pointer to the PCS object associated with an MI process.
This article introduces an effective method (locate the Work Control Block Table (WCBT) Entry of an active job in the WCBT via the job index and then retrieve the PCS pointer in the WCBTE) by investigating how the operating system programs achieve this task step by step.
A Brief Review of the Work Control Block Table (WCBT) and the Job Index
Leif Svalgaard discusses the Work Control Block Table (WCBT) and the Job Index in detail in chapter 9, The Work Control Block Table, of his great e-book, AS/400 Machine Level Programming. The technique discussed in this article is also covered in this chapter.
At the operating-system level, a job exists from the time it enters the system until it still has spooled output. Each existing job in the system has an entry in the WCBT. The WCBT actually consists of a master (or root) WCBT (QSYS/QWCBT00) and one or more WCBTs named QWCBT01, QWCBT02, and so on. A WCBT object is a space object with MI object type/subtype code hex 19D0. The master WCBT contains pointers to the other WCBTs, which actually contain WCBTEs allocated for jobs in the system. Entries in the WCBT are each hex 400 bytes long. For an active job, the system pointer to the PCS object associated with an MI process is at offset hex
At offset hex 220 within the associated space of QWCBT00 is a system pointer to an index object, QSYS/QWCBT_JOB_INDEX, which will be referred to as the job index in the remaining portion of this article. The MI type/subtype code of the job index is hex 0EA4. The argument length (entry length) of the job index is 48 bytes; the key length of the job index is 32 bytes. The 32-byte key portion of the job index entry has two formats as shown in the following table.
Job Index Entry Key Formats |
||
Format 1 |
||
Offset (hex) |
Data Type |
Description |
0 |
Char(1) |
'1' |
1 |
Char(10) |
Job name |
B |
Char(10) |
User name |
15 |
Char(6) |
Job number |
1B |
Char(5) |
Hex 0000000000 |
Format 2 |
||
Offset (hex) |
Data Type |
Description |
0 |
Char(1) |
'2' |
1 |
Char(10) |
User name |
B |
Char(6) |
Job number |
11 |
Char(10) |
Job name |
1B |
Char(5) |
Hex 0000000000 |
The remaining 16 bytes of a job index entry represent a space pointer addressing the WCBTE of the corresponding job in the WCBT. Each job has two index entries in the job index, with index key format 1 and 2, respectively; the space pointers in these index entries address the same WCBTE. Note that two index key formats provide more flexibility for searching a specific job or multiple jobs within the job index. With index key format 1, you can search for a job or jobs by:
- Job name
- Job name and user name
- Job name, user name, and job number
With index key format 2, you can search for a job or jobs by:
- User name
- User name and job number
- User name, job number, and job name
Also note that the WCBT and the job index are all in the system domain.
The QWCCDSUC Program
Program QSYS/QWCCDSUC is the Command Processing Program (CPP) of the Work with User Jobs (WRKUSRJOB) command and is also the operating system program we are going to study in this article. To start, we need to perform the following two steps:
- Complete a *SVL LIC trace upon a WRKUSRJOB command.
- Dump the RISC instruction stream of the QWCCDSUC Program via the System Service Tools (SST).
The following are example commands to trace a WRKUSRJOB operation:
4 > trcint *on trctbl(a) trctype(*svl) job(name-of-your-interactive-job) /* Start + an LIC trace against the current job */ 4 > wrkusrjob user(ljl) 4 > trcint *off trctbl(a) /* Stop trace and output + the trace records to spooled file QPCSMPRT. */ |
Next, we're going to investigate the process that the QWCCDSUC program uses to retrieve the system pointer to the PCS object associated with an MI process. We'll simulate this process with an OMI program (wcbt1.emi) and ILE RPG program (wcbt2.rpgle). Both these simulation programs accept a job name, a job user, and a job number to identify an active job in the system and return the PCS pointer of the job via their fourth parameter.
Retrieve the System Pointer to the Job Index
Debugging shows that during a WRKUSRJOB operation, the QWCCDSUC program retrieves the system pointer to the job index through the following steps:
- 1.Locate the system pointer to the master WCBT (i.e., QWCBT00) stored in the Process Communication Object (PCO) of the current MI process at offset hex 1B0.
- 2.Issue the Set Space Pointer from Pointer (SETSPPFP) MI instruction to retrieve the space pointer that addresses the associated space of QWCBT00.
- 3.Locate the system pointer to the job index in the associated space of QWCBT00 at offset hex 220.
MI instructions in the QWCCDSUC program involved in this process and the PowerPC instructions generated for them (at V5R4) are listed below:
MI PROGRAM SUBTYPE: 01 NAME: QWCCDSUC ADDRESS: 18BBB |
|||
MI INSTRUCTION NUMBERS: hex 01 (address: 18BBB |
|||
Location |
Object Text |
Source Statement |
Description |
0008E8 |
4B801633 |
BLA 0X3801630 |
Invoke LIC routine pmgtpco_Gennaker in module #cfgrbla, which returns the address of the PCO of the current MI process. [1] |
0008EC |
39E30000 |
ADDI 15,3,0 |
Save the returned PCO address to General Purpose Register (GPR) 15 (r15). |
MI INSTRUCTION NUMBERS: hex 040 (address: 18BBB |
|||
Location |
Object Text |
Source Statement |
Description |
000DF8 |
E0CF01BF |
LQ 6,0X1B0(15),15 |
Load the system pointer to QWCBT00 at offset hex 1B |
000DFC |
|
TXER 0,0,41 |
|
000E00 |
3B470000 |
ADDI 26,7,0 |
|
000E04 |
|
ORI 3,6,0 |
|
000E08 |
|
RLDICL. 8,6,2,62 |
|
000E |
40820010 |
BC 4,2,0X10 |
|
000E10 |
|
ADDI 4,26,0 |
|
000E14 |
4B801963 |
BLA 0X3801960 |
Invoke the implementing LIC routine of the SETSPPFP MI instruction to retrieve the space pointer that addresses the associated space of QWCBT00. [3] |
000E18 |
|
ORI 26,3,0 |
|
000E |
FB410120 |
STD 26,0X120(1) |
Store the returned address. [4] |
Notes
[1] The BLA form Branch (b) instruction branches the execution to address FFFFFFFFFF 801630, where the LIC routine pmgtpco_Gennaker in module #cfgrbla is located. The pmgtpco_Gennaker function returns the address of PCO of the current MI process via r3. Similar code is generated for a statement in an ILE program that invokes the Return PCO Pointer (PCOPTR2) system built-in or an MI instruction in an OMI program that refers to a data object or a space object (SPC) the addressability type of which is BASPCO (addressability type is based on PCO).
[2] The Load Quadword instruction reveals the offset value, hex 1B0, of the system pointer to the master WCBT (QWCBT00) in the PCO.
[3] At V5R4, code generated for a SETSPPFP MI instruction invokes the implementing LIC routine of SETSPPFP via a BLA 0X3801960 instruction. Here, the implementing LIC routine of SETSPPFP takes the system pointer to QWCBT00 as its source operand and returns the address of the associated space of QWCBT00 via r3.
[4] r1 always addresses the current Invocation Stack Frame (ISF). The Store Double (std) instruction stores the 8-byte address of the associated space of QWCBT
In wcbt1.emi, the OMI instruction to simulate the MI instructions hex 01 and hex
dcl mspptr spp-root-wcbt@ ; dcl spc root-wcbt bas(spp-root-wcbt@) ; dcl sysptr job-index@ dir pos(h'221') ;
dcl spc pco baspco ; dcl sysptr root-wcbt@ dir pos(h'1B1') ;
setsppfp spp-root-wcbt@, root-wcbt@ ; |
The following are PowerPC instructions generated for the SETSPPFP instruction in our simulating program.
MI PROGRAM SUBTYPE: 01 NAME: WCBT1 ADDRESS: |
||
MI INSTRUCTION NUMBERS: hex 02 (address: |
||
Location |
Object Text |
Source Statement |
0000FC 000100 000104 000108 000110 000114 000118 000120 |
4B801633 E 38660000 40820010 38870000 4B801963 60670000 F8E10098 |
BLA 0X3801630 LQ 6,0X1B0(3),11 TXER 0,0,41 ADDI 3,6,0 RLDICL. 2,6,2,62 BC 4,2,0X10 ADDI 4,7,0 BLA 0X3801960 ORI 7,3,0 STD 7,0X98(1) |
Similar ILE RPG source code in wcbt2.rpgle is the following:
d pco ds based(pco@) d * SYP to QWCBT00 at offset hex 1B d syp_qwcbt00@ * procptr d roo_wcbt ds based(wcbt@) d * SYP to the job index at offset hex * the associated space of QWCBT00 d job_inx@ * * ... STMT /free 75 pco@ = pcoptr2(); 76 wcbt@ = setsppfp(syp_qwcbt00@); * ... /end-free |
Search the Job Index for a Specific Job
Debugging shows that during a WRKUSRJOB operation, the QWCCDSUC program retrieves the system pointer to the PCS object associated with a job through the following steps:
- Search the job index for index entries of interests via a Find Independent Index Entry (FNDINXEN) MI instruction. At V5R4, the MI instruction number of this FNDINXEN instruction in the OPM program template of QWCCDSUC is hex 6BC. (The trace data of the *SVL LIC trace upon a WRKUSRJOB operation is handy to determine the location from which the FNDINXEN MI instruction is issued.)
- Locate the WCBTE of a job via the space pointer in a returned index entry at offset hex 20.
- Locate the PCS pointer of the job in the WCBTE at offset hex 20.
PowerPC instructions generated for MI instruction hex 6BC of QWCCDSUC:
MI PROGRAM SUBTYPE: 01 NAME: QWCCDSUC ADDRESS: 18BBB |
|||
MI INSTRUCTION NUMBERS: hex 06BC (address: 18BBB |
|||
Location |
Object Text |
Source Statement |
Description |
00AE44 |
E11E07B6 |
LQ 8,0X7B0(30),6 |
|
00AE48 |
|
TXER 0,0,41 |
|
00AE |
38690000 |
ADDI 3,9,0 |
Operand 1 (receiver) of FNDINXEN |
00AE50 |
38950220 |
ADDI 4,21,544 |
Operand 2 (index) of FNDINXEN [1] |
00AE54 |
39400016 |
ADDI 10,0,22 |
The SCV 10 function number for FNDINXEN is 22 at V5R4. |
00AE58 |
E0DE0706 |
LQ 6,0X700(30),6 |
Operand 3 (rule options) of FNDINXEN |
00AE |
|
TXER 0,0,41 |
|
00AE60 |
7FC |
TD 30,4,21 |
|
00AE64 |
60E50000 |
ORI 5,7,0 |
|
00AE68 |
E11E0756 |
LQ 8,0X750(30),6 |
Operand 4 (search argument) of FNDINXEN |
00AE |
|
TXER 0,0,41 |
|
00AE70 |
|
ADDI 6,9,0 |
|
00AE74 |
44000141 |
SCV 10 |
Issue the FNDINXEN MI instruction. |
[1] MI instruction hex 6BA of the QWCCDSUC program is a Copy Bytes with Pointers (CPYBWP) instruction that copies the address information in the space pointer machine object that addresses the associated space of QWCBT00 (like MSPPTR spp-root-wcbt@ in wcbt1.emi) to another space pointer. In the CPYBWP process, r21 is set to the address of the associated space of QWCBT00. Here, r4 addresses the system pointer to the job index stored in the associated space of QWCBT00 at offset 544 (hex 220).
Debugging shows that QWCCDSUC issues the FNDINXEN instruction with two search arguments in index key format 2 to retrieve all job index entries that begin with 1-byte constant '2' and a 10-byte user name. For example, the two 32-byte search arguments of a WRKUSRJOB LJL command might look like the following:
CB CB80 00000000 00000000 00000000 00000000 * ................ * CB CBA0 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF * ................ * |
The following OMI source code (wcbt1.emi) simulates the FNDINXEN instruction in QWCCDSUC. Instead of searching for a range of job index entries, the code searches for a specific job index entry identified by fnd-arg.
/** FNDINXEN */ dcl spcptr rcv@ auto init(rcv) ; dcl dd rcv char(h'30') auto bdry(16) ; /* op-1 */ dcl dd rcv-arg char(h'20') def(rcv) pos(1) ; dcl spcptr wcbte@ def(rcv) pos(h'21') ; dcl spcptr opt-lst@ auto init(opt-lst) ; /* op-3 */ dcl dd opt-lst char(14) auto ; dcl dd * char(2) def(opt-lst) pos(1) init(x'0001') ; /* Rule option: EQUAL */ dcl dd * bin(2) unsgnd def(opt-lst) pos(3) init(x'0020') ; /* Argument (Key) length: hex 20 */ dcl dd * bin(2) def(opt-lst) pos(5) init(x'0000') ; /* Argument (Key) offset: ignored for a search for EQUAL operation */ dcl dd * bin(2) def(opt-lst) pos(7) init(x'0001') ; /* Occurence count: 1 */ dcl dd rtn-cnt bin(2) def(opt-lst) pos(9) ; /* Return count */ dcl dd rtn-ent-len bin(2) unsgnd def(opt-lst) pos(11) ; /* Returned entry length (1) */ dcl dd rtn-ent-off bin(2) unsgnd def(opt-lst) pos(13) ; /* Returned entry offset (1) */ dcl spcptr fnd-arg@ auto init(fnd-arg) ; /* op-4 */ dcl dd fnd-arg char(h'20') auto ; dcl dd * char(1) def(fnd-arg) pos(1) init('1') ; /* Entry format 1 */ dcl dd fnd-job-nam char(10) def(fnd-arg) pos(2) ; dcl dd fnd-job-usr char(10) def(fnd-arg) pos(12) ; dcl dd fnd-job-num char(6) def(fnd-arg) pos(22) ; dcl dd * char(5) def(fnd-arg) pos(28) init(x'0000000000') ;
fndinxen rcv@, job-index@, opt-lst@, fnd-arg@ ;
dcl dd wcbte char(h'400') bas(wcbte@) ; dcl dd * char(h'20') def(wcbte) pos(1) ; dcl sysptr pcs@ def(wcbte) pos(h'21') ; /* [1] */ dcl sysptr rtn-pcs@ bas(pcs@@) ;
cpybwp rtn-pcs@, pcs@ ; /* [2] */ |
Notes
[1] Once the job index is found, we can locate the PCS pointer (pcs@) at offset hex
[2] Copy the PCS pointer in the WCBTE to parameter rtn-pcs@.
The ILE RPG source code (in wcbt2.rgple) that achieves the same task is as follows:
* Operand 1 of FNDINXEN, receiver d rcv ds d rcv_arg d wcbte@ * * Operand 3 of FNDINXEN, option list d opt_lst ds * Rule option, x'0001' = search for EQUAL d * Length of search argument d 5u 0 inz(32) d 5i 0 inz(0) * Occurrence count = 1 d 5i 0 inz(1) * Return count d rtn_cnt 5i 0 * Returned index entry info d ent_len 5u 0 d ent_off 5i 0 * Operand 4 of FNDINXEN, search argument d fnd_arg ds d inx_fmt d fnd_jobnam d fnd_jobusr d fnd_jobnum d * WCBTE d wcbte ds qualified d based(wcbte@) d d pcs@ * * ... /free * ... fnd_jobnam = jobnam; fnd_jobusr = jobusr; fnd_jobnum = jobnum; 81 fndinxen (rcv : job_inx@ : opt_lst : fnd_arg);
83 pcs@ = wcbte.pcs@; *inlr = *on; /end-free |
The complete source programs are available as wcbt1.emi and wcbt2.rpgle. Compile the WCBT1 and WCBT2 programs and change them to system state so that they can run at security level 40 or above.
Compile the following tiny test program (wcbt1b.rpgle).
* Prototype of the WCBT1 program d pcsptr pr extpgm('WCBT1') d jobnam d jobusr d jobnum d pcs@ * * My prototype d me pr extpgm('WCBT1B') d jobnam d jobusr d jobnum d pcs@ s * d me pi d jobnam d jobusr d jobnum STMT /free 18 pcsptr(jobnam : jobusr : jobnum : pcs@); 19 *inlr = *on; /end-free |
Debug WCBT1B, set breakpoint at statement 19, and then call WCBT1B with parameters: the job name, job user, and job number of an active job. At breakpoint 19, issue the eval pcs@ debug command. The resulting display might look like the following:
Evaluate Expression
Previous debug expressions
> BREAK 19 > EVAL pcs@ PCS@ = SYP:TEA LJL 655110 :1AEF: :001111110 0010000 |
You see that pcs@ is a system pointer to the PCS object (MI object type/subtype code is hex 1AEF) associated with an active job called 655110/LJL/TEA.
Final Thoughts
Now we've proven Leif's technique to retrieve the PCS pointer of an active job via the job index and WCBT by studying and simulating the operating system program QWCCDSUC. The WCBT1 (or WCBT2) program can be a useful utility. So what can we do with this utility? Think it over!
LATEST COMMENTS
MC Press Online