gtpa2m2aApplication Programming

TPF Application Environment

Accessing the ECB

There is an entry control block assigned to each input message or entry that defines all resources allocated to process that entry. The C data structure corresponding to the ECB is called eb0eb, and is defined in header file c$eb0eb.h. The macro, ecbptr, is used to obtain access to the ECB. Figure 19 shows 2 examples of using this macro. In the first example, pointer ecb is initialized to point to the current ECB. In the second example, amsg is a pointer data object that is assigned to point to the AM0SG record on data level 1. The ecbptr macro returns the base address of the ECB.

Figure 19. Using ecbptr to Access the Contents of ce1cr1


struct eb0eb   *ecb;
struct am0sg   *amsg;

  ·
  ·
  ·
ecb = ecbptr(); /* set ecb to point to ECB */ amsg = ecbptr()->ce1cr1; /* set aaa to point to 1st CBRW in ECB */

The ecbptr macro is resolved by a single instruction. Repeated calls to ecbptr, therefore, generate more efficient code than storing the result and using that result as a pointer to the eb0eb structure.

Work Areas

The ECB contains areas for application use and reference, as well as several areas that only TPF can use. Areas available to the application program are known as work areas. There are 2 work areas, known as the EBW and EBX work areas, which are controlled by the application. These areas are used as transient work areas, as register save areas, for switch settings, or for other application purposes. C/C++ programmers, however, must use these areas judiciously, because they are subject to modification by any program segment that processes this entry. In the course of processing the entry, the contents of these areas are used for different purposes. Because automatic storage is available in C/C++ programming, it should be used for internal variables. For C/C++ programmers, the preferred purpose of the ECB work areas is to interface with assembler programs. There are several ways to pass parameters or values in assembler, including using registers and by using these ECB areas.

Programming Rule

Avoid using the ECB work areas for storing transient data. The preferred use of these areas is to pass arguments to or receive values from a called assembler segment. Use automatic storage for internal variables.

Data Levels

Information about file addresses is stored in 8-byte fields called file address reference words (FARWs). Information about certain main storage blocks is stored in 8-byte fields called core block reference words (CBRWs). There are 16 FARWs and 16 CBRWs per ECB, each of which is associated with a data level. The data levels are identified in hexadecimal notation as D0 (data level 0) through DF (data level 15).

Think of a data event control block (DECB) as another ECB data level, but it does not reside in an ECB. An ECB data level and a DECB are very similar, but in a DECB the FARW has been expanded to 12 bytes to provide 8-byte file addressing. For more information, see Data Event Control Blocks.

Managing Files

The TPF system supports stream input/output (I/O) at an abstract level, with a hierarchical file system modeled on the UNIX and Portable Operating System Interface for Computer Environments1 standards (POSIX) TPF also supports record-level DASD I/O using TPF-specific FIND and FILE protocols. The TPF tape and general file interfaces are also record-level protocols.

TPF File System

The TPF file system automatically and transparently handles low-level problems such as record blocking, allocation, chaining, and locking protocols. The TPF file system also gives efficient direct access to data in a file. When used appropriately, the hierarchical file system can significantly reduce the cost and time required to design, implement, and maintain applications.

The TPF file system application programming interface (APIs) include all of the ANSI Standard C library (ISO/IEC 9899-1990, section 7) and most of the POSIX1, standards sections 5 and 6. The TPF file system is not POSIX compliant but for most of the API functions, the interfaces and semantics are identical to POSIX1 (see TPF C/C++ Language Support User's Guide for details about deviations between the TPF file system APIs and the POSIX.1 standards).

The TPF file system APIs work at two levels:

The more abstract level is the buffered I/O functions, declared in <stdio.h>. The buffered I/O functions operate on a pointer to FILE. Examples include fopen, fclose and fflush; fread and fwrite; the formatted I/O functions such as fprintf and fscanf; the character I/O functions such as fgetc, fgets, fputc, fputs; and many others. These APIs are typically used in C language applications that need to create and access files. In general, they are easier to use and more efficient than the less abstract system-level functions that follow.

The system-level I/O functions, declared in <unistd.h>, <fcntl.h>, <dir.h>, and other headers, are appropriate in cases where an application needs to work on the directory structure itself or where more control over files than is provided by the buffered I/O functions is required. The system-level I/O functions operate on a file descriptor, a path name (which is a C string), or a pointer to DIR. Examples include creat, open, close, read, write, fcntl, chdir, chown, chmod, mkdir, mknod, and stat, and many others.

It is possible to switch levels if necessary. The fileno function returns the file descriptor underlying a pointer to FILE, allowing you to switch from buffered I/O to system-level I/O. Conversely, the fdopen function creates a pointer to FILE from a previously opened file descriptor, allowing you to switch from system-level I/O to buffered I/O.

Record-Level DASD I/O

The term DASD refers to direct access storage devices. C programmers can think of the term DASD as being synonymous with disk file, or disk, or file.

The basic record-level DASD I/O actions are implemented in TPF API functions find_record and file_record. The waitc function is used in TPF for error detection at the record I/O level. See TPF C/C++ Language Support User's Guide for more information about these functions.

Figure 20. Using the waitc Function for Error Detection


if(waitc())             /* if nonzero return code                         */
  {
  snapc(SNAP_EXIT,0x6404,"I/O ERROR",NULL,'U',SNAPC_NOREGS,SNAPC_ECB,NULL);
                                           /* force abnormal exit   */
  }

There are two groups of find and file functions. The first group is higher level in the sense that invoking one function takes care of several different operations with one command. These functions are also simpler to use, because the programmer can specify certain fields (id and rcc) as parameters on the function call, rather than setting these CBRW fields with separate assignment statements.

 file_record 
File a record.

 file_record_ext 
File a record with extended options (this function includes TPF DECB support).

 find_record_ext 
Find a record with extended options (this function includes TPF DECB support).

 find_record 
Find a record.
Note:
Applications that call the find_record_ext and file_record_ext functions and use 8-byte file addresses or DECBs in place of data levels, must be compiled with the C++ compiler. For more information about TPF DECB support, see Data Event Control Blocks.

Additional find and file functions that give the C programmer more control, and should, therefore, be used with more caution are:

 filec 
File a record

 filnc 
File a record with no release

 filuc 
File and unhold a record

 findc 
Find a record

 finhc 
Find and hold a record

 finwc 
Find a record and wait

 fiwhc 
Find and hold a record and wait

 unfrc 
Unhold a file record.

When using this second set of functions, programmers must have a greater understanding of the system file-record-level I/O routines and may need to call the waitc function to make sure the record is attached to the ECB.

See the detailed API function descriptions in TPF C/C++ Language Support User's Guide for more information about the use of these functions.

The TPF system also uses another entity for file I/O, called a general data set. General data sets are organized on the basis of contiguous space on DASD, and are compatible with MVS. Two functions are used to manage this type of data set:

 gdsnc 
Open and close data set

 gdsrc 
Get record address.

Tape I/O

Real-time tapes are tapes that can be written to (and only written to) at any time by any operation in the system. There are two API functions available to write to real-time tapes:

 tourc 
Write record, release buffer block

 toutc 
Write record, retain buffer block.

General tapes are I/O tapes used for application programming. They allow the application program to write to consecutive files and read them in logical sequence. There are two groups of API functions for managing general tapes: basic general tape functions and high-level general tape functions.

A basic general tape function performs a single tape function and gives an ECB absolute control over a tape. (However, a tape can be shared between ECBs by assigning and reserving a tape in the appropriate sequence.) Using the basic general tape functions can also provide more efficient processing if it is needed. The basic general tape functions are:

 tasnc 
Assign tape to process

 tbspc 
Backspace tape

 tclsc 
Close a general tape

 tdspc 
Display tape status

 tdspc_q 
Display tape queue length

 topnc 
Open tape

 tprdc 
Read tape record

 trewc 
Rewind tape

 trsvc 
Reserve tape for other processes

 tsync 
Flush tape buffer

 twrtc 
Write tape record.

A high-level general tape function performs multiple tape functions from the set of basic general tape functions and allows all ECBs to share a tape.

At the beginning of processing a high-level general tape function, all the functions, except for tape_open, assign the tape. Therefore, when you use these functions, except for tape_open, you must reserve the tape or the tape must be in a reserved state from previous processing.

At the end of processing a high-level general tape function, all the functions, except for tape_close, reserve the tape. Therefore, when using these functions, except for tape_close, the tape will be left in a reserved state at the end of processing.

The high-level general tape functions are:

 tape_close 
Close a general tape

 tape_cntl 
Tape position control

 tape_open 
Open tape

 tape_read 
Read a record

 tape_write 
Write a record.

ECBs and Entries

In the TPF system each active entry has an ECB associated with it. Once created, the ECB is processed by a specific application, which can consist of many individual program segments.

Control

An ECB or entry has control when it has the attention of the CPU. Control is granted based on the CPU loop, the TPF system's scheduling system. (See TPF Concepts and Structures or TPF Main Supervisor Reference for more detail about the CPU loop and task dispatching.)

Control is lost under the following circumstances:

The TPF system will also force an ECB to exit if it does not relinquish control to the operating system in 500 milliseconds (that is, it appears to be looping). This timer is reset when an ECB waits for pending I/O with the waitc function and when it suspends processing through the dlayc and defrc functions.

When TPF Enter/Back services are invoked, the same ECB remains in control and continues processing with another program segment.

You can create an entry (ECB) by calling one of the following TPF API functions:

 credc 
Create a deferred entry

 creec 
Create a new ECB with an attached block

 cremc 
Create an immediate entry

 cretc 
Create a time-initiated entry

 cretc_level 
Create a time-initiated entry with an attached core block

 crexc 
Create a low priority entry.

 tpf_cresc 
Create a synchronous entry

 system 
Execute a command

The application program is responsible for passing any required data to the newly created ECB when it calls the TPF API library function. In particular, note that the input message and terminal address are not automatically copied to the new ECB. In the TPF system environment, there is not a strong parent-child relationship between entries; the new ECB cannot communicate anything back to the ECB that created it unless the tpf_cresc or system function is used, whereby the child ECB may pass or return a value back to the parent ECB.

Use caution when using the ECB creation functions. There is a limit to the number of entries that can be active in the system and approaching this limit too closely can degrade performance.

Exit Processing

When an entry is completed, control is returned to the operating system. If the entry was created by the system function calling a DLM with a main function, or if it was created by the CRESC macro or the tpf_cresc function, the system adds the parent process to the CPU ready list so that it can resume processing.

The entry's exit status is returned to the parent process as the system function's return code. Returning from the initial call to a main function is equivalent to calling the exit function with the return value as its status parameter. For example:

    int main(void) { return 15; }

is equivalent to:

    #include <stdlib.h>
    int main(void) { exit(15); }

If the initial program that the entry ran does not contain a main function, the entry must explicitly call a process-terminating function, such as exit, abort, serrc_op, snapc, and others to return control to the operating system. The abort function forces the current ECB to exit under abnormal circumstances; no dumps are issued for invalid ECB states such as having a hold on a file address, or having a general tape opened or assigned. The serrc_op function causes a system error dump to be generated. Following the dump the ECB will be exited if the defined term SERRC_EXIT was coded as one of the parameters. The snapc function causes a system error dump to be generated. Following the dump the ECB will be exited if the defined term SNAPC_EXIT was coded as one of the parameters.

TPF Terminal Communications

Terminal Input

The user input terminal can only send messages to the system, which is then responsible for scheduling a process associated with the message. TPF application programs are activated by these input messages. Although they can send output messages in response, they do not remain active and wait for additional input messages except for TPF/APPC where the TP remains active in the same ECB throughout the life of a conversation. For non-TPF/APPC messages each new input message that arrives will cause the TPF system to create a new, independent ECB.

Therefore, non-TPF/APPC application programs must obtain all information required to process the transaction from the single input message along with data contained in the TPF file system. TPF application programs cannot operate in an interactive mode because they are not able to "listen" for additional input messages.

Programming Rule

Use the parser (IPRSE) or sscanf to obtain portions of the input message. Do not attempt to interact with the user input terminal. Design applications in such a manner that all information required to process the transaction is available in either the input message itself or in existing data records available to the process.

When a user enters a message, it is processed by the appropriate network facilities and passed to the TPF system. The message is then added to the input list (processed by the CPU loop), and becomes associated with data level 0 (D0). The standard C function sscanf has been adapted to the TPF system to access these user input messages from D0. The only difference is that these functions do not solicit terminal input, but will access the message on D0. If the user attempts to get input message lines that do not exist, a null will be returned. Likewise, if the message associated with D0 has been released or is not an input message, a null will be returned.

Output Messages

There are several different options available to C and C++ programmers who want to send an output message to the user terminal:

 I/O stream 
An I/O stream, including stdout or stderr can be opened on a special file node such as /dev/tpf.omsg/, which is associated with a device driver that writes an output message. Any of the formatted I/O functions (fprintf, printf) or text I/O functions (fputs, putc, putchar, puts) can then be used to write the output message to the I/O stream.

 routc 
Requires a routing control parameter list (RCPL) to be built and passed to it as an argument. An RCPL is associated with each input and output message, and identifies the origin, destination, and characteristics of the message. For this reason, it is recommended that an application program preserve the RCPL received at activation time and change it to an output RCPL (by swapping the origin and destination addresses).

The routc function can be used with either single line or full-screen formatted output (SNA) terminals. Also, TPF Advanced Program-to-Program Communication support allows TPF application programs to communicate with LU 6.2 applications on remote platforms. (For more information about TPF Advanced Program-to-Program Communications support, see TPF ACF/SNA Data Communications Reference.)

The TPF system also supports direction of output using a device driver. A device driver should be designed by the user to output streams to the desired terminal.

Using TPF Globals

There must be a tag name for each global field and record defined in the c$globz.h header file. This file is included by tpfglbl.h, which is required whenever you access global fields or records. Whenever changes are made to c$globz.h, you must recompile any programs that access the global tags.

There are 2 functions that you can use to access TPF globals:

 glob 
Returns the address if a field is specified and returns the address of global directory entry if record is specified.

 global 
Allows you to modify a global field or record.

The following functions are available in ISO-C only.

 glob_keypoint 
Keypoints a global field or record.

 glob_lock 
Locks and accesses a global field or record in preparation for a synchronous update.

 glob_modify 
Modifies a global field or record.

 glob_sync 
Synchronizes a global field or record across a complex.

 glob_unlock 
Unlocks a global field or record.

 glob_update 
Updates a global field or record.

The glob function provides read-only access, whereas the global function allows you to update, modify, keypoint, lock (reserve for exclusive use), unlock, copy, or synchronize global fields. These command options must be run in the correct order; for example, you cannot issue an UNLOCK before you have issued a LOCK. For more detail about these options, see TPF C/C++ Language Support User's Guide.

The global tags acted on by C functions must be defined in the c$globz.h header file or unpredictable results can occur.

Naturally, locks should not be held longer than necessary. Programs using the glob_lock function should be prepared to call glob_update, glob_sync or glob_unlock as soon as possible to prevent severe system degradation caused by other ECBs waiting for the lock.

If the global field or record can be synchronized, glob_lock must be called before calling glob_modify or glob_update.

Programs using these functions should not have any pending I/O operations outstanding because they can perform the equivalent of a waitc function.

You can find more detailed information about TPF globals as follows:

Type of Information Reference
High-level description Creating Globals for C
Installation details Customizing C/C++ Language Support
Basic TPF global concepts, terminology, overview TPF System Installation Support Reference
Global program logic TPF System Installation Support Reference.