gtpa2m0k | Application Programming |
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:
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).
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.
/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.
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.
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.
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 */
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:
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);
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");
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.
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(®s); /* Calculate record address */
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:
A chain is a series of records, each with an address pointer to the next record in the series. The first record in the chain is usually called the prime record. This technique will not work if the record to be updated is part of more than one chain. See Record Hold Facility for further details.
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.
To create the new file record CRC2 takes the following steps:
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:
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. */
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.
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.
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.
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.