InterSystems コールアウト・ライブラリの作成
InterSystems コールアウト・ライブラリは、カスタム・コールアウト関数、および Caché がそれらを使用できるようにする使用可能化コードを含む共有ライブラリです。この章では、コールアウト・ライブラリを作成して実行時にアクセスする方法を説明します。
以下の項目について説明します。
-
コールアウト・ライブラリの概要 — コールアウト・ライブラリの作成およびアクセス方法を説明します。
-
ZFEntry リンク・オプション — 関数引数が渡される方法を決定するリンク・オプションの詳細を説明します。
-
コールアウト・ライブラリ Runup 関数と Rundown 関数 — コールアウト・ライブラリがロードまたはアンロードされるときに自動的に呼び出される 2 つのオプション関数について説明します。
-
トラブルシューティング — 避けるべきコーディング作業について説明します。
このドキュメントでは、共有ライブラリという用語は、動的にリンクされたファイル (Windows の DLL ファイル、UNIX® および関連オペレーティング・システムの SO ファイル、または OpenVMS の共有可能イメージ・ファイル) を示します。コールアウト・ライブラリは、コールアウト・ゲートウェイへのフックを含む共有ライブラリであり、多様な $ZF 関数が実行時にこれをロードし、アクセスできるようにします。
コールアウト・ライブラリの概要
ObjectScript コードからコールアウト・ライブラリにアクセスするには複数の方法がありますが、一般的には、ライブラリ名、関数名、および必要な引数を指定するのが主な方法です (“コールアウト・ライブラリ関数の呼び出し” を参照してください)。例えば、以下のコードでは、簡単なコールアウト・ライブラリ関数を呼び出します。
以下の ObjectScript コードは、ターミナルで実行されます。これは、simplecallout.dll という名前のコールアウト・ライブラリをロードし、2 つの整数引数を加算して合計を返す AddInt と言う名前のライブラリ関数を呼び出します。
USER> set sum = $ZF(-3,"simplecallout.dll","AddInt",2,2)
USER> write "The sum is ",sum,!
The sum is 4
この例では、$ZF(-3) を使用します。これは、単一のコールアウト・ライブラリ関数を呼び出す最も簡単な方法です。その他のオプションは、“コールアウト・ライブラリ関数の呼び出し” を参照してください。
simplecallout.dll コールアウト・ライブラリの複雑さは、それを呼び出すコードとあまり変わりません。すべてのコールアウト・ライブラリで必要とされる以下の 3 つの要素を含みます。
-
cdzf.h コールアウト・ヘッダ・ファイルを含めるときに提供される標準コード。
-
パラメータが正しく指定された 1 つ以上の関数。
-
ZFEntry テーブル のマクロ・コード。これは、ライブラリがロードされる際に Caché がコールアウト関数を見つけるために使用するメカニズムを生成します (詳細は、“ZFEntry テーブルの作成” を参照してください)。
simplecallout.dll コールアウト・ライブラリを生成するためにコンパイルされたコードは以下のとおりです。
#define ZF_DLL /* Required only for dynamically linked libraries. */
#include <cdzf.h> /* Required for all Callout code. */
int AddTwoIntegers(int a, int b, int*outsum) {
*outsum = a+b; /* set value to be returned by the $ZF function call */
return 0; /* set the exit status code */
}
ZFBEGIN
ZFENTRY("AddInt","iiP",AddTwoIntegers)
ZFEND
-
1 番目の行は、Caché にコードを静的にリンクする (“静的にリンクされたコールアウト関数” で後述) のではなく、動的にリンクされたコールアウト・ライブラリを作成していることを示すスイッチである ZF_DLL を定義する必要があります。
-
2 番目の行は、動的および静的リンク・コードの両方で必要な cdzf.h ファイルを含みます。
-
AddTwoIntegers() 関数が次に定義されます。これには、以下の機能があります。
-
2 つの入力パラメータである整数 a と b、および 1 つの出力パラメータである整数ポインタ *outsum。
-
出力パラメータ *outsum に値を割り当てる文。これは、$ZF(-3) への呼び出しによって返される値です。
-
return 文は、関数出力値を返しません。代わりに、$ZF 呼び出しが正常に行われた場合に Caché によって受け取られる終了ステータス・コードを指定します。この関数が失敗した場合、Caché はシステムによって生成された終了ステータス・コードを受け取ります。
-
-
最後の 3 行は、Caché がコールアウト・ライブラリ関数を見つけるために使用する ZFEntry テーブルを生成するマクロ呼び出しです。この例では、単一のエントリのみです。ここで、
-
"AddInt" は、$ZF 呼び出し内の関数を識別するために使用される文字列です。
-
"iiP" は、2 つの入力値および出力値のデータ型を指定する文字列です。
-
AddTwoIntegers は、C 関数のエントリ・ポイント名です。
-
ZFEntry テーブルは、共有ライブラリをロードし、コールアウト・ゲートウェイによりアクセス可能にするメカニズムです (“ZFEntry テーブルの作成” を参照)。ZFENTRY 宣言は、C 関数と ObjectScript $ZF 呼び出し間のインタフェースを指定します。この例では、このインタフェースは、次のように動作します。
-
C 関数宣言 は、以下の 3 つのパラメータを指定します。
int AddTwoIntegers(int a, int b, int*outsum)
パラメータ a および b は入力であり、outsum は、出力値を受け取ります。AddTwoIntegers の返り値は、終了ステータス・コードであり、出力値ではありません。
-
ZFENTRY マクロ は、Caché 内での関数の識別方法およびパラメータが渡される方法を定義します。
ZFENTRY("AddInt","iiP",AddTwoIntegers)
"AddInt" は、$ZF 呼び出し内の C 関数 AddTwoIntegers を指定するために使用されるライブラリ関数識別子です。リンク宣言 ("iiP") は、パラメータ a および b をリンク・タイプ i (入力のみの整数) として、outsum をリンク・タイプ P (入力および出力の両方に使用できる整数ポインタ) として宣言します。
-
$ZF(-3) 関数呼び出し は、ライブラリ名、ライブラリ関数識別子、および入力パラメータを指定し、出力パラメータの値を返します。
set sum = $ZF(-3,"simplecallout.dll","AddInt",2,2)
パラメータ a および b は、最後の 2 つの引数によって指定されます。3 番目のパラメータ outsum は出力にのみ使用されるため、引数は必要ありません。outsum の値は、$ZF(-3) 呼び出しが返されたときに sum に割り当てられます。
ZFEntry テーブルの作成
すべてのコールアウト・ライブラリは、ZFEntry テーブルを定義する必要があり、これにより Caché がコールアウト関数をロードしてアクセスできるようになります (簡単な例は “コールアウト・ライブラリの概要” を参照してください)。ZFEntry テーブルは ZFBEGIN で始まり ZFEND で終わるマクロ・コードのブロックによって生成されます。これら 2 つのマクロ間で、関数を公開するごとに 1 回、ZFENTRY マクロを呼び出す必要があります。
各 ZFENTRY 呼び出しは、以下の 3 つの引数をとります。
zfentry(zfname,linkage,entrypoint)
ここで、zfname は $ZF 呼び出し内で関数を指定するために使用される文字列、linkage は引数を渡す方法を指定する文字列、entrypoint は C 関数のエントリ・ポイント名です。
既定では、ZFEntry テーブルは、静的にリンクされている関数にのみ使用できるコードを生成します (詳細は、“静的にリンクされたコールアウト関数” を参照してください)。コールアウト・ライブラリを作成するには、マクロ・コードがライブラリ関数を見つけるための別のメカニズムを生成するようにするスイッチである #define ZF_DLL 指示文をコードに含める必要があります。静的ポインタ・テーブルの代わりに、内部 GetZFTable 関数が生成されます。コールアウト・ライブラリがロードされると、Caché はこの関数を呼び出して後続のライブラリ関数名の検索用にライブラリを初期化します。
ZFEntry テーブル内のエントリの位置が重要となる場合があります。$ZF(-5) および $ZF(-6) インタフェース (次の章 “コールアウト・ライブラリ関数の呼び出し” で説明します) は、両方ともテーブル内でシーケンス番号 (1 で始まる) を指定することによってライブラリ関数を呼び出します。例えば、$ZF(-6) は以下の呼び出しを使用して ZFEntry テーブル内の 3 番目の関数を呼び出します。
x = $ZF(-6,libID,3)
ここで libID はライブラリ識別子、3 はテーブル内の 3 番目のエントリのシーケンス番号です。
OpenVMS システムでは、ZFENTRY マクロは ZFPRIV で置き換えることができます。これは、特権レベルを指定する追加パラメータをとります (“特権レベルを上げる ZFPRIV の使用” を参照)。
ZFEntry リンク・オプション
各 ZFENTRY 文 (“ZFEntry テーブルの作成” を参照) では、関数引数が渡される方法を決定する文字列が必要です。このセクションでは、利用可能なリンク・オプションについて詳細に説明します。
-
NULL で終了する文字列を C リンク・タイプで渡す — NULL で終了する文字列のリンク・オプションについて説明します。
-
短い計算文字列を B リンク・タイプで渡す — 計算文字配列に ZARRAY 構造を使用するリンクについて説明します。
-
標準的な計算文字列を J リンク・タイプで渡す — 計算文字配列に Caché CACHE_EXSTR 構造を使用するリンクについて説明します。
-
短い文字列の $ZF ヒープの構成 — 従来の短い文字列パラメータ渡しのメモリ割り当てを制御する Caché システム設定について説明します。
リンクの概要
各 ZFENTRY 文 (“ZFEntry テーブルの作成” を参照) では、引数が渡される方法を説明する文字列が必要です。例えば、"iP" は、整数と整数へのポインタの 2 つのパラメータを指定します。2 番目の文字は、2 番目の引数が入力と出力の両方に使用されることを指定するために大文字になっています。コードは、最大で 32 の実パラメータおよび仮パラメータを持つことができます。
大文字のリンク・タイプを指定する場合 (i を除くすべてのリンク・タイプで許可されている)、入力と出力の両方にこの引数を使用することができます。1 つの出力引数のみが指定されている場合は、その最終値は関数の返り値として使用されます。複数の出力引数が指定されている場合は、すべての出力引数がコンマ区切りの文字列として返されます。
出力引数は入力引数として使用する必要はありません。すべての入力引数の後に出力限定引数を指定する場合、関数は出力引数のいずれも指定することなく呼び出すことができます (例は、“コールアウト・ライブラリの概要” を参照してください)。
ObjectScript プログラマの観点からすると、パラメータは入力のみです。実パラメータの値は $ZF 呼び出しによって評価され、C ルーチン宣伝内の仮パラメータにリンクされます。C 仮パラメータへの変更は失われるか、または$ZF 返り値にコピー可能になるかのいずれかです。
ZFENTRY マクロが、仮パラメータを返り値として使用するように指定しない場合は、$ZF 呼び出しは空の文字列 ("") を返します。リンク宣言は、1 つ以上の出力パラメータを含むことができます。この場合、すべての返り値は単一のコンマ区切り文字列に変換されます。複数の返り値間に挿入されたコンマと、1 つの返り値内に存在するコンマとを区別する方法はないため、最後の返り値のみがコンマを含むようにします。
以下のテーブルは、利用可能なオプションを説明しています。
C データ型 | Input | In/Out | メモ |
---|---|---|---|
int | i | なし (P を使用) | i リンク・タイプは入力のみです。整数タイプを返すには、P (int *) を使用します。入力引数は数値文字列の場合があります (メモ 1 参照)。 |
int * | p | P | 入力引数は数値文字列の場合があります (メモ 1 参照)。 |
double * | d | D | 入力引数は数値文字列の場合があります (メモ 1 参照)。#D を使用して double * を基数 2 形式で保持します (メモ 2 を参照)。 |
float * | f | F | 入力引数は数値文字列の場合があります (メモ 1 参照)。#F を使用して float * を基数 2 形式で保持します (メモ 2 を参照)。 |
char * | 1c または c | 1C または C | これは、一般的な C NULL 終了文字列です (メモ 3 を参照)。 |
unsigned short * | 2c または w | 2C または W | これは、C 形式の NULL 終了 UTF-16 文字列です (メモ 3 を参照)。 |
wchar t * | 4c | 4C | これは、wchar_t 要素のベクトルとして保存される C 形式の NULL 終了文字列です (メモ 3 および 4 を参照)。 |
ZARRAYP | 1b または b | 1B または B | 最大 32,767 文字の短い 8 ビット各国語文字列。 |
ZWARRAYP | 2b または s | 2B または S | 最大 32,767 文字の短い 16 ビット Unicode 文字列。 |
ZHARRAYP | 4b | 4B | wchar_t によって実装される要素内に保存される、最大 32,767 文字の短い Unicode 文字列 (メモ 4 を参照してください) |
CACHE_EXSTR | 1j または j | 1J または J | 8 ビット各国語文字で構成される、最大 3,641,144 文字の標準的な文字列 |
CACHE_EXSTR | 2j または n | 2J または N | 16 ビット Unicode 文字で構成される、最大 3,641,144 文字の標準的な文字列 |
CACHE_EXSTR | 4j | 4J | wchar_t 文字で構成される、最大 3,641,144 文字の標準的な文字列 (メモ 4 を参照してください) |
-
i、p、d、f — 数値引数が指定されると、Caché では文字列の入力引数が許可されます。詳細は、“数値リンクの使用” を参照してください。
-
#F、#D — 数値を基数 2 浮動小数点形式で保持するには、float * で #F を使用するかまたは double * で #D を使用します。詳細は、“数値リンクの使用” を参照してください。
-
1C、2C、4C — このリンクで渡されるすべての文字列は最初の NULL 文字で切り捨てられます。詳細は、“NULL で終了する文字列を C リンク・タイプで渡す” を参照してください。
-
4B、4C、4J — wchar_t が一般的に 32 ビットであっても、Caché では 16 ビットのみを使用して各 Unicode 文字を格納するため、これらのリンクは wchar_t の使用を指定する既存のコードまたはシステム・インタフェースとやり取りするときにのみ役立ちます。
構造体と引数のプロトタイプ定義 (インターシステムズ内部定義を含む) は、インクルード・ファイル cdzf.h にあります。
この章で説明しているリンク・タイプに加えて、OpenVMS システム・サービスを呼び出す際には V リンクを使用することができます (“システム・サービスでの V リンクの使用” を参照)。
数値リンクの使用
数値リンク・タイプは、以下のデータ型用に提供されています。
C データ型 | Input | In/Out | メモ |
---|---|---|---|
int | i | なし (P を使用) | i リンク・タイプは入力のみです。整数タイプを返すには、代わりに P を使用します。 |
int * | p | P | int へのポインタです。 |
double * | d | D | #D (出力のみ) を使用して double * を基数 2 形式で返します。 |
float * | f | F | #F (出力のみ) を使用して float * を基数 2 形式で返します。 |
数値引数が指定されると、Caché では文字列の入力引数が許可されます。文字列が渡されると、先頭の数字が文字列から解析されて数値が派生します。先頭の数字がない場合は、値 0 が受け取られます。つまり、"2DOGS" は 2.0 として受け取られますが、"DOG" は 0.0 として受け取られます。整数の引数は切り捨てられます。例えば、"2.1DOGS" は 2 として受け取られます。詳細は、"ObjectScript の使用法" の “文字列から数値への変換” を参照してください。
出力リンクが F (float *) または D (double *) で指定されている場合、返す数値は内部基数 10 の数の形式に変換されます。数値を基数 2 形式で保持するには、float * で #F を使用するかまたは double * で #D を使用します。
入力引数では # 接頭語は許可されていません。変換を回避するには、関数を呼び出す ObjectScript コード内で $DOUBLE を使用して入力値を作成する必要があり、対応する入力リンクは小文字の f または d として指定される必要があります。
既定では、Caché は、10 進法で小数を格納します。例えば、数値 1.3 は 13*.10 として格納されます。一方、大半の高レベル言語は、2 進数の形式で小数を格納します (2 進数と 2 の累乗の積)。引数を f (float *) または d (double *) として記述する場合、Caché は、入力時に 10 進数値を 2 進数値に変換し、出力時に 10 進数値に戻します。この変換により、値に若干の誤差が生じる可能性があります。
Caché は標準の IEEE 形式の 64 ビット浮動小数点を作成する $DOUBLE 関数をサポートします。これらの数は、精度を失うことなく外部関数と Caché 間で渡すことができます (外部関数が 64 ビットの double ではなく 32 ビットの float を使用する場合を除く)。出力では、IEEE 形式の使用は、接頭語 # を F または D の引数タイプへ追加すると、指定できます。例えば、"i#D" は整数の入力引数 1 つと、64 ビット浮動小数点出力引数 1 つに引数リストを指定します。
NULL で終了する文字列を C リンク・タイプで渡す
このリンク・タイプは、Caché が NULL ($CHAR(0)) 文字を含む文字列を送信しないことがわかっている場合にのみ使用します。このデータ型を使用する際は、C 関数は、文字列が長い場合でも、Caché によって渡される文字列を最初の NULL 文字で切り捨てます。例えば、文字列 "ABC"_$CHAR(0)_"DEF" は、"ABC" に切り捨てられます。
C データ型 | Input | In/Out | メモ |
---|---|---|---|
char * | 1c または c | 1C または C | これは、一般的な C NULL 終了文字列です。 |
unsigned short * | 2c または w | 2C または W | これは、C 形式の NULL 終了 UTF-16 文字列です。 |
wchar t * | 4c | 4C | これは、wchar_t 要素のベクトルとして保存される C 形式の NULL 終了文字列です。 |
数値文字列を返すために 3 つすべてのリンク・タイプを使用する短いコールアウト・ライブラリを以下に示します。
以下の 3 つの関数それぞれは、ランダム整数を生成して最大 6 桁の数値文字列に変換し、C リンクを使用してその文字列を返します。
#define ZF_DLL // Required when creating a Callout library.
#include <cdzf.h>
#include <stdio.h>
#include <wchar.h> // Required for 16-bit and 32-bit strings
int get_sample(char* retval) { // 8-bit, null-terminated
sprintf(retval,"%d",(rand()%1000000));
return ZF_SUCCESS;
}
int get_sample_W(unsigned short* retval) { // 16-bit, null-terminated
swprintf(retval,6,L"%d",(rand()%1000000));
return ZF_SUCCESS;
}
int get_sample_H(wchar_t* retval) { // 32-bit, null-terminated
swprintf(retval,6,L"%d",(rand()%1000000));
return ZF_SUCCESS;
}
ZFBEGIN
ZFENTRY("GetSample","1C",get_sample)
ZFENTRY("GetSampleW","2C",get_sample_W)
ZFENTRY("GetSampleH","4C",get_sample_H)
ZFEND
短い計算文字列を B リンク・タイプで渡す
cdzf.h コールアウト・ヘッダ・ファイルは、短い文字列 (インターシステムズの従来の文字列型) を表す計算文字列構造 ZARRAY、ZWARRAY、および ZHARRAY を定義します。これらの構造は、文字要素の配列 (それぞれ、8 ビット、16 ビット Unicode、または 32 ビット wchar t) および配列内の要素の数を指定する short 整数 (最大値は 32,768) を含みます。以下はその例です。
typedef struct zarray {
unsigned short len;
unsigned char data[1]; /* 1 is a dummy value */
} *ZARRAYP;
以下はその説明です。
-
len — 配列の長さが格納されます。
-
data — 文字データを格納する配列です。要素タイプは、ZARRAY は unsigned char、ZWARRAY は unsigned short、ZHARRAY は wchar_t です。
B リンクは、3 つの配列構造に対応して、ポインタ型 ZARRAYP、ZWARRAYP、および ZHARRAYP を指定します。返される配列の最大サイズは 32,767 文字です。
C データ型 | Input | In/Out | メモ |
---|---|---|---|
ZARRAYP | 1b または b | 1B または B | 8 ビットの最大 32,767 文字を含む短い各国語文字列。 |
ZWARRAYP | 2b または s | 2B または S | 16 ビットの最大 32,767 文字を含む短い Unicode 文字列。 |
ZHARRAYP | 4b | 4B | 最大 32,767 の wchar_t 文字を含む短い Unicode 文字列。 |
引数の最大合計長さは、1 文字あたりのバイト数に依存します (“$ZF ヒープの構成” を参照)。
数値文字列を返すために 3 つすべてのリンク・タイプを使用するコールアウト・ライブラリを以下に示します。
以下の 3 つの関数それぞれは、ランダム整数を生成して最大 6 桁の数値文字列に変換し、B リンクを使用して文字列を返します。
#define ZF_DLL // Required when creating a Callout library.
#include <cdzf.h>
#include <stdio.h>
#include <wchar.h> // Required for 16-bit and 16-bit characters
int get_sample_Z(ZARRAYP retval) { // 8-bit, counted
unsigned char numstr[6];
sprintf(numstr,"%d",(rand()%1000000));
retval->len = strlen(numstr);
memcpy(retval->data,numstr,retval->len);
return ZF_SUCCESS;
}
int get_sample_ZW(ZWARRAYP retval) { // 16-bit, counted
unsigned short numstr[6];
swprintf(numstr,6,L"%d",(rand()%1000000));
retval->len = wcslen(numstr);
memcpy(retval->data,numstr,(retval->len*sizeof(unsigned short)));
return ZF_SUCCESS;
}
int get_sample_ZH(ZHARRAYP retval) { // 32-bit, counted
wchar_t numstr[6];
swprintf(numstr,6,L"%d",(rand()%1000000));
retval->len = wcslen(numstr);
memcpy(retval->data,numstr,(retval->len*sizeof(wchar_t)));
return ZF_SUCCESS;
}
ZFBEGIN
ZFENTRY("GetSampleZ","1B",get_sample_Z)
ZFENTRY("GetSampleZW","2B",get_sample_ZW)
ZFENTRY("GetSampleZH","4B",get_sample_ZH)
ZFEND
複数の値を含む出力引数文字列ではコンマが区切り文字として使用されます。コンマは計算文字列配列の一部となるため、引数リストの 最後 にこれらの配列を宣言し、呼び出しごとに 1 つの配列を使用します。
標準的な計算文字列を J リンク・タイプで渡す
callin.h ヘッダ・ファイルは、標準的な InterSystems 文字列を表す計算文字列構造 CACHE_EXSTR を定義します。この構造は、文字要素の配列 (8 ビット、16 ビット Unicode、または 32 ビット wchar t) および配列内の要素の数を指定する int 値 (最大値は 3,641,144) を含みます。
typedef struct {
unsigned int len; /* length of string */
union {
Callin_char_t *ch; /* text of the 8-bit string */
unsigned short *wch; /* text of the 16-bit string */
wchar_t *lch; /* text of the 32-bit string */
/* OR unsigned short *lch if 32-bit characters are not enabled */
} str;
} CACHE_EXSTR, *CACHE_EXSTRP;
C データ型 | Input | In/Out | メモ |
---|---|---|---|
CACHE_EXSTR | 1j または j | 1J または J | 8 ビット各国語文字の標準的な文字列 |
CACHE_EXSTR | 2j または n | 2J または N | 16 ビット Unicode 文字の標準的な文字列 |
CACHE_EXSTR | 4j | 4J | 32 ビット wchar_t 文字の標準的な文字列 |
次の 2 つの InterSystems コールイン関数 ("コールイン API の使用法" の “コールイン関数リファレンス” を参照してください) は、CACHE_EXSTR の作成または削除に使用されます。
-
CacheExStrKill — CACHE_EXSTR 文字列に関連付けられているストレージを解放します。
-
CacheExStrNew[W][H] — 文字列に対して要求されたストレージの容量を割り当て、CACHE_EXSTR 構造に、構造の長さおよび構造の値フィールドへのポインタを埋め込みます。
これらの関数の使用方法のデモンストレーションは、以下の例を参照してください。
数値文字列を返すために 3 つすべてのリンク・タイプを使用するコールアウト・ライブラリを以下に示します。
以下の 3 つの関数それぞれは、ランダム整数を生成して最大 6 桁の数値文字列に変換し、J リンクを使用して文字列を返します。
#define ZF_DLL // Required when creating a Callout library.
#include <cdzf.h>
#include <stdio.h>
#include <wchar.h>
#include <callin.h>
int get_sample_L(CACHE_EXSTRP retval) { // 8-bit characters
Callin_char_t numstr[6];
size_t len = 0;
sprintf(numstr,"%d",(rand()%1000000));
len = strlen(numstr);
CACHEEXSTRKILL(retval);
if (!CACHEEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.ch,numstr,len); // copy to retval->str.ch
return ZF_SUCCESS;
}
int get_sample_LW(CACHE_EXSTRP retval) { // 16-bit characters
unsigned short numstr[6];
size_t len = 0;
swprintf(numstr,6,L"%d",(rand()%1000000));
len = wcslen(numstr);
CACHEEXSTRKILL(retval);
if (!CACHEEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.wch,numstr,(len*sizeof(unsigned short))); // copy to retval->str.wch
return ZF_SUCCESS;
}
int get_sample_LH(CACHE_EXSTRP retval) { // 32-bit characters
wchar_t numstr[6];
size_t len = 0;
swprintf(numstr,6,L"%d",(rand()%1000000));
len = wcslen(numstr);
CACHEEXSTRKILL(retval);
if (!CACHEEXSTRNEW(retval,len)) {return ZF_FAILURE;}
memcpy(retval->str.lch,numstr,(len*sizeof(wchar_t))); // copy to retval->str.lch
return ZF_SUCCESS;
}
ZFBEGIN
ZFENTRY("GetSampleL","1J",get_sample_L)
ZFENTRY("GetSampleLW","2J",get_sample_LW)
ZFENTRY("GetSampleLH","4J",get_sample_LH)
ZFEND
前述の例では、CACHEEXSTRKILL(retval) は、メモリから入力引数を削除するために常に呼び出されています。これは、引数が出力に使用されない場合でも常に実行する必要があります。実行しない場合は、メモリ・リークが発生します。
短い文字列の $ZF ヒープの構成
このセクションは、従来の短い文字列 (“短い計算文字列を B リンク・タイプで渡す” を参照してください) にのみ適用されます。標準的な InterSystems 文字列 (“標準的な計算文字列を J リンク・タイプで渡す” を参照してください) は、独自のスタックを使用します。
$ZF ヒープは、すべての $ZF の短い文字列入力および出力パラメータに割り当てられる仮想メモリ領域です。これは、以下の Caché システム設定によって制御されます。
-
ZFString は、1 つの文字列パラメータに対して使用が許可される文字数です。このために実際に必要なバイト数は、使用している文字が 8 ビット文字か、16 ビット Unicode 文字か、UNIX® 上の 32 ビット文字かによって異なります。この設定で許可されている範囲は、0 から 32767 文字です。既定は、0 であり、最大値を使用することを示します。
-
ZFSize は、Caché がすべての $ZF 入力および出力パラメータに割り当てる合計バイト数です。この設定で許可されている範囲は、0 から 270336 バイトです。0 (既定の設定) は、Caché が ZFString の値に基づいて適切な値を計算することを示します。
以下のように ZFSize (合計バイト数) を ZFString (文字列あたりの最大文字数) に基づいて計算します。
ZFSize = (<bytes per character> * ZFString) + 2050
例えば、ZFString の値が既定の 32767 文字だとします。
-
Unicode 16 ビット文字を使用すると、ZFSize の適切な値は (2 * 32767 + 2050) = 67584 バイトになります。
-
UNIX® 32 ビット文字を使用すると、ZFSize の適切な値は (4 * 32767 + 2050) = 133118 バイトになります。
これらの設定は、以下のいずれかの場所で変更できます。
-
構成パラメータ・ファイル ("構成パラメータ・ファイル・リファレンス" の “[config]” セクションの “zfheap” を参照してください)。
-
管理ポータル ("追加構成設定リファレンス" の “詳細メモリ設定” にある ZFSize および ZFString のエントリを参照してください)。
コールアウト・ライブラリの Runup 関数と Rundown 関数
InterSystems コールアウト・ライブラリは、共有オブジェクトがロードされたとき (runup) またはアンロードされたとき (rundown) に呼び出されるカスタム内部関数を含むことができます。どちらのケースも引数は渡されません。関数は以下のように使用されます。
-
ZFInit — コールアウト・ライブラリが $ZF(-3)、$ZF(-4,1)、または $ZF(-6) によって最初にロードされたときに呼び出されます。この関数からの返りコードは、エラーがないことを示すゼロ、もしくはいくつかの障害の存在を示すゼロ以外の値になります。呼び出しが正常に実行されると、ZFUnload rundown 関数のアドレスが保存されます。
-
ZFUnload — コールアウト・ライブラリが $ZF(-3) への呼び出しによってアンロードまたは置換されたとき、あるいは $ZF(-4,2) または $ZF(-4,4) によってアンロードされたときに呼び出されます。プロセスの停止では呼び出されません。エラーが rundown 関数実行中に発生した場合、それ以降、コールアウト・ライブラリのアンロードを許可するための呼び出しは無効となります。ZFUnload からの返り値は現在無視されています。
コールアウト・ライブラリを構築する際、リンクを確立するプロシージャの間に、ZFInit と ZFUnload 記号を明示的にエクスポートする必要がある場合があります。
トラブルシューティング
ほとんどすべてのルーチンをコールアウト・ゲートウェイで呼び出すことができますが、そうしなければならないという意味ではありません。これは、数学関数で使用するのが最適であり、Caché I/O でうまく処理されない外部デバイスへのインタフェース、または Caché インタフェースが存在しないシステム・サービスの場合に効果的に使用することができます。
以下の動作によって重大な問題が発生する可能性があります。
-
自身に属していないメモリへのアクセス
メモリ・アクセス違反は、Caché によって処理され、Caché 内のバグとして扱われます。
-
トラップによって処理されるその他のエラーの発生
トラップによって処理されるエラー (ほとんどのプラットフォーム上でのゼロによる除算など) も Caché 内のバグとして扱われます。
-
プロセスの優先度の変更
Caché は、Caché を実行している他のプロセスと相互作用する必要があります。優先度を下げると、上げるのと同様に問題が発生する場合があります。例えば、プロセスが CPU を解放する直前にスピン・ロックで保護されたリソースを取得することを考えてみましょう。優先度が低すぎると、高い優先度のその他のプロセスがリソースを奪い合い、事実上、スピン・ロックを解除できるようにするプロセスの実行を妨げます。
-
中断のマスク
インターロックを実装するために中断を短時間マスクする場合がありますが、中断をマスクしたままにしないように十分注意する必要があります。
-
削除できないリソースを作成または開く
ファイルを開いて malloc を使用してメモリを割り当てることは問題ありません。それらのリソースはプロセスの終了時に閉じられるかまたは解放されます。2 番目のスレッドを作成すると、2 番目のスレッドが Caché プロセスの終了前に正常に終了することを保証できないため、2 番目のスレッドは作成しないでください。
-
opaque 以外のオブジェクトを ObjectScript 以外のコードで返す
コード内のメモリのブロックを malloc して、それを読み取るために $VIEW(address,−3,size) を使用できると考えないでください。また、ObjectScript 以外のコードに malloc ブロックを戻さないでください。コードは opaque ハンドルを返し、後で opaque ハンドルを受け取った時に使用する前に有効であることを確認する必要があります。
-
プロセスの終了
exit だけを呼び出すことはしないでください。常に ZF_SUCCESS または ZF_FAILURE のいずれかと共に返します (これらの値の実装は Caché プラットフォーム間で異なることに留意してください)。
-
exec のいずれかのバージョンの呼び出しによる終了
子プロセス内で fork してから exec を呼び出すことはできますが、必ず親は Caché に返り、子プロセスは Caché に返らないようにしてください。
これは、OpenVMS で LIB$DO_COMMAND を使用する際にも当てはまります。
-
プロセスでのエラー処理の振る舞いの変更
他のオペレーティング・システムと異なり、UNIX® システムのみが、現在の内部フレームのローカル・エラー処理を確立することを許可します。