Standards / Extensions | C or C++ | Dependencies |
---|---|---|
Language Environment | C |
#include <stdlib.h>
void (*fetch(const char *name))();
Dynamically loads the load module specified by name into memory. The load module can then be invoked from a z/OS® XL C program. The name or the alias by which the fetchable load module is identified in the load module library must appear in a fetch() library function call.
To avoid infringing on the user's name space, this nonstandard function has two names. One name, the external entry point name, is prefixed with two underscore characters, and the other name is not. The name without the prefix underscore characters is exposed only when you use LANGLVL(EXTENDED).
To use this function, you must either invoke the function using its external entry point name (that is, the name that begins with two underscore characters __fetch()) or compile with LANGLVL(EXTENDED). When you use LANGLVL(EXTENDED), any relevant information in the header is also exposed.
You cannot fetch a module that contains a main(). If you do, fetch() will not return a usable pointer. Use of the pointer will result in undefined behavior. To call these types of modules, use the system() library function. Alternatively, when creating the module, you can reset the entry point so that the linkage is provided by z/OS XL C.
When non-reentrant modules have been fetched multiple times, you should release them in the reverse order; otherwise the load modules may not be deleted immediately.
You can fetch modules written in C and C++. For C modules, the source of the fetched module must, in general, contain #pragma linkage(…, fetchable) (the exception is described below). To fetch a C++ module, the routine must be declared extern “C”, and must be declared in a #pragma linkage(…, fetchable) directive. See also fetchep() — Share writable static for more information about the need for #pragma linkage.
XPLINK programs can fetch non-XPLINK programs, and vice versa. The function descriptor returned by fetch() will contain glue code to support a stack swap and parameter list conversion if necessary. Calls to a fetched routine that do not cross an XPLINK linkage boundary will not incur any glue code overhead.
If the fetched module is compiled as a DLL it can import variables and functions from other DLL modules, but it cannot export variables or functions.
Nested fetching is supported. That is, a fetched module can also invoke the fetch() library function to dynamically load a separate fetchable module.
Multiple fetching is also supported. Fetching a module more than once will result in separate fetch pointers. If the module is marked “reentrant”, multiple fetches will not reload the module into storage. Under MVS™, you can place the reentrant module into the Extended Link Pack Area or the Link Pack Area (ELPA/LPA) to save time on the load. Although multiple copies of the reentrant module are not brought into storage, each fetch returns a separate pointer. If a module is not reentrant, multiple fetches cause multiple loads into storage. Be aware that if you fetch() a non-reentrant module multiple times, the module may not get deleted by release() until all fetch instances have been released. Also, you should keep in mind that multiple loads of a non-reentrant module can be costly in terms of storage.
Writable statics are, in general, process-scoped. The exception is that, when a thread calls a fetched module, the writable statics are changed for that thread only, that is, thread-scoped.
Under MVS, fetchable (or dynamically loaded) modules must be link-edited and accessible using the standard system search. MVS supports fetching of non-reentrant, serially reusable, and reentrant modules.
Under POSIX, however, the fetchable, dynamically loaded modules cannot be in the HFS (Hierarchical File System). Note also, that the POSIX and XPG4 external variables are propagated. Refer to z/OS XL C/C++ Programming Guide for more information on external variables.
Unless your program is naturally reentrant, each reentrant module has a different copy of writable static. Follow these steps to allow the fetching of your reentrant module that has writable static:
To dynamically fetch a set of functions with shared writable static, you can use the library function fetchep(). See fetchep() — Share writable static for more details.
Both the module being fetched and the module invoking the fetch() library function can be reentrant.
You can fetch modules without specifying the directive, #pragma linkage(…, FETCHABLE), in the fetched module. If you do, then using the fetch pointer will result in calling the entry point for that module. When you link the module, you must reset the entry point. In addition, you cannot have any writable static.
It follows that fetching a reentrant C module containing writable statics requires that you use the #pragma linkage(… FETCHABLE) preprocessor directive in the fetched module.
typedef int COBOL_FUNC ();
#pragma linkage (COBOL_FUNC, COBOL)
⋮
COBOL_FUNC * fetch_ptr;
fetch_ptr = (COBOL_FUNC *) fetch(module); /* loads fetched module */
fetch_ptr(args); /* sets up the proper linkage for the call */
Once the module is fetched, calling the fetched function is similar to making an interlanguage call.
fetch() also supports AMODE switching: when the function call is made, AMODE will be switched; upon return, the AMODE will be restored. Beware of calling fetched modules with AMODE=24 that try to access variables or the library above the line.
Link considerations: When linking the function to be fetched, you must link in the necessary libraries and specify the entry point as the function you are fetching unless you have included this directive: #pragma linkage(…, FETCHABLE).
When linking the main() z/OS C function, you must specify the necessary libraries to use the functions you are fetching. For example, if you are fetching a COBOL function, specify the COBOL library. This requirement does not apply to Language Environment.
When running main(), specify the runtime libraries you will need for main(), as well as the functions you will fetch. This requirement does not apply to Language Environment.
If successful, fetch() returns a pointer to a stub that will call the entry point to the fetched load module.
If the load fails, fetch() returns NULL and may set errno to one of the following values:
Examples of using the fetch() function with C: The following example demonstrates how to compile, link, and run a program that fetches a function in another object module that contains the directive: pragma linkage(…., FETCHABLE).
#include <stdio.h>
#include <stdlib.h>
typedef int (*funcPtr)(); /* pointer to a function returning an int */
int main(void)
{
int result;
funcPtr add;
printf("fetch module\n");
add = (funcPtr) fetch("f1a"); /* load module F1A */
if (add == NULL) {
printf("ERROR: fetch failed\n");
}
else {
printf("execute fetched module\n");
result = (*add)(1,2); /* execute module F1A */
printf("1 + 2 == %d\n", result);
}
}
#pragma linkage(func1, fetchable)
int func1(int a, int b)
{
printf("in fetched module\n");
return(a+b);
}
>
//F1A EXEC EDCC,INFILE='userid.TEST.SOURCE(F1A)'
// OUTFILE='userid.TEST.OBJ(F1A),DISP=SHR',
// CPARM='NOSEQ,NOMARGIN,RENT'
//F1B EXEC EDCPL,INFILE='userid.TEST.OBJ(F1A)'
// OUTFILE='userid.TEST.LOAD(F1A),DISP=SHR'
//F1 EXEC EDCCLG,INFILE='userid.TEST.SOURCE(F1)'
//GO.STEPLIB DD
// DD DSN=userid.TEST.LOAD,DISP=SHR
/* cob1 */
#include <stdlib.h>
#include <stdio.h>
typedef void funcV(); /* function returning void */
#pragma linkage(funcV, COBOL) /* establish Cobol linkage */
int main(void)
{
int var1 = 1;
int var2 = 2;
funcV *add;
printf("fetch module\n");
add = (funcV *) fetch("cob1a"); /* load module COB1A */
if (add == NULL)
{
printf("ERROR: fetch failed\n");
}
else
{
printf("execute fetched module\n");
(*add)(&var1, &var2); /* execute module COB1A */
printf("1 + 2 == %d\n", var1);
}
}
IDENTIFICATION DIVISION.
PROGRAM-ID. COB1A.
****************************************************************
* This subroutine receives 2 integer parameters. *
* The first is added to the second and the result is stored *
* back into the first. *
****************************************************************
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
LINKAGE SECTION.
01 VAR1 PIC S9(9) COMP.
01 VAR2 PIC S9(9) COMP.
****************************************************************
* PROCEDURE DIVISION *
****************************************************************
PROCEDURE DIVISION USING VAR1 VAR2.
*
* ADD VAR2 TO VAR1 PLACING THE RESULT IN VAR1.
*
COMPUTE VAR1 = VAR1 + VAR2.
GOBACK.
//*==================================================================
//COBCL PROC CREGSIZ='2048K',
// INFILE=,
// OUTFILE='&&GSET(GO),DISP=(MOD,PASS),UNIT=VIO,SPACE=(512,(50,20,1))'
//*
//*------------------------------------------------------------------
//* COBOL Compile Step
//*------------------------------------------------------------------
//COBCOMP EXEC PGM=IGYCRCTL,REGION=&CREGSIZ;
//STEPLIB DD DSNAME=IGY.V1R3M0.SIGYCOMP,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSIN DD DSNAME=&INFILE,DISP=SHR
//SYSLIN DD DSNAME=&&LOADSET,UNIT=SYSDA,
// DISP=(MOD,PASS),SPACE=(TRK,(3,3)),
// DCB=(BLKSIZE=3200)
//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT2 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT3 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT4 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT5 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT6 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT7 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//*
//*------------------------------------------------------------------
//* COBOL Link-Edit Step
//*------------------------------------------------------------------
//COBLINK EXEC PGM=HEWL,COND=(8,LT,COBCOMP),REGION=1024K
//SYSLIB DD DSNAME=CEE.V1R3M0.SCEELKED,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSLIN DD DSNAME=&&LOADSET,DISP=(OLD,DELETE)
// DD DDNAME=SYSIN
//SYSLMOD DD DSNAME=&OUTFILE;
//SYSUT1 DD UNIT=SYSDA,SPACE=(TRK,(10,10))
// PEND
//*
//*==================================================================
//* Compile and Link-Edit COBOL program COB1A
//*------------------------------------------------------------------
//COB1A EXEC COBCL,
// INFILE='userid.TEST.SOURCE(COB1A)',
// OUTFILE='userid.TEST.LOAD(COB1A),DISP=SHR'
//COBLINK.SYSIN DD *
ENTRY COB1A
/*
//*
//*------------------------------------------------------------------
//* Compile and Link-Edit C program COB1
//*------------------------------------------------------------------
//COB1 EXEC EDCCLG,
// INFILE='userid.TEST.SOURCE(COB1)',
// CPARM='OPT(0) NOSEQ NOMAR'
//GO.STEPLIB DD
// DD DSNAME=userid.TEST.LOAD,DISP=SHR
Examples of alternatives to fetch() under C++: This example shows how to use DLL as an alternative to fetch(). Here, myfunc() is the function to be dynamically loaded using DLL, and main() invokes DLL.
⁄⁄ CELEBF52-part 1 of 2-other file is CELEBF53.
⁄⁄ This example shows how to use DLL as an alternative to fetch().
⁄⁄ C++ program that invokes myfunc using DLL
#include <stdlib.h>
#include <stdio.h>
#include <dll.h>
extern "C" { ⁄⁄ needed to indicate C linkage
typedef int (*funcPtr)(); ⁄⁄ pointer to a function returning an int
}
int main (void)
{
dllhandle *dllh;
funcPtr fptr;
if ((dllh = dllload( "celebf53" )) == NULL) {
perror( "failed to load celebf53" );
exit( -1 );
}
if ((fptr = (funcPtr) dllqueryfn( dllh, "myfunc" )) == NULL) {
perror( "failed to retrieve myfunc" );
exit( -2 );
}
if ( fptr() != 0 ) {
perror( "failed to execute myfunc" );
exit( -3 );
}
if ( dllfree( dllh ) != 0 ) {
perror( "failed to free celebf53" );
exit( -4 );
}
return( 0 );
}
⁄* CELEBF53-part 2 of 2-other file is CELEBF52.
This example shows how to use DLL as an alternative to fetch().
*⁄
⁄*
C function dynamically loaded using DLL
*⁄
#include <stdio.h>
int myfunc (void)
{
printf( "Hello world\n" );
return( 0 );
}
The following example shows how a C++ program can dynamically call a function in a C DLL module, to fetch other C modules.
// CELEBF54-part 1 of 3-other files are CELEBF55, CELEBF56.
// This example shows how a C++ program can dynamically call a function
// in a C DLL module, to fetch other C modules
// C++ program that dynamically calls a function in a C DLL module
#include <stdio.h>
#include <stdlib.h>
#include <dll.h>
#include <iostream.h>
extern "C" { // needed to indicate C linkage
typedef int (*funcPtr)(); // pointer to a function returning an int
}
int main (void)
{
dllhandle *dllh;
funcPtr fptr;
if ((dllh = dllload( "mydll" )) == NULL) {
perror( "failed to load mydll" );
exit( -1 );
}
if ((fptr = (funcPtr) dllqueryfn( dllh, "fwrap" )) == NULL) {
perror( "failed to retrieve fwrap" );
exit( -2 );
}
if ( fptr() != 0 ) {
perror( "failed to execute fwrap" );
exit( -3 );
}
if ( dllfree( dllh ) != 0 ) {
perror( "failed to free mydll" );
exit( -4 );
}
return( 0 );
}
/* CELEBF55-part 2 of 3-other files are CELEBF54, CELEBF56.
This example shows how a C++ program can dynamically call a function
in a C DLL module, to fetch other C modules
fwrap function used in a DLL module-it fetches mymod, which
contains myfunc
*/
#include <stdio.h>
#include <stdlib.h>
typedef int (*funcPtr)(); /* pointer to a function returning an int */
int fwrap (void)
{
funcPtr fptr;
if ((fptr = (funcPtr) fetch( "mymod" )) == NULL) {
perror( "failed to fetch mymod" );
return( -1 );
}
else
return(fptr());
}
/* CELEBF56-part 3 of 3-other files are CELEBF54, CELEBF55.
This example shows how a C++ program can dynamically call a function
in a C DLL module, to fetch other C modules
*/
/* C function to be fetched */
#include <stdio.h>
#pragma linkage(myfunc, fetchable)
int myfunc (void)
{
printf( "in fetched module\n" );
return( 0 );
}
The following example shows how to statically call a C function that in turn fetches other functions. Here, myfunc() is the function to be fetched, fetcher() is a C function that fetches myfunc(), and main() is a function that statically calls fetcher().
// CELEBF57-part 1 of 3-other files are CELEBF58, CELEBF59.
// This example shows how to statically call a C function that
// fetches other functions.
// C++ statically calling a C program that uses fetch()
#include <iostream.h>
extern "C" { // needed to indicate C linkage
int fetcher (void);
}
int main (void)
{
cout << "The fetcher says: ";
fetcher();
cout << "and returns";
return( 0 );
}
/* CELEBF58-part 2 of 3-other files are CELEBF57, CELEBF59.
This example shows how to statically call a C function that fetches
other functions.
*/
/*
C function that fetches mymod which contains myfunc
*/
#include <stdio.h>
#include <stdlib.h>
typedef int (*funcPtr)(); /* pointer to a function returning an int */
int fetcher (void)
{
funcPtr fptr;
if ((fptr = (funcPtr) fetch( "mymod" )) == NULL) {
perror( "failed to fetch mymod" );
return( -1 );
}
else {
fptr(); /* invoke fetched function */
return( 0 );
}
}
/* CELEBF59-part 3 of 3-other files are CELEBF57, CELEBF58.
This example shows how to statically call a C function that fetches
other functions.
*/
/* C function to be fetched */
#include <stdio.h>
#pragma linkage(myfunc, fetchable)
int myfunc (void)
{
printf( "Hello world " );
return( 0 );
}
Although fetching and using DLL are functionally comparable, there is one subtle difference. Fresh copies of static and global variables are allocated each time a module is fetched, but not each time a DLL load of the same module is done.
The following example shows that, when a module is fetched multiple times, fresh copies of static and global variables are allocated.
/* CELEBF60-part 1 of 2-other file is CELEBF61.
This example shows how copies of variables are allocated when multiple
fetches are done.
*/
/*
C program fetching mymod multiple times--mymod contains myfunc.
*/
#include <stdio.h>
#include <stdlib.h>
typedef int (*funcPtr)(int); /*pointer to a function returning an int*/
int main (void)
{
funcPtr fptr1, fptr2;
if ((fptr1 = (funcPtr) fetch( "mymod" )) == NULL) {
perror( "failed to fetch mymod" );
return( -1 );
}
if ( fptr1(100) != 0 ) {
perror( "failed to execute myfunc" );
exit( -2 );
}
if ((fptr2 = (funcPtr) fetch( "mymod" )) == NULL) {
perror( "failed to fetch mymod" );
return( -3 );
}
if ( fptr2(100) != 0 ) {
perror( "failed to execute myfunc" );
exit( -4 );
}
return( 0 );
}
/* CELEBF61-part 2 of 2-other file is CELEBF60.
This example shows how copies of variables are allocated when multiple
fetches are done.
*/
/* C module mymod */
#include <stdio.h>
#pragma linkage(myfunc, fetchable)
int globvar = 5;
int myfunc (int x)
{
globvar += x;
printf( "%d\n", globvar );
return( 0 );
}
105
105
The following example shows that fresh copies of static and global variables are not allocated for multiple DLL loads of the same module.
// CELEBF62-part 1 of 2-other file is CELEBF63.
// This example shows how copies of variables are allocated when
// multiple DLL loads are done.
// C++ program doing multiple DLL loads of the same module
#include <stdlib.h>
#include <stdio.h>
#include <dll.h>
extern "C" { //needed to indicate C linkage
typedef int (*funcPtr)(int); //pointer to a function returning an int
}
int main (void)
{
dllhandle *dllh1, *dllh2;
funcPtr fptr;
if ((dllh1 = dllload( "mydll" )) == NULL) {
perror( "failed to load mydll" );
exit( -1 );
}
if ((fptr = (funcPtr) dllqueryfn( dllh1, "myfunc" )) == NULL) {
perror( "failed to retrieve myfunc" );
exit( -2 );
}
if ( fptr(100) != 0 ) {
perror( "failed to execute myfunc" );
exit( -3 );
}
if ((dllh2 = dllload( "mydll" )) == NULL) {
perror( "failed to load mydll" );
exit( -4 );
}
if ((fptr = (funcPtr) dllqueryfn( dllh2, "myfunc" )) == NULL) {
perror( "failed to retrieve myfunc" );
exit( -5 );
}
if ( fptr(100) != 0 ) {
perror( "failed to execute myfunc" );
exit( -6 );
}
if ( dllfree( dllh1 ) != 0 ) {
perror( "failed to free mydll" );
exit( -7 );
}
return( 0 );
}
/* CELEBF63-part 2 of 2-other file is CELEBF62.
This example shows how copies of variables are allocated when multiple
DLL loads are done.
*/
/* C function invoked using DLL */
#include <stdio.h>
#include <stdlib.h>
int globvar = 5;
int myfunc (int);
int myfunc (int x)
{
globvar += x;
printf( "%d\n", globvar );
return( 0 );
}
105
205