TP8 supplies a variant of the normal GCOS8 programming environment. When you link a program to run under TP8, you have to be aware of how you intend to use the program. There are several possibilities:
Unlike normal C programs, TPRs cannot grow the data heap. They can only use what was allocated at link time, so it is necessary to specify a large enough heap when linking the run-unit.
In linking run-units to run under TP8, you need to create SYMREFs for special support modules. Normally, you do this by specifying "Use=" on the NSC command line. However, if you use LKED to build the run-unit, you create SYMREFs with the "Create_Reference" directive.
For example, to build a command TPR, you specify
Use=C$TPROGon the NSC command line or use the LKED directive
Create_Reference -SYMREF C$TPROGThe TP8 support modules implicitly reference EASEE$ENTRIES so you do not have to create an explicit reference to EASEE$ENTRIES.
In general, you can use the following command line for compiling a TPR.
nsc srcfile slib=lib slib=tp8 name=tprname use=symrefwhere:
slib=lib slib=tp8should appear in that format and order. These specify standard libraries that should be searched for routines needed in constructing the TPR. If you are linking with LKED, you can get the same effect with the statement
Library -Language c tp8since the "c" library corresponds to "lib" in the NSC StandardLibrary= option.
In many cases, it will also be appropriate to add the options
Format=rununit Update=tprlibto the NSC command line when compiling TPRs. This formats the compiled TPR as a run-unit, then uses the RUED command to put the result in a run-unit library. (In place of "tprlib", put the name of a suitable run-unit library.)
A command TPR is defined in the workstation database as the first TPR of a command. The "main()" function is defined:
main(int argc, char **argv, void *tp_storage, void *global_storage, void *transaction_storage)where "argc" and "argv" describe the parsed command line in the usual manner for C programs. Note that redirection constructs like ">outfile" and "<infile" are automatically taken care of during program set-up; they won't appear in "argv" because they are handled before "main" starts executing.
In a command TPR, the library does an explicit receive to obtain the command line that is parsed into "argc" and "argv". Therefore the TPR should NOT be configured for implicit receive in the workstation definition.
When linking a command TPR, specify "Use=C$TPROG".
A normal TPR does not receive a parsed command line. It may be called as the first TPR of a command, or called by another TPR. Since no command line processing is done, you cannot redirect "stdin" and "stdout".
The TPR mainline function is defined as:
_tpr(void *tp_storage, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6)If this TPR is the first TPR of a command, 'p1' and 'p2' will point to the global and transaction storage areas respectively. The remaining arguments are not used.
If the TPR is called by another TPR, 'p1' etc. point to the six user arguments passed by the caller to _TP_CALL_TPR or .ILINK.
If the TPR is configured for implicit receive in the workstation database, it must be linked as a normal TPR.
When linking a subroutine TPR, specify "Use=C$TPSUB".
Linking a mixed language TPR with a non-C mainline is much like linking a regular mixed language program. See "expl nsc mix".
Note that Cobol85 mainlines have no way to use use the "argc" and "argv" arguments passed to a command TPR, so it is probably best to call the mainline routine "_tpr" and link as a normal TPR. If you have Cobol handling the entry (i.e. you are not using "_tpr"), you must also specify "Use=TPR$ENTRIES".
In order to support data retention, you need special coding both in the user TPR code and in the C library.
On entry to the TPR, static and external variables may not have the initial value specified at compile time. Instead they will retain the values from the last time this copy of the TPR was invoked. The initialization values specified at compile time are only available on the first invocation of this kind of TPR. The C library does quite a bit of first time initialization, and carries a lot of state information on the stack. If you want to invoke a TPR successfully using data retained from a previous incarnation, the library must arrange that most of this initialization is not repeated, and also that the state information on the stack is preserved so that it can be restored.
You can get the library to do this by requesting special set-up and handling of the user TPR mainline. In a normal environment, when the mainline function returns, the library uses the return value as an argument to exit(), which closes all files and does other wrap-up operations. As a side effect, the writable storage is left in a state where the data areas CANNOT be reused.
When a TPR is set up for data retention, the library handles the return from the mainline function differently. As in the normal case, the value returned will be used as the exit status from the TPR, but in this case the library doesn't call "exit". Instead, the library preserves the current stack and other data, and arranges that the next time the TPR, this information is restored and normal library initialization is bypassed. This save/restore code is the same mechanism used to support "service" domains in non-TP8 environments. Since the program doesn't call "exit", you must perform clean-up actions explicitly before returning. In particular, you must:
Normally, you should not call "exit" from a TPR built for data retention. If you do call "exit", the library will perform normal exit wrap-up on its own and will also mark its copy of the data non-reusable so that the next time the TPR is invoked the library will load a fresh copy of its data.
For command TPRs using data retention, specify
Use=C$TPROG_RETOn return from the TPR main function, the library flushes TTY output, If you specified command line redirection, the redirected files are closed.
For subroutine TPRs using data retention, specify
Use=C$TPSUB_RET
Mixed language TPRs with data retention are probably best organized as a subroutine TPR. If the mainline function is not written in C, this may require the use of LKED's rename facility so that the mainline function is called "_tpr".
If a sysout file code (e.g. P*) is opened and written to, the data will not be written directly to sysout. Instead it will be passed to TP8 sysout/display processing like output from the Cobol "display" verb. This allows the data to be redirected or collected as specified by the sysout controls in the workstation database. Because of restrictions in TP8, sysout data files will default to BCD print image (media 3), instead of ASCII print image like a normal batch program.
"stderr" will be opened on file code P* which is assumed to be a sysout file code. This means, fatal library error messages and abort tracebacks will be sent to sysout.
Output written to "stdout" will be buffered and sent to the source LID using _TP_SEND_MESSAGE.
A read from "stdin" will flush current terminal output ("stdout") with EGI, and wait for input with _TP_RECEIVE_MESSAGE. I.e. this is used for immediate conversational transactions. Please see the TP8 manuals for further discussion about the about immediate conversations.
Linking a service domain to work under TP8 is very similar to linking a normal NS mode service domain. Service domains linked for use under TP8 can also be used in other environments. Service domains are able to grow the heap beyond what was allocated at link time.
In addition to the normal set up to link a service domain, specify
Use=TP$SERVICEwhen linking the run-unit.
For service domains that depend on the TP8 environment, the external "_tp_storage" is a pointer to the data in the "TP Storage" area.
Copyright © 2000, Thinkage Ltd.