TP8 - linking programs to run under TP8.

Description:

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$TPROG
on the NSC command line or use the LKED directive
Create_Reference -SYMREF C$TPROG
The TP8 support modules implicitly reference EASEE$ENTRIES so you do not have to create an explicit reference to EASEE$ENTRIES.

General Points for Building a TPR

In general, you can use the following command line for compiling a TPR.

nsc srcfile slib=lib slib=tp8 name=tprname use=symref
where:
srcfile
is the name of the file containing the source for the TPR.
tprname
is the name you want to give the TPR.
symref
is one of the following special symrefs:
C$TPROG
for command TPRs
C$TPSUB
for normal (subroutine) TPRs
TP$SERVICE
for service domains
TPR$ENTRIES
for mixed language TPRs where entry is handled by the other language
C$TPROG_RET
for command TPRs using data retention
C$TPSUB_RET
for normal TPRs using data retention
Note that the arguments
slib=lib slib=tp8
should 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 tp8
since 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=tprlib
to 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.)

Command TPRs

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".

Normal "Subroutine" TPRs

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".

Mixed Language TPRs

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".

TPRs with Data Retention

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:

  1. Close all open files.
  2. Explicitly free memory allocated with "malloc", unless you want the next invocation to inherit all the data stored in such memory.
Because "exit" is not called, "wrapup" functions registered with "atexit()" will not be executed.

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_RET
On 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".

Notes on I/O

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.

Service Domains Under TP8

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$SERVICE
when 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.

See Also:

expl nsc domain
for more information about service domains.

Copyright © 2000, Thinkage Ltd.