05
Tue, Nov
5 New Articles

The API Corner: Retrieving Information, Part I

APIs
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

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:

1

Receiver variable

Output

Char(*)

2

Length of receiver variable

Input

Binary(4)

3

Format of receiver information

Input

Char(8)

4

Job identification information

Input

Char(*)

5

Format of job identification information

Input

Char(8)

6

Error code

I/O

Char(*)


  Default Public Authority: *USE

  Threadsafe: Yes

Format CSTK0100: Return OPM and ILE Call Stack Entries

 

Offset

Type

Field

Dec

Hex

0

0

BINARY(4)

Bytes returned

4

4

BINARY(4)

Bytes available

8

8

BINARY(4)

Number of call stack entries for thread

12

C

BINARY(4)

Offset to call stack entry information

16

10

BINARY(4)

Number of call stack entries returned

20

14

CHAR(8)

Returned thread identifier

28

1C

CHAR(1)

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)

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)

Request level

CHAR(10)

Program name

CHAR(10)

Program library name

BINARY(4)

MI instruction number

CHAR(10)

Module name

CHAR(10)

Module library name

CHAR(1)

Control boundary

CHAR(3)

Reserved

BINARY(4), UNSIGNED

Activation group number

CHAR(10)

Activation group name

CHAR(2)

Reserved

CHAR(10)

Program ASP name

CHAR(10)

Program library ASP name

BINARY(4)

Program ASP number

BINARY(4)

Program library ASP number

BINARY(8), UNSIGNED

Activation group number long

CHAR(*)

Reserved

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

Offset

Type

Field

Dec

Hex

0

0

CHAR(10)

Job name

10

A

CHAR(10)

User name

20

14

CHAR(6)

Job number

26

1A

CHAR(16)

Internal job identifier

42

2A

CHAR(2)

Reserved

44

2C

BINARY(4)

Thread indicator

48

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                        

                                                                    

dCallStack        pi                                               

d NbrEntInput                   15p 5 const                        

                                                                   

dGetCallStack     pr                  extpgm('QWVRCSTK')           

d RcvVar                         1    options(*varsize)            

d LenRcvVar                     10i 0 const                        

d FmtRcvVar                      8    const                        

d JobID                      65535    const options(*varsize)      

d FmtJobID                       8    const                        

d ErrCde                              likeds(QUSEC)                

                                                                    

 /copy qsysinc/qrpglesrc,qwvrcstk                                  

 /copy qsysinc/qrpglesrc,qwcattr                                   

 /copy qsysinc/qrpglesrc,qusec                                     

                                                                    

dRcvVar           ds                  likeds(QWVK0100)             

d                                     based(RcvVarPtr)             

                                                                   

dEntryInfo        ds                  likeds(QWVCSTKE)             

d                                     based(EntInfPtr)             

                                                                   

dProcName         s            256    based(ProcNamePtr)            

dNbrEnt           s             10i 0                              

dCount            s             10i 0                              

dCurProcName      s             52                                 

dPrvPgmName       s             10                                  

dWait             s              1                                 

                                                                   

 /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;                                                        

                                                                      

  // 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);                        

                                                                      

  // 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;                                                             

                                                                     

  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;                                                      

     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   

                                                                      

  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;                                        

         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     

  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.

 

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.

 

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!).

 

Meanwhile, if you have other API questions, send them to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll see what I can do about answering your burning questions in future columns.

Bruce Vining

Bruce Vining is president and co-founder of Bruce Vining Services, LLC, a firm providing contract programming and consulting services to the System i community. He began his career in 1979 as an IBM Systems Engineer in St. Louis, Missouri, and then transferred to Rochester, Minnesota, in 1985, where he continues to reside. From 1992 until leaving IBM in 2007, Bruce was a member of the System Design Control Group responsible for OS/400 and i5/OS areas such as System APIs, Globalization, and Software Serviceability. He is also the designer of Control Language for Files (CLF).A frequent speaker and writer, Bruce can be reached at This email address is being protected from spambots. You need JavaScript enabled to view it.. 


MC Press books written by Bruce Vining available now on the MC Press Bookstore.

IBM System i APIs at Work IBM System i APIs at Work
Leverage the power of APIs with this definitive resource.
List Price $89.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: