gtpa2m0kApplication Programming

A TPF Transaction Example

This section presents an example transaction that is followed through the system. Some of the coding details have been simplified for the purposes of discussion. Many of the C functions used in coding this example are further discussed in TPF Application Program Interface Functions.

At the outset, assume a TPF system that is idle, except that the communications control program (CCP) is monitoring the lines for input. System activity is triggered when any user enters a message at a terminal. A given terminal may have access to any application in the network, but until some association is established, TPF has no knowledge of the intended destination of the message. The first message will be a request to connect the terminal to some application. This is done with a login message specifying the application. For example:

LOGI CRED

This message requests TPF to connect the inputting terminal to a credit verification application identified as CRED. (CRED is defined as a non-SNA application.) This new message would normally be placed at the bottom of a queue called the input list. In our example the system is idle so that it is processed immediately. The process flow is as follows:

Step 1
The CCP gives control to a system program called OPZERO, which performs 2 principal functions.

Step 2
OPZERO passes control to the communications source processor (COMM SOURCE), whose principal function is to determine the intended destination of the message and to create the routing control parameter list (RCPL). The RCPL, like the ECB, will be associated with this entry throughout its life in the system; it defines the origin and destination of the message as well as descriptive information to facilitate routing and processing. COMM SOURCE stores the RCPL in the ECB work area at location EBW000.

COMM SOURCE also retrieves a routing control block (RCB) or agents assembly area (AAA), or both, depending on what the application expects. (See Routing Control Block) By convention, the RCB address is placed in data level 3 of the ECB, while the AAA address is placed in data level 1. In a central processing complex with more than 1 instruction stream COMM SOURCE also may be used to determine the routing of the message to an application specific I-stream or to the I-stream determined by the system. This is done by a COMM SOURCE user exit. Finally, COMM SOURCE passes control to the log processor (assuming the terminal is not already logged to an application).

Step 3
The log processor in effect connects the inputting terminal to application CRED. The log processor updates the slot for the terminal in the WGTA table. If the terminal is an SNA logical unit, the resource vector table (RVT) also is updated. The index value indicates the connection and also points to the program to be activated to begin processing the message for application CRED.

The log processor generates a message stating that the terminal has been successfully connected to application CRED and requests the TPF message router to send it to the requesting terminal. The details of how this is done are deferred to the next message.

Step 4
The terminal operator is now in a position to enter messages for the credit verification application. Until the connection is terminated all input from this terminal will be so routed. The operator enters a message requesting credit against a specific account number for a value of $75. For example:
     /4247852601709 $75
 

The first character (/) is an action code identifying the format and expected function of the message. Now assume for clarity in following the flow that the terminal is connected to a BSC line. Processing will begin as described in Step 1. It continues with Step 2 in creating the RCPL and retrieving the RCB. However, when COMM SOURCE looks at the WGTA slot for this terminal it finds that it is already connected to an application. The index value in the WGTA points to information in the application name table and the routing control application table, which supply the file address of the input message editor for application CRED. COMM SOURCE passes control to this program, which we will call CRC1. Figure 1 shows the conditions when CRC1 (the application) is activated.

Figure 1. Conditions When Application Is Activated. The RCB and/or the AAA may be present.


To summarize:

Should this message come in from an SNA network, conditions would be identical except that there would be no RCB on level 3 (unless the application is RCB-dependent), and the origin field of the RCPL would be in SNA format (sequence number, resource ID/CPU ID).

From this point, the processing flow is exclusively in the hands of the application and unlimited variations are possible. It depends on the complexity of the functions to be performed and the application design. Conceivably, a simple application might be contained in one program segment, which would do something with the data blocks passed to it by COMM SOURCE, send its response message, and exit. On the other hand, a complex application may involve hundreds of program segments interacting with each other and TPF, extensive file accessing and main storage requirements. For the purpose of this example, assume a simple credit verification application of two program segments and arbitrarily select some commonly used functions that illustrate the manner in which application programs interface with TPF. Figure 2 shows the logic flow for CRC1 and Figure 3 shows the logic flow for CRC2.

Step 5
There are different procedures for assembly language programs and C language programs.

For assembly language, after first determining that this is a normal new input message, CRC1 must edit the message and determine which function is being requested. TPF provides a data macro that defines the fields in the input message and allows the program to refer to it by symbolic tags. The data macro name is AM0SG.

Example:

AM0SG REG=R2
 

By issuing the data macro statement, CRC1 indicates to the assembler that it intends to address the AM0SG record using register 2 as a base. The symbolic tags can be referred to by loading R2 with the pointer to the input message from level 0 of the ECB.

The input message tokenization support macro BPKDC might be used, or the program could supply its own logic for the edit. In any case, CRC1 determines that the message is a valid standard request for credit.

For C language, after first determining that this is a normal new input message, CRC1 must edit the message and determine which function is being requested. CRC1 uses the scanf function to read the data in. The scanf function locates and then parses the input message into an account number and an amount and returns the number of fields that were successfully converted and assigned. Note that the gets function must be implemented for the scanf function to work properly. The scanf and gets functions are not implemented according to the ANSI standard. See the TPF C/C++ Language Support User's Guide for details on scanf and gets.

Alternatively, the C language parser (IPRSE_parse) can be used in this example.

Example:

  rc = scanf("/%[0123456789] $%d", acctnbr, &amount);
 

For the purposes of this discussion, assume that the message is a valid standard request for credit.

Step 6
The program then retrieves the negative credit file, which resides on the fixed file. The fixed file is a DASD file area assigned permanently to specific functions or record types, as opposed to the dynamic pools, which may be used repeatedly for various purposes. There are many types of records on the fixed file, but the TPF file access routines see it as one file. Therefore, before requesting TPF to retrieve the negative credit file record you must supply its ordinal number (relative record number) in the entire fixed file. The application only knows the ordinal number in the negative credit file. To resolve this, all records on the fixed file are assigned a record type, identified by a symbolic name.

TPF provides an index table and utility program called FACS, which, when given the symbolic record type and ordinal number in that type, will calculate the ordinal number in the entire fixed file. Hereafter, ordinal number in the entire fixed file will be referred to in this publication as the symbolic file address.

Note:
An older form of this program, called FACE, operates like FACS except that a numeric rather than symbolic record type is passed to FACE. The numeric record type is set up using an equate in assembly language or a #define in C language; however, any changes to the FACE index table may require programs that use FACE to be recompiled. Programs that use FACS are not affected by changes to the FACS index table. See FACE, FACS, and FAC8C for further information.

Assembly program CRC1 calculates the ordinal number of the desired negative credit file record and transfers control to FACS, supplying this ordinal number, the symbolic record type (for example: #VD1VD), and the location in the file address reference word (Step 8) at which the symbolic file address is to be stored.

Example:

ENTRC FACS

Figure 2. Logic Flow for Program CRC1

Pseudo logic for credit application segment CRC1.
-------------------------------------------------
 
Edit input message into acct# and amount.
 
Compute Negative file record address on level D2.   /* FACS or face_facs */
Retrieve Negative file record on level D2.          /* finwc or find_record */
 
If acct# is in Negative file record,
    Indicate negative response.
    Unhold RCB.                                     /* unfrc */
Else,
    Get floor limit address                         /*GLOBZ or glob */
    If floor limit is exceeded,
        Indicate floor limit reject.
        Unhold RCB.                                 /* unfrc */
    Else,
        Release message block (D0).                 /* crusa */
        Release Negative file record block (D2).
        Release RCB (D3).
        Unhold RCB.                                 /* unfrc */
 
        Call CRC2.                                  /* Process activity file */
 
Get block for output message on level D6.           /* getcc */
Edit output message in block on level D6.
Build output message RCPL.
Request send output message.                        /* routc */
 
Exit.
 

Program CRC1 calculates the ordinal number of the desired negative credit file record and calls FACS, supplying this ordinal number, the symbolic record type (for example: #VD1VD), and the location in the file address reference word (Step 8) at which the symbolic file address is stored.

In assembler, use the ENTRC macro to call FACS:

ENTRC FACS

In C, include the header file <tpfio.h> to declare the FACS function. FACS takes a single parameter, a pointer to a TPF_regs structure (defined in <tpfregs.h>). The fields of the TPF_regs structure (R0, R6, and R7) imitate the assembler interface to FACS.

The TPF C library also provides a face_facs function, which is a more intuitive interface for calculating a fixed file address.

Example:

  #include <tpfio.h>
  #define VD1RI "#VD1VD  "
  #define VD1RI_ordinal 10

  ·
  ·
  ·
unsigned long rtnord ; /* return ordinal */
  ·
  ·
  ·
/* ** Locate negative credit record (VD1VD) for account on fixed file. */ int ffrc = face_facs(VD1RI_ordinal,VD1RI,0,D2,&rtnord) ; /* Calc fixed file address */

Step 7
The assembler program FACS or the ISO-C face_facs function calculates the symbolic file address of the desired negative credit file record, stores it at the location specified, and returns control to CRC1.

Step 8
CRC1 now can request that TPF read the record from file storage into main storage. This is done with the FINDC macro (assembly language) or the find_record (C language) file reference function. Before the function is called, a data level must be chosen and the FARW set up. The FARW is an 8-byte control field for file activity associated with each ECB data level. The low order 4 bytes will contain the symbolic file address because FACS or face_facs placed it there in Step 6.

The high order 4 bytes of the FARW are for data integrity. Normally, the requesting program must specify the record identification as an argument in the function call so that it will be entered in to the high-order 2 bytes of the FARW. The record identification will also appear in the header of the record in file storage. (This record identification is assigned to your application by an application or data base designer.) CRC1 enters the ID (for example, VD) and then requests TPF to read the record into level 2 and return control to CRC1 only after the I/O is complete. The coding for this form of the macro is:

FINWC D2,ERROR1

ERROR1 is the symbolic tag in CRC1 to which control will be returned if there is any abnormal I/O condition.

For C, the find_record function call requires the following arguments:

level
The data level of an available FARW and CBRW for use by the system.

address
A pointer to the file address of the record to be retrieved; NULL if the FARW has been preinitialized.

ID
A 2-character string that must match the identification characters in the record to be retrieved; RECIDRESET if the identification field has been preinitialized. If the requested ID does not match the record's identification characters, the ECB error fields will indicate an identification check failure and control will return to the application at I/O completion. No comparison will be made if the identification field is zero ('\0').

rcc
An unsigned character that must match the record code check (rcc) byte in the record to be retrieved. If the requested rcc does not match the record's rcc, then the ECB error fields will indicate an identification check failure and control will return to the application as described above for the ID argument. If rcc is zero ('\0'), then no comparison will be made.

type
What the record's hold status will be after I/O completion, either NOHOLD or HOLD.

CRC1 requests TPF to read the record into level 2 and return control to CRC1 only after the I/O is complete. An example of the coding for this form of the function is:

  vd1ptr = find_record(D2, NULL, "VD", '\0', NOHOLD);
 

Step 9
TPF obtains an appropriate storage block and reads the negative credit file record into main storage, then returns control to CRC1. Assume that there are no errors or integrity failures.

Step 10
CRC1 searches the record for the input account number. Assume it is not found; the account is, therefore, in good standing, and the next step proceeds.

Step 11
The dollar value requested in the message must now be checked against a floor limit; requests greater than the floor limit are rejected. The floor limit is only a 4-byte field, but must be accessed by every entry (except those found in the negative credit file). For performance considerations, it should be stored in an area accessible to all entries but not requiring a file retrieval. For such requirements TPF maintains the global area.

The global area is a section of main storage accessible to all users by executing the appropriate functions. It can be used for any type of data requiring quick access, from miscellaneous constants to main storage resident data records.

By issuing one macro (GLOBZ), the assembler application program can load the base register and have access to any field in the first 4096 bytes of the global area. These 4096 byte global areas are unique to each I-stream. If there are any shared resources in these areas, provision must be made to handle the synchronization of accessing/updating these resources. It is, therefore, a common practice to place, in the first 4096 bytes, address pointers to the rest of the global area.

Example:

GLOBZ REGR=R5

The system loads register 5 with the base of the global area. By convention all tags in the global area (used by assembler language programs) begin with the character @. For example, the floor limit might be stored in a field labeled _cflth. CRC1 now compares the input value with the global field; it finds the request value below the floor limit and proceeds to the next step.

The c$globz.h C language header file contains symbolic tags and displacements for miscellaneous data fields and pointers to records in the global area. By calling one function (glob), the application program can examine any global field or record.

By TPF convention, all tags in the global area begin with the character "_" for C language code; however, it is important to note that when the same tags are referenced in assembler language code, the corresponding names must begin with the "@" character. Also, other characters in the tag name are converted to lowercase. For example, the floor limit might be stored in a field labeled _cfltn for C language access and atcfltn for assembler access.

CRC1 now compares the input value with the global field; it finds the request value below the floor limit and proceeds to the next step.

Example:

  cfltn = glob(_cfltn);            /* Check against global limit       */
  if(amount > *cfltn)
    msgnexit("OVER FLOOR LIMIT\n");
 

Step 12
The next functional requirement is to check the requesting account number for excessive activity on this date and during this week.

For this purpose an activity file is maintained. All processing cannot be contained in one segment so that activity file processing will be handled by program segment CRC2.

Before passing control to CRC2, however, CRC1 will return any system resources not in use or imminently planned for use. All system resources such as main storage blocks and file pool addresses should be returned promptly. Since many ECBs operate concurrently, failure to do this could be a significant drain on system performance and require excessive resource allocation.

CRC1 finds three items no longer required:

These blocks are returned to the system with the crusa function, which requires only the number of levels to be released and the names of the data levels themselves.

Because CRC1 expects to be reactivated after activity file processing, it passes control to CRC2 with the return option.

Example:

ENTRC CRC2

Figure 3 shows the logic flow for CRC2.

C language example:

   /*
   ** Discard input message, VD1VD record block, and RCB
   */
 
   crusa(3, D2, D3, D0);         /* Release core blocks        */
   unfrc(D3);                        /* Unhold the RCB file record */

Figure 3. Logic Flow for Program CRC2

Pseudo logic for credit application segment CRC2.
-------------------------------------------------
 
Compute Activity file record address on level D4.   /* FACS or face_facs */
Retrieve and HOLD Activity file record on level D4. /* fiwhc or find_record */
 
If acct# is in Activity file record,
    Update usage counts.
Else,
    If there is room for acct# in Activity record,
        Add acct# and set usage count to 1.
    Else,
        Get block for chained Activity record (D5).
        Get file address for chained record (D5).   /* getfc */
        Chain new file address to prime record.
        Initialize new Activity file record.
        Add acct# and set usage count to 1.
        File chained record (D5).                   /* filec */
 
File and UNHOLD prime record (D4).                  /* filuc or file_record */
 
Create CRC3 to record transaction log.              /* cremc */
Return to caller.

Step 13
The next functional requirement is to check the requesting account number for excessive activity on this date and during this week. For this purpose an activity file is maintained. The activity file also resides on the fixed file. CRC2 calculates the ordinal number of the required activity record and calls FACS (or face_facs for C language), passing the ordinal number, the activity file record type (for example, "#VU1VU "), and the level 4 FARW as the location for storing the symbolic file address.

C language example:

  #define vu1vu "#VU1VU  "
  #define vu1vu_ordinal 100  struct TPF_regs regs ;

  ·
  ·
  ·
/* ** Check if there has been excessive activity for this account. ** Locate credit activity record on fixed file. */ regs.r0 = vu1vu_ordinal /* Ordinal number */ regs.r6 = (long) vu1vu; /* Record identification (type) */ regs.r7 = (long) &(ecbptr()->ce1fa4); /* Data level */ FACS(&regs); /* Calculate record address */

Step 14
The FACS macro (or the face_facs function) calculates the symbolic file address of the activity record, stores it in the FARW of level 4, then returns control to CRC2.

Step 15
CRC2 enters the record identification for the activity file in the FARW, then calls a find-wait-and-hold form of the find_record function to read the record into data level 4.

For example:

FIWHC D4,ERROR2

C language example:

  if(!(vu1ptr = find_record(D4, NULL, "VU", '\0', HOLD)))
    serrc_op(SERRC_EXIT,00x1238, "ACTIVITY FILE FIND ERROR",NULL);
                             /* If no prime exists, error.       */
 

To assure data integrity and proper sequencing of updates when modifying a file, programs intending to update a record must ensure that the record is not currently being updated by another program. The program does this either by:

The record is read successfully and searched for the input account number, but the account number is not found. This is a normal condition. Account numbers appear in this file only if used in the last seven days. An item appearing for the first time in the last seven days must be added to the file.

Step 16
CRC2 must add the item to the file and note its use today. However, the record is full and no records are chained from it. A new record must be created, chained to the first record (now called the prime record), and filed in the random pool. Unlike the fixed file, the random pool is a section of DASD storage assigned to no specific record type. It is a dynamic pool of file blocks from which any entry may request a record from TPF and return it when no longer required. The pools are divided only by record size and usage classification. (Refer to Random Pool File Area).

To create the new file record CRC2 takes the following steps:

  1. It requests from TPF a file address from the random pool and a main storage block in which to build the record. The GETFC macro in assembly language or the getfc function in C language obtains the file pool address and storage block. Although transparent to the application, this record identification is an index into the RIAT and tells TPF the pool type from which to take the address. The application need know only the record identification of the it is building. The size of the acquired working storage block is determined by the attributes associated with the record identification.

    The ID ("VU" in this example) is stored in the header of the new block on level 5 and in the FARW for level 5. The ID is the same because this block is a chain extension of the prime record, whose identification is VU. All records chained together have the same record identification. (The record identification is assigned to the application by an application designer.)

    Assembly language example:

    GETCC D5,L2     Request a 1055-byte (L2) block on level 5
    

    C language example:

      vu1ptr->vu1fch = getfc(D5, GETFCOVERF, "VU", GETFCBLOCK,
        GETFCSERRC);
     
    /* model:  getfc(level,type,ID,block,error)
    

    The c language arguments and descriptions are as follows:

    level
    The data level.

    type
    The pool type and size to be used with the ID argument.

    ID
    A pointer to a 2-character record identification that will be used in scanning the record identification attribute table (RIAT).

    block
    Whether or not a block of working storage should simultaneously be obtained.

    error
    Whether or not control should be returned to CRC1 in the event of an error.
  2. CRC2 store upon return the new random pool address returned by TPF in the FARW for level 5 in the forward chain field of the prime record on level 4.
  3. CRC2 initializes the chain record and enters the new data item and item count of 1 in the new record.
  4. CRC2 files the newly created chain record and then files and unholds the prime record.

Assembly language examples:

FILEC D5     Files chain record from level 5.
 
FILUC D4     Files and unholds prime record from level 4.

C language example:

  if (newpool)                /* If we got a pool,         */
      holdstatus = NOHOLD;    /* D4 record is not locked   */
                                  /* File the D4 record block. */
  file_record (D4, NULL, NULL, '\0', holdstatus);
  if (newpool)                /* If we got a pool,         */
  file_record (D5, NULL, NULL, '\0', UNHOLD);
                                  /* file the prime record.    */
 

Step 17
The user wishes to keep a transaction log containing a copy of the input values (account number and dollar value) for each request for which credit is granted. The items are to be blocked in a 1055-byte main storage block and then written to the real-time tape (RTA tape). However, the user does not want to keep the customer and operator waiting on line for this processing, since all key decisions that relate to approving the credit have been made. CRC2, therefore, creates a separate entry to process the transaction log independently, passing to it the required log data and specifying the program to be called for initial processing (CRC3). This is done with a create macro in assembly language or a create function in C language, and CRC2 uses a form of the function that requests an immediate activation of the new entry.

Assembly language example:

LA    R14,48        Number of bytes to pass to the new entry
 
LA    R15,EBW020    Location of data to pass
 
CREMC CRC3          Program to be activated to process the new entry

C language example:

  cremc(sizeof(packedacct), cremargs, CRC3);
                                  /* Create entry CRC3 */
 

CRC3 then continues with the mainline process.

Step 18
CRC2 processing is now complete. In assembler, it issues a BACKC macro, which returns control to CRC1. In C language, control is returned by a return statement. Note that it is not necessary to return the main storage blocks on levels 4 and 5 because TPF does this automatically unless instructed not to do so.

All that remains is to send a message to the terminal operator indicating that the credit may be granted.

The first requirement for an assembly language program to send a message is to build the message block. The first or only segment of the message must be in main storage, attached to any level of the ECB. CRC1 requests a 127-byte block from TPF on level 6. The same data macro (AM0SG) is used for output and input messages. The data macro is issued, and register 3 loaded with the pointer from level 6.

GETCC D6,L0
AM0SG REG=R3
L     R3,CE1CR6

The header of the record is initialized with the record ID ('OM'), the forward chain field is zeroed, and the character count and text are entered.

In a C language program, CRC1 uses the puts function to output the message to terminal.

Step 19
CRC1 builds the output RCPL for assembly language.

The puts function is not ANSI or ISO compliant. Its action is defined by site installation. The input RCPL, received from the COMM SOURCE program at EBW000, has not been disturbed and contains the necessary data for output. The first two fullwords containing destination and origin are exchanged; destination becomes the LNIATA and CPU ID of the terminal, origin becomes CRED. The control field bits are modified as described in the DSECT RC0PL for assembly language or the c$rc0pl.h header for C language.

Assembly language program CRC1 loads register 3 with the address of the RCPL (EBW000) and requests TPF to send the message by issuing the ROUTC macro.

Example:

ROUTC LEV=D6,LIST=R3

This specifies that the message is in core at level 6 and register 3 points to the RCPL.

Step 20
Processing for the entry is now complete; the application has no further function to perform. CRC1 stops by calling the EXITC macro in assembly language or the exit function in C language. TPF removes the entry from the system and releases the main storage block containing the ECB. If any main storage blocks are attached to the ECB, they are released at exit.

The preceding process by no means presents a definitive review of all application facilities. It is meant to be illustrative and to give a practical framework into which to fit the detailed descriptions that follow.