標準/拡張機能 | C/C++ | 依存項目 |
---|---|---|
Language Environment | C |
#include <stdlib.h>
void (*fetch(const char *name))();
name で指定されたロード・モジュールをメモリーへ動的にロードします。その後は、z/OS® XL C プログラムから そのロード・モジュールを呼び出すことができます。フェッチ可能なロード・モジュールをロード・モジュール・ライブラリー 内で識別するための名前または別名を、fetch() ライブラリー関数呼び出し の中に指定する必要があります。
ユーザーのネーム・スペースが侵害されるのを回避するため、この非標準関数には 2 つの名前があります。外部エントリー・ポイント名である一方の名前には、接頭部として 2 つの 下線文字が付いていて、もう一方の名前には付いていません。接頭部下線文字が付いていない名前は、LANGLVL(EXTENDED) を使用する場合にのみ表示されます。
この関数を使用するには、その外部エントリー・ポイント名 を使用する関数 (つまり、2 つの下線文字で始まる名前) を 呼び出すか、または LANGLVL(EXTENDED) でコンパイルする必要があります。LANGLVL(EXTENDED) を使用すると、ヘッダー内の関連情報もすべて表示されます。
main() が含まれているモジュールをフェッチすることはできません。それをフェッチした場合、fetch() は、使用できないポインターを 戻します。そのポインターを使用すると、未定義の動作を行う結果となります。このような種類のモジュールを呼び出すには、system() ライブラリー 関数を使用してください。代わりに、モジュールの作成時に、リンケージが z/OS XL C で提供されるようにエントリー・ポイントをリセットすることもできます。
再入不能なモジュールが複数回フェッチされた場合は、逆順にそれらを解放しなければなりません。そうでない場合は、ロード・モジュールはすぐに削除されます。
C および C++ で作成 されたモジュールをフェッチすることができます。C モジュールでは、フェッチされるモジュールのソースは、一般に、#pragma linkage(…, fetchable) を含みます (例外は以下で説明します)。C++ モジュールをフェッチ するためには、そのルーチンを extern “C” であると宣言する必要 があり、また、#pragma linkage(…, fetchable) ディレクティブ で宣言する必要があります。#pragma linkage に必要な情報については、fetchep() - 書き込み可能静的変数の共用も参照してください。
XPLINK プログラムは、非 XPLINK プログラムをフェッチすることができ、その逆も可能です。fetch() によって戻された関数記述子には、必要に応じて、スタック・スワップおよびパラメーター・リストの型変換をサポートするグルー・コードが含まれます。XPLINK リンケージ境界を横断しないフェッチ・ルーチンへの呼び出しでは、グルー・コードのオーバーヘッドは発生しません。
フェッチされたモジュールが DLL としてコンパイルされる場合は、別の DLL モジュールから変数や関数をインポートすることができますが、変数や関数を エクスポートすることはできません。
ネストされたフェッチはサポートされています。つまり、フェッチされたモジュールは、fetch() ライブラリー関数を 呼び出して、フェッチ可能な別のモジュールを動的にロードすることも できます。
多重フェッチもサポートされています。モジュールの複数回のフェッチの結果、個々のフェッチ・ポインターを作成します。モジュールが「再入可能」のマークが付けられている場合は、多重フェッチでは、モジュールをストレージに再ロードしません。 MVS™ では、ロードの時間を節約するために、再入可能モジュールを、拡張リンク・パック域またはリンク・パック域 (ELPA/LPA) に置くことができます。再入可能なモジュールの複数コピーはストレージに入れられませんが、フェッチごとに、別のポインターを戻します。モジュールが再入可能でない場合、多重フェッチでは、ストレージへの複数回のロードが行われます。再入不能モジュールを複数回 fetch() した場合、すべての フェッチ・インスタンスが解放された後でなければ、release() によって そのモジュールが削除されないことがあるので、注意してください。また、再入不能なモジュールの複数回のロードは、ストレージの点で非常にコ ストがかかることを覚えておいてください。
書き込み可能静的変数は、一般にプロセスの範囲内で有効です。例外は、スレッドがフェッチされたモジュールを呼び出すとき、書き込み可能静的変数はそのスレッドに対してのみ変更されます。つまり、スレッドの範囲でのみ有効です。
MVS では、フェッチ可能 (または動的にロードされる) モジュールは、リンク・エディットされ、標準システム検索を使用してアクセス 可能でなければなりません。MVS は再入不能、逐次再使用可能、および再入可能のモジュールの取り出しをサポートしています。
しかし POSIX では、フェッチ可能で、動的にロードされたモジュールは HFS (階層ファイル・システム) には入れられません。 また、POSIX および XPG4 外部変数は伝搬されることにも注意してください。外部変数についての詳細は、「z/OS XL C/C++ プログラミング・ガイド」を参照してください。
ユーザーのプログラムが本来再入可能であれば、各再入可能モジュールは 、書き込み可能静的変数の別々のコピーを持ちます。以下のステップに従って、書き込み可能静的変数を持つ再入可能モジュールを フェッチすることができます。
共用書き込み可能静的変数を使用して一連の関数を動的にフェッチする ためには、ライブラリー関数の fetchep() を使用できます。詳しくは、fetchep() - 書き込み可能静的変数の共用を参照してください。
フェッチされるモジュールと fetch() ライブラリー関数を呼び出す モジュールの両方が再入可能になることができます。
フェッチされるモジュールで、#pragma linkage(…, FETCHABLE) ディレクティブを 指定しないでモジュールをフェッチすることができます。その場合、フェッチ・ポインターを使用すると、そのモジュールのエントリー・ポ イントを呼び出す結果となります。モジュールをリンクするとき、エントリー・ポイントをリセットしなければな りません。さらに、書き込み可能静的変数を一切持つことはできません。
また、書き込み可能静的変数を含む再入可能 C モジュールをフェッチするには、フェッチされるモジュールで #pragma linkage(… FETCHABLE) プリプロセッサー指示を使用する必要があります。
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 */
モジュールがフェッチされた後、フェッチされた関数を呼び出すと、言語間呼び出しを行うのと同様になります。
fetch() は、AMODE 切り替えもサポートします。つまり、この関数が呼び出されると、AMODE が切り替えられ、戻り時に AMODE が復元されます。フェッチされたモジュールが AMODE=24 で呼び出されたことがわかる と、基準以上の変数またはライブラリーへアクセスしようとします。
リンクに関する考慮事項: フェッチされる関数をリンクする際には、必要なライブラリーでリンクし、以下のディレクティブを含まない場合は、フェッチ中の関数として、エントリー・ポイン トを指定しなければなりません。#pragma linkage(…, FETCHABLE)
main() z/OS C 関数をリンクするとき、フェッチしようとする 関数を使用するために必要なライブラリーを指定する必要があります。例えば、COBOL 関数をフェッチしようとする場合は、COBOL ライブラリーを指定 します。この要件は、Language Environment には 該当しません。
main() を実行するときは、フェッチする関数だけではなく、main() の ために必要となるランタイム・ライブラリーも指定してください。この要件は、Language Environment には 該当しません。
正常に実行された場合、fetch() は、フェッチされたロード・モジュールへのエントリー・ポイントを呼び出す、スタブへのポインターを戻します。
ロードが失敗した場合、fetch() は NULL を戻して、errno を以下のいずれかの値に設定する場合があります。
C での fetch() 関数の使用例: 以下の例では、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
C++ での fetch() の代替例: この例は、fetch() の代わりとして DLL を使用する場合の DLL の使い方を示します。 ここで、myfunc() は DLL を使用して動的にロードされる関数で 、main() は 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 );
}
次の例では、C++ プログラムが C DLL モジュール内の関数を動的に呼び出して、別の C モジュールをフェッチする方法を示します。
// 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 );
}
以下の例では、別の関数をフェッチする代わりに、C 関数を静的に呼び出す方 法を示しています。ここで、myfunc() はフェッチされる関数で、fetcher() は myfunc() をフェッチする C 関数で、main() は 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 );
}
DLL のフェッチや使用は機能的には互換性がありますが、微妙な違いがあります。静的変数やグローバル変数の新しいコピーは、フェッチされるモジュールを毎回割り振 りますが、同じモジュールの DLL ロードは毎回は行われません。
以下の例では、モジュールが複数回フェッチされるとき、静的変数やグローバル変数の新しいコピーが割り振られる様子を示します。
/* 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
以下の例では、同じモジュールの DLL の複数回ロードに対しては、静的変数やグローバル変 数の新しいコピーが割り振られない様子を示します。
// 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