Sie sind auf Seite 1von 31

MC Press Online

The API Corner: Retrieving Information, Part I


Contributed by Bruce Vining Wednesday, 19 March 2008 Last Updated Thursday, 05 June 2008

In previous columns, we discussed the basics of API error handling and data types. Today, we'll talk about accessing and using information returned by retrieve type APIs.

By Bruce Vining

System APIs generally return information to you in one or more structures. One API that uses this approach, and that you might find handy to know about, is the Retrieve Call Stack (QWVRCSTK) API and format CSTK0100. This API and format is shown below and documented here.

In previous columns, we discussed the basics of API error handling and data types. Today, we'll talk about accessing and using information returned by retrieve type APIs.

System APIs generally return information to you in one or more structures. One API that uses this approach, and that you might find handy to know about, is the Retrieve Call Stack (QWVRCSTK) API and format CSTK0100. This API and format is shown below and documented here.

Retrieve Call Stack (QWVRCSTK) API

Required Parameter Group:

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Receiver variable

Output

Char(*)

Length of receiver variable

Input

Binary(4)

Format of receiver information

Input
http://www.mcpressonline.com Powered by Joomla! Generated: 28 August, 2008, 23:44

MC Press Online

Char(8)

Job identification information

Input

Char(*)

Format of job identification information

Input

Char(8)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Error code

I/O

Char(*)

Default Public Authority: *USE

Threadsafe: Yes

Format CSTK0100: Return OPM and ILE Call Stack Entries

Offset

Type

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Field

Dec

Hex

BINARY(4)

Bytes returned

BINARY(4)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Bytes available

BINARY(4)

Number of call stack entries for thread

12

BINARY(4)

Offset to call stack entry information

16

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

10

BINARY(4)

Number of call stack entries returned

20

14

CHAR(8)

Returned thread identifier

28

1C

CHAR(1)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Information status

29

1D

CHAR(*)

Reserved

These fields repeat, in the order listed, for the number of call stack entries.

BINARY(4)

Length of this call stack entry

BINARY(4)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Displacement to statement identifiers

BINARY(4)

Number of statement identifiers

BINARY(4)

Displacement to the procedure name

BINARY(4)

Length of procedure name

BINARY(4)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Request level

CHAR(10)

Program name

CHAR(10)

Program library name

BINARY(4)

MI instruction number

CHAR(10)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Module name

CHAR(10)

Module library name

CHAR(1)

Control boundary

CHAR(3)

Reserved

BINARY(4), UNSIGNED

Activation group number


http://www.mcpressonline.com Powered by Joomla! Generated: 28 August, 2008, 23:44

MC Press Online

CHAR(10)

Activation group name

CHAR(2)

Reserved

CHAR(10)

Program ASP name

CHAR(10)

Program library ASP name


http://www.mcpressonline.com Powered by Joomla! Generated: 28 August, 2008, 23:44

MC Press Online

BINARY(4)

Program ASP number

BINARY(4)

Program library ASP number

BINARY(8), UNSIGNED

Activation group number long

CHAR(*)

Reserved

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

ARRAY(*) of CHAR(10)

Statement identifiers

CHAR(*)

Procedure name

This API, which returns information about all programs and procedures active in a thread's call stack, requires six parameters. The Receiver variable is where the API returns the information, and, as we learned in "Understanding API Data Types," the Char(*) definition tells us it's a variable-length parameter. The Length of receiver variable is a 4-byte integer used to tell the API how much storage we've allocated for the Receiver variable parameter. Format of receiver information is an 8-byte character value that defines the type of information we want the API to return in the Receiver variable parameter. We will be using format CSTK0100, which instructs the API to only return information on OPM and ILE programs (*PGM) and service programs (*SRVPGM) and to return the information in the form shown immediately above. Job identification information is a variable-length input structure where you identify the job thread you want call stack information about, and Format of job identification information is an 8-byte character value defining the format of the Job identification parameter. We will be using format JIDF0100, which is shown here:

Format JIDF0100: Identify Job and Thread of Interest

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Offset

Type

Field

Dec

Hex

CHAR(10)

Job name

10

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

CHAR(10)

User name

20

14

CHAR(6)

Job number

26

1A

CHAR(16)

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Internal job identifier

42

2A

CHAR(2)

Reserved

44

2C

BINARY(4)

Thread indicator

48

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

30

CHAR(8)

Thread identifier

The sixth parameter, Error code, is a variable-length structure that was discussed in "System API Basics."

The structures returned by this API are more complex than what you will find with many APIs, but they do include various features that I want to discuss. Below is a program that accepts one parameter: the number of call stack entries you want information about, starting with the procedure currently running. The program then displays the procedure and program names found.

dCallStack

pr

extpgm('CALLSTACK')

d NbrEntInput

15p 5 const

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

dCallStack

pi

d NbrEntInput

15p 5 const

dGetCallStack

pr

extpgm('QWVRCSTK')

d RcvVar

options(*varsize)

d LenRcvVar

10i 0 const

d FmtRcvVar

const

d JobID

65535

const options(*varsize)

d FmtJobID

const

d ErrCde

likeds(QUSEC)

/copy qsysinc/qrpglesrc,qwvrcstk

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

/copy qsysinc/qrpglesrc,qwcattr

/copy qsysinc/qrpglesrc,qusec

dRcvVar

ds

likeds(QWVK0100)

based(RcvVarPtr)

dEntryInfo

ds

likeds(QWVCSTKE)

based(EntInfPtr)

dProcName

256

based(ProcNamePtr)

dNbrEnt

10i 0

dCount

10i 0

dCurProcName

52

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

dPrvPgmName

10

dWait

/free

// Check for parameter, default to all

if %parms = 0;

NbrEnt = *hival;

else;

NbrEnt = NbrEntInput;

endif;

// API is to return escape messages if an error is found

QUSBPRV = 0;

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

// Initialize Job identification format JIDF0100

QWCF0100 = *loval;

// Set structure to x'00's

QWCJN02 = '*';

// Job name: * = this job

QWCUN = *blanks;

// User name

QWCJNBR00 = *blanks;

// Job number

QWCIJID = *blanks;

// Internal job ID

QWCTI00 = 1;

// Thread = this thread

// Call API to find out how much storage is needed

GetCallStack(QWVK0100 :%size(QWVK0100) :'CSTK0100'

:QWCF0100 :'JIDF0100' :QUSEC);

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

// Check information status

select;

when QWVIS = ' ';

// Info OK

when QWVIS = 'I';

// Info partial, still OK

when QWVIS = 'N';

// Info not available

dsply 'Information is not available.' ' ' Wait;

*inlr = *on;

return;

other;

dsply ('Unexpected status value of ' + QWVIS) ' ' Wait;

*inlr = *on;

return;

endsl;

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

RcvVarPtr = %alloc(QWVBAVL);

// Get the storage

GetCallStack(RcvVar :QWVBAVL :'CSTK0100' // Call API again to get

:QWCF0100 :'JIDF0100' :QUSEC); // all of the data

// Check information status in case anything has changed

select;

when RcvVar.QWVIS = ' ';

// Info OK

when RcvVar.QWVIS = 'I';

// Info partial, still OK

when RcvVar.QWVIS = 'N';

// Info not available

dsply 'Information is not available.' ' ' Wait;

*inlr = *on;

return;

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

other;

dsply ('Unexpected status value of ' + RcvVar.QWVIS) ' 'Wait;

*inlr = *on;

return;

endsl;

// If call stack isn't as large as user requested, then tell them

if NbrEnt > RcvVar.QWVERTN;

NbrEnt = RcvVar.QWVERTN;

dsply ('Showing ' + %char(NbrEnt) + ' call stack entries.');

endif;

EntInfPtr = RcvVarPtr + RcvVar.QWVEO;

// Get the first entry

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

for Count = 1 to NbrEnt;

// Process all entries

// that were requested

// Display Pgm/Srvpgm name when it changes

if EntryInfo.QWVPGMN <> PrvPgmName;

PrvPgmName = EntryInfo.QWVPGMN;

dsply ' ';

dsply ('Program name: ' + EntryInfo.QWVPGMN);

endif;

// If procedure name was returned, display it up to the max

// byte limitation of the dsply opcode (currently 52)

if EntryInfo.QWVPD > 0;

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

ProcNamePtr = EntInfPtr + EntryInfo.QWVPD;

if EntryInfo.QWVPL > %size(CurProcName);

CurProcName = %subst(ProcName :1 :%size(CurProcName));

else;

CurProcName = *blanks;

CurProcName = %subst(ProcName :1 :EntryInfo.QWVPL);

endif;

dsply CurProcName;

else;

dsply 'Cannot determine procedure name. OPM perhaps?';

endif;

EntInfPtr += EntryInfo.QWVEL;

// Move to next entry

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

endfor;

dealloc RcvVarPtr;

// Free the storage

dsply 'End of call stack list.' ' ' Wait; // Wait for the operator

// to indicate list read

*inlr = *on;

return;

/end-free

While the program is shown in its entirety, today we will only look at this program up through the initial call to the QWVRCSTK API. Because of space considerations, we will defer discussion of the remainder of the program to the next article.
http://www.mcpressonline.com Powered by Joomla! Generated: 28 August, 2008, 23:44

MC Press Online

As you are quite familiar with RPG, I won't go into the details of the program other than to explain how they relate to API usage or to explain an implementation decision. The first decision is the declaration of the NbrEntInput parameter as a packed decimal 15,5. This was done for ease of use in testing the program from the command line. If this parameter is not provided, the program will default to showing all call stack entries.

The program uses several include files that are provided with i5/OS in the QSYSINC library. The QWVRCSTK include file provides the definitions for format CSTK0100, QWCATTR the definition for format JIDF0100, and QUSEC the definitions for the QUSEC Error code structure. In case you're wondering how I knew to use these particular include files, the convention is that include file names are the same as the name of the *PGM or *SRVPGM implementing the API. As I'm using the QWVRCSTK API, the associated file member in QSYSINC/QRPGLESRC is QWVRCSTK. While I might expect member QWVRCSTK to also define format JIDF0100, I find in looking at the QWVRCSTK include that there is a comment saying that the job identification structures are found in include QWCATTR, so I /copy that include also. And as discussed in "System API Basics," the standard API error code structures are found in QUSEC. If you don't have QSYSINC on your system, you can install it with option 13 of i5/OS.

From an API usage point of view, the first item the program takes care of is how API error messages are to be returned. In our case, we are setting the Bytes provided field (QUSBPRV) of the Error code structure (QUSEC) to 0. This tells the API that we want serious errors to be returned as escape messages.

Next, the program initializes the Job identification data structure associated with format JIDF0100. In looking at source member QWCATTR, we can see that the name of the provided data structure is QWCF0100. An important aspect to keep in mind is how we initialize this structure. Imbedded within format JIDF0100 is a reserved field (QWCERVED06) that must be set to x'00's. When using API include files, never reference a reserved field by name. IBM reserves the right to start using any reserved field in a future release and, at that time, to change the reserved field's name to something more meaningful. This type of change by IBM would cause a compile failure if you had a statement in your application program such as 'QWCERVED06 = *loval;' and you needed to compile the application on that future release, even for some totally unrelated reason. You can avoid this exposure by initializing the entire structure to the required value and then setting the specific fields to indicate the function you want performed. In our case, we initialize QWCF0100 to x'00's and then set the other subfields (Job name QWCJN02, Job user name QWCUN, etc.) to indicate we want the call stack for the current job and thread.

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

At this point, the program calls the QWVRCSTK API. One structure being passed, QWCF0100, was discussed in the previous paragraph and identifies the job and thread we want call stack information about. The second structure, QWVK0100, is the IBM-provided data structure defining the fixed location fields of format CSTK0100, Bytes returned (QWVBRTN) through Information status (QWVIS).

Many i5/OS APIs return a receiver variable that contains only fixed-length fields and a fixed number of fields. The Retrieve Member Description API, QUSRMBRD, with format MBRD0100, introduced in "Understanding API Data Types," is such an API. Other APIs, such as QWVRCSTK, can return both a fixed amount of data (data structure QWVK0100) and a variable amount of data. In the case of QWVRCSTK, this variable amount of data associated with format CSTK0100 is defined by the data structure QWVCSTKE and the subfields Entry length (QWVEL) through Activation group number long (QWVAGNL). If you review Format_CSTK0100, you will see that the fields of QWVCSTKE are documented in the Offset section as not being at a fixed location within the Receiver variable and that the number of returned occurrences of QWVCSTKE is dependent on the number of call stack entries found. This is an indication that you will most likely find multiple data structures defined in the QSYSINC include file: one for the single occurrence structure, one or more for the multiple occurrence structure. To further muddy the waters, QWVCSTKE also returns a variable amount of data with each occurrence. A procedure name, for instance, can be from 1 to 256 bytes in length or, in the case of an OPM program, there may be no procedure name at all.

So how do we figure out how large a Receiver variable needs to be so that we get all of the call stack information? We don't know how many call stack entries there might be, and we don't know how big each call stack entry might be. We could just guess a large number of entries and multiply by the maximum size of an entry that might be returned to obtain a Receiver variable size, but there is a better way.

Most retrieve type APIs that return information to you include at least two fields in the fixed-size portion of the Receiver variable. These two fields are Bytes returned and Bytes available. Bytes returned tells you how many bytes of data the API actually returned to the Receiver variable. Bytes available tells you how many bytes of data could have been returned if you'd had a sufficiently large Receiver variable.

What we're doing with the initial call to QWVRCSTK is passing in the data structure QWVK0100 so that we can get back the Bytes available field QWVBAVL (along with some other very useful information). What we will do with QWVBAVL, and some of the other information found in QWVK0100, you'll see in the next article (or, if you're impatient, you can look at the sample program and see for yourself what we'll be doing!).

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

MC Press Online

Meanwhile, if you have other API questions, send them to me at bvining@brucevining.com. I'll see what I can do about answering your burning questions in future columns.

http://www.mcpressonline.com

Powered by Joomla!

Generated: 28 August, 2008, 23:44

Das könnte Ihnen auch gefallen