C H A P T E R  7

Using C Shared Objects

Sun MTP provides the ability to run online and batch CICS applications that are written in the C language. Online C programs are not directly invoked from the $KIXPROGS directory as COBOL programs are; instead, they are linked into shared objects so that the transaction server can invoke them.

This chapter contains the following topics:



Note - The terms shared object and shared library are used interchangeably.



To run batch C programs in the standard batch environment, you must use the C-ISAM interface. See Executing C Language Batch Programs.

Also, refer to the Linker and Libraries Guide, which is available on docs.sun.com. This document provides detailed information about building and maintaining shared objects.


Shared Object Model for C Applications

Sun MTP runs C application programs as shared objects. Shared objects are created using a three-step process:

1. kixclt translates C code containing EXEC CICS commands into a .c file. See Translating C Programs.

2. The C compiler compiles the .c file into an object (.o) file. See Building the Shared Object.

3. The loader creates the shared object (.so file). See Building the Shared Object.

The following discussion describes how Sun MTP uses shared objects.

1. You must define the shared objects in the Program Control Table (PCT) and Processing Program Table (PPT).

PCT

Program

Trans ID

PPT

Program

Shared Library

BCCT00

BCCT

BCCT00

bcct00

BCCT01

BC01

BCCT01

bcct01

 

 

BCCT02

bcct02


2. When the region starts, each transaction server prepares the shared objects in the PPT. Because BCCT00 and BCCT01 are entries in the PCT, their corresponding shared objects must contain one, and only one, main() function as their entry points. By default, the transaction server expects to find the symbol main as the entry point to any C program it finds in the PPT. If no main is found, a warning message indicates that no main is found in the specified program.

3. The BCCT00 and BCCT01 programs each contain a main and several other function symbols, but BCCT02 does not. BCCT02 could be an inventory of ancillary functions used by BCCT00 or BCCT01 through the C-style function call.

4. When coding each main, the only required EXEC CICS command is the EXEC CICS ADDRESS EIB(...). The kixclt translator does not issue a warning if the command is missing. However, unpredictable results can occur at run time.

5. The source file suffix .ccs is reserved for source files with a main function and EXEC CICS commands and any non-main source files with EXEC CICS commands. Ancillary functions that exist as separate compilable units with no EXEC CICS commands use the .c file suffix. These files do not need to be translated by kixclt before they are built into shared objects.

6. The source files for BCCT00, BCCT01, and BCCT02 follow the structures illustrated in the following code examples. These are translated, compiled, and then linked into shared objects.

CODE EXAMPLE 7-1 bcct00.ccs --Source File for BCCT00
#include <stdio.h>
main()
{
. . .
func1();
. . .
funca();
}
void func1()
{
EXEC CICS ...
. . .
}

CODE EXAMPLE 7-2 bcct01.ccs --Source File for BCCT01
#include <stdio.h>
main()
{
EXEC CICS ADDRESS EIB(...)
func2();
funca();
}

CODE EXAMPLE 7-3 bcct02.ccs --Source File for BCCT02
#include <stdio.h>
void funca()
{
. . .
EXEC CICS ...
. . .
EXEC CICS RETURN ...
}
void func2()
{
. . .
. . .
}


Using the CICS API in C

This section describes the unsupported API commands and explains the C equivalents for the CICS command data types. See Chapter 4 for more information about Sun MTP compatibility with CICS.

Unsupported API Commands

The full CICS API is supported in C with the following exceptions:

These commands are incompatible with the C language philosophy of structured program logic flow; they represent unstructured exception handling. Therefore, the C programs must handle their own exception processing with RESP or RESP2 following each CICS command. Use of unsupported commands results in a translator error diagnostic.



Note - HANDLE ABEND PROGRAM is supported.



Replacing Data Type Values in C

Chapter 4 describes the CICS commands and their data types. The following table shows the corresponding data types in C.

TABLE 7-1 CICS API and C Language Data Types

CICS API Data Type

C Language Data Type

data-value (halfword)

short

data-value (fullword)

int

data-value (char string)

char [n]

data-area (halfword)

short

data-area (fullword)

int

data-area (fullword)

char [n]

cvda

int

prt-ref

C pointer type reference(char * int *)

name

char string in double quotes


The following typdefs are contained in the cicstype.h header file:

cics_char_t

Character

cics_ubyte_t

One byte unsigned

cics_sshort_t

Signed short

cics_ushort_t

Unsigned short

cics_slong_t

Signed int

cics_ulong_t

Unsigned int

cics_bool_t

Boolean

cics_uxlong_t

Unsigned binary (8 bytes)

cics_sxlong_t

Signed binary (8 bytes)



Translating C Programs

C programs that contain a mixture of C language and EXEC CICS commands are identified with a .ccs extension. The kixclt utility translates these programs into a .c file. You execute kixclt providing the name of the input file and any other desired options relevant for C. For example:

$ kixclt exp_main.css

The Sun Mainframe Transaction Processing Software Reference Guide describes kixclt and its options.

CODE EXAMPLE 7-4 shows a sample .ccs file.

CODE EXAMPLE 7-4 .ccs File--Example (1 of 2)
#include <stdio.h>
/*	This is an example of a main() .ccs file with EXEC CICS
	commands embedded in it for illustrative purposes
*/
main()
{
	struct my_struct {
	                 char stuff[23];
	                 int  flen;
	                 };
	struct my_struct right_here;
	struct my_struct *my_ptr;
	struct cics_eib *prm1;
	char *prm2;
 
	my_ptr = &right_here;
	EXEC CICS ADDRESS EIB(prm1);
	prm2 = 0;
	my_ptr->flen = 8192;
 
	EXEC CICS GETMAIN
			SET     (&prm2)
			FLENGTH (my_ptr->flen)
			SHARED
			INITIMG ("|");
	/* More application code here */
	EXEC CICS FREEMAIN DATA (prm2);
	EXEC CICS RETURN
			TRANSID ("BC01");
}

During translation, the translator inserts .h header files into the output file with the appropriate function calls to kxdfhei1.

cicstype.h

CICS typedefs

cics_eib.h

EIB control structures

cics_api.h

API control function definitions


For .ccs files that contain the main() function, the translator also inserts the function call to initialize the transaction environment within the region. For .ccs files that have no main() function, the .h header files are inserted, but no initialization function call is inserted.

If your application requires, include the following header files in the .ccs file:

dfhaid.h

Attention key code definitions

dfhbmsca.h

BMS control codes


All of these header files are located in the $UNIKIX/src/CICS_structures directory.

The following code example shows the translated output of the .ccs file shown in CODE EXAMPLE 7-4. The output file has a .c extension. If errors occur during translation, a filename.err file is also generated.

CODE EXAMPLE 7-5 .c File--Example (1 of 2)
/* This is an example of a main() .ccs file with EXEC CICS
   commands embedded in it for illustrative purposes                 */
#include <stdio.h>
#include "cicstype.h"
#include "cics_eib.h"
#include "cics_api.h"
main()
 
{
		int kxdfh_entry = cics_entr("EXP_MAIN");
	struct my_struct {
				char stuff[23];
				int  flen;
				};
	struct my_struct right_here;
	struct my_struct *my_ptr;
	struct cics_eib *prm1;
	char *prm2;
 
	my_ptr = &right_here;
		/*EXEC CICS ADDRESS EIB(prm1);*/
			{
				KIX_MOV_DFHEIV0("\"\"  E                 \"   #00000016");
				kxdfhei1(&_dfheiv0, 
								&prm1);
				cics_dfhbak();
			}
 
	prm2 = 0;
	my_ptr->flen = 8192;
	/*EXEC CICS GETMAIN
			SET     (&prm2)
				FLENGTH (my_ptr->flen)
				SHARED
				INITIMG ("|");*/
			{
 
	KIX_MOV_STR(_dfheiv9,"|");
					KIX_MOV_DFHEIV0(",\"IF S                $   #00000019");
					kxdfhei1(&_dfheiv0, 
							&prm2, 
							&my_ptr->flen, 
							&_dfheiv9);
					cics_dfhbak();
					}
	/* More application code here */
	/*EXEC CICS FREEMAIN DATA    (prm2);*/
					{
					KIX_MOV_DFHEIV0(",$                    \"   #00000025");
					kxdfhei1(&_dfheiv0, 
							*&prm2);
					cics_dfhbak();
					}
 
/*EXEC CICS RETURN
			TRANSID ("BC01");*/
 
					{
					KIX_MOV_STR(_dfheiv5,"BC01");
					KIX_MOV_DFHEIV0(".( T                  $   #00000026");
					kxdfhei1(&_dfheiv0, 
							&_dfheiv5, 
							&_dfheiv99, 
							&_dfheiv99);
					cics_gobk();
					}
}

Limitations of the C Translator

The kixclt translator translates the EXEC CICS commands in a C program into inline C code. It does not, however, translate all varieties of C language constructs, so avoid embedding complex C language expressions as arguments of an EXEC CICS command, such as:

EXEC CICS . . . (command)
	LENGTH (func1() + func2() + ((num_1 < num_2) ? (short)100 : (short)200)

Instead, declare a local variable of the proper type and assign the result of the complex C expression to it outside the EXEC CICS command. Then use the variable as the argument to the EXEC CICS command. For example:

short my_var;
my_var =
 
	(short) func1() + func2() + ((num_1 < num_2) ? (short)100 :
		short(200)));
EXEC CICS . . .(command)
	LENGTH(my_var);


Setting Up Shared Objects

You must execute all C application programs from one or more previously built shared objects. See Building the Shared Object.

You must identify each C program, and the corresponding shared object in which it resides, in the PPT. Refer to the Sun Mainframe Transaction Processing Software Reference Guide.

Naming Shared Objects

Observe these requirements when naming shared objects:

For example, legal object names are:

lev1/lev2/myshobj: Maximum length for a PPT entry (note that .so is not part of the name in Sun MTP). This entry has two subdirectory levels before the shared object.

mysharedobj: Shared object with no subdirectory levels.

Opening Shared Objects

Each shared object listed in the PPT corresponds to its specified transaction. An individual shared object is not opened until its corresponding transaction is invoked. This method of opening shared objects keeps the startup overhead low, ensuring that only invoked shared objects are opened. However, once a shared object is opened, it is not unloaded (or closed) when its transaction terminates; it remains in a state of readiness for the next invocation of the same transaction.

Because the loading algorithm for application shared objects is based on the invocation of the corresponding program, any symbol reference dependencies must be declared on the link line at the time the particular shared object is built (see Link Line Examples for Building a Shared Object); otherwise those symbols will not be available for the Dynamic Loader to resolve.



Note - If your shared objects have no dependencies, you do not have to make any changes.



Another way to make dependency symbols available to the dynamic loader is to set the pre-load (P/L) field in the PPT entry to Y for the dependency shared object. When you set this field to Y, the transaction server will open all the pre-load shared objects when it starts up. If every shared object in the PPT has its pre-load field set to Y, then all shared objects are loaded when the region starts.



Note - It is unnecessary to both declare the dependencies on the link line at the time the shared object is built and set the "pre-load" flag to open the shared object at runtime.



Link Line Examples for Building a Shared Object

This link line example shows the building of a shared object named prog1.so with dependencies in another shared object called libmoreso.so.

$ ld -G -Bdynamic  -o prog1.so prog1.o -R $KIXLIB/mysos1 \
   -L $KIXLIB/mysos1 -lmoreso



Note - Refer to the man page for the ld(1) command for information about each argument.



PPT Pre-load Field

Each PPT entry has a single-character field labeled P/L. You must set this field to Y if the corresponding shared object is to be loaded when the region is started. Otherwise, set this field to N or leave it blank.


Building the Shared Object


procedure icon  To Build a Shared Object

1. Using the .c output file created by the kixclt translator, create the shared object:

a. Compile the .c file with the C compiler to produce a named .o file.

b. Invoke the loader to process the .o file and produce the shared object file (.so extension).

2. Move the shared object to the desired directory.

The following commands translate, compile, and create the shared object. $KIXLIB points to a single shared object directory.

$ cc -Bdynamic -Kpic -c -Xt -I $UNIKIX/src/CICS_structures \
	-o exp_main.o exp_main.c
$ ld -G -o exp_main.so exp_main.o
$ mv exp_main.so $KIXLIB

The $UNIKIX/test/primer/C directory contains a shell script build_ACCT.sh, which builds the sample ACCT application. You can use it as a model for compiling applications using a shell script.


Assembling BMS Maps

The command line functionality of the kixbms utility is the same in the C environment as it is in the COBOL environment. However, the output is different. To convert a .bms source file, use this format:

$ kixbms -c TSTMNU.bms

The output from this command is determined by the LANG option in the TSTMNU.bms source file. If LANG=C, kixbms creates:

All the .h output from kixbms is in C structure format, which means that all the map definitions are aligned. If you want to use the same maps and mapsets for both COBOL and C application programs, you must rebuild all the COBOL copybooks that describe the maps by using the -a (alignment) option on the kixbms command line. Refer to the Sun Mainframe Transaction Processing Software Reference Guide for information about all the kixbms options.

When a C header file is created, the output file name is always uppercase with a lowercase .h extension. This header file name must be included in the .ccs source file for the program that is using BMS maps.

The following example is a BMS input file. Note the STORAGE=AUTO statement in the second line.

CODE EXAMPLE 7-6 BMS Source File
		TITLE 'FILEA - MAP FOR OPERATOR INSTRUCTIONS - C'
TSTMNU  DFHMSD MODE=INOUT,CTRL=(FREEKB,FRSET),STORAGE=AUTO,           *
               LANG=C,TIOAPFX=YES,EXTATT=MAPONLY,COLOR=BLUE
MENU    DFHMDI SIZE=(12,40)
        DFHMDF POS=(1,10),LENGTH=21,INITIAL='OPERATOR INSTRUCTIONS',  *
               HILIGHT=UNDERLINE
        DFHMDF POS=(1,32),LENGTH=1
        DFHMDF POS=(3,1),LENGTH=29,INITIAL='OPERATOR INSTR - ENTER MEN*
               U'
        DFHMDF POS=(4,1),LENGTH=38,INITIAL='FILE INQUIRY   - ENTER INQ*
               Y AND NUMBER'
        DFHMDF POS=(5,1),LENGTH=38,INITIAL='FILE BROWSE    - ENTER BRW*
               S AND NUMBER'
        DFHMDF POS=(6,1),LENGTH=38,INITIAL='FILE ADD       - ENTER ADD*
               S AND NUMBER'
        DFHMDF POS=(7,1),LENGTH=38,INITIAL='FILE UPDATE    - ENTER UPD*
               T AND NUMBER' 
MSG     DFHMDF POS=(11,1),LENGTH=39,INITIAL='PRESS CLEAR TO EXIT'
        DFHMDF POS=(12,1),LENGTH=18,INITIAL='ENTER TRANSACTION:'
        DFHMDF POS=(12,20),LENGTH=4,ATTRB=IC,COLOR=GREEN,             *
               HILIGHT=REVERSE
        DFHMDF POS=(12,25),LENGTH=6,INITIAL='NUMBER'
KEY     DFHMDF POS=(12,32),LENGTH=6,ATTRB=NUM,COLOR=GREEN,            *
               HILIGHT=REVERSE
        DFHMDF POS=(12,39),LENGTH=1
        DFHMSD TYPE=FINAL

CODE EXAMPLE 7-7 shows the .h output file after running kixbms. The use of the STORAGE=AUTO statement results in the union statement in the last line, which is an instantiation of the structure.

CODE EXAMPLE 7-7 .h Output File From kixbms --Instantiation Example (1 of 2)
union menuu {  
	struct {  
			char  dfhms1[12];
			short msgl;
			char  msgf;
			char  msgi[39];
			short keyl;
			char  keyf;
			char  keyi[6];
			}     menui;
	struct {  
			char  dfhms1[12];
			short dfhms2;
			char  msga;
			char  msgo[39];
			short dfhms3;
			char  keya;
			char  keyo[6];
			}     menuo;
			}     ;
union menuu menu;

If the STORAGE=AUTO statement is omitted from the BMS source file, the last line in the .h output file is a pointer to the structure, as shown in CODE EXAMPLE 7-8.

CODE EXAMPLE 7-8 .h Output File From kixbms --Pointer Example
union menuu {  
	struct {  
			char  dfhms1[12];
			short msgl;
			char  msgf;
			char  msgi[39];
			short keyl;
			char  keyf;
			char  keyi[6];
			}     menui;
	struct {  
			char  dfhms1[12];
			short dfhms2;
			char  msga;
			char  msgo[39];
			short dfhms3;
			char  keya;
			char  keyo[6];
			}     menuo;
			}     ;
} *bmsmapbr;


Invoking C Programs

Two arguments are normally passed to the C program when it is started: argc and argv. However CICS programs expect to run in a special environment and to be loaded by the transaction server. Therefore, each C program in a region is started as if it had only one command line argument: the Transaction ID. The result is that argc is set to 1 and argv[0] contains the transaction code.

The address of the EIB block is not passed into a starting C program nor is the COMMAREA address. Both of these addresses, if needed by the application program, are obtained using the EXEC CICS ADDRESS EIB and the EXEC CICS ADDRESS COMMAREA statements, respectively.

The function call to initialize the Sun MTP transaction environment does acquire the EIB pointer into a variable called tcb_eib_ptr (within cics_api.h), which is usable by the application code. Therefore, it is not necessary to reacquire it using EXEC CICS ADDRESS EIB. However, do so for the application's own EIB pointer, using a second variable provided in cics_api.h called dfheiptr.


Using CEMT With Shared Objects

The options to CEMT SET and CEMT INQ allow you to dynamically change the shared object for a program and to inquire about the name of the current object. See Running a Different Version of the Same Shared Object.

The LIBRARY option of the CEMT SET PROGRAM transaction enables you to dynamically change a program's shared object while Sun MTP is running.

Format:

CEMT S[ET] PROG[RAM] prog-name LIB[RARY] lib-name PROG[RAM] prog-name	LIB[RARY] blankreset

where:

prog-name

Name of the program; maximum 8 characters.

lib-name

Name of the shared object; maximum 16 lowercase characters.

blankreset

Remove the designated program from shared library processing by setting the PPT shared object field for the program to blanks.




Note - You must spell blankreset exactly as shown or it is used as a new shared object name.



After you execute the CEMT command, you must execute a CINI transaction to initialize the new shared object and internal tables.

Use the LIBRARY option to the CEMT INQ PROGRAM transaction to inquire for the name of the current shared object.

Format:

CEMT I[NQ] PROG[RAM] prog-name LIB[RARY]

prog-name is the name of the program, a maximum of eight characters.

If the program has a shared object, the following message is displayed:

KIX1584I CEMT transaction terminated ShrLib = lib-name

If the program does not have a shared object, the following message is displayed:

KIX1584I CEMT transaction terminated ShrLib = NoSharedLibPrsnt

Running a Different Version of the Same Shared Object

You can load a new version of a shared object without having to restart the Sun MTP region. For example, suppose your application uses a shared library named prog_pay1.so, which is defined in the PPT as dir1/prog_pay1. During execution, you observe that prog_pay1.so does not behave as expected, so you compile and rebuild a new version of prog_pay1.so. Rather than recycling the region to pick up the new version, save the new version of the shared object in a different directory, dir2.

To run the new shared object, use the following transactions:

CEMT SET PROGRAM MY_PROG1 LIBRARY dir2/prog_pay1

This transaction changes the shared memory PPT to point to the new directory where the shared object is located. This change is valid for the life of the region. The path name can be up to 16 characters long and is relative to the $KIXLIB or $KIXSYS directories. Refer to the Sun Mainframe Transaction Processing Software Reference Guide for information about defining shared objects in the PPT.

The following transaction causes the transaction processors to reopen the shared objects and make them available:

CEMT SET PROGRAM MY_PROG1 LIBRARY NEWCOPY



Note - Do not simply recompile and rebuild the shared object and overwrite the previous version. Unpredictable errors might occur.