perlcall - C からの Perl 呼び出し規約
このドキュメントの目的は、どのようにして Perl のサブルーチンを C から 直接呼び出すか、つまり コールバック の書き方を示すことです。
コールバックを記述するための Perl から提供される C の インターフェースについての議論とは別に、本ドキュメントでは実践的な インターフェースを例で示します。 それに加え、コールバックをコーディングするための幾つかの テクニックがカバーされます。
必要に応じて、例を示すようにしてあります。
An Error Handler@@@@@@@@@@エラーハンドラ
あるアプリケーションの C API へのインタフェース XSUB を作成しました。
アプリケーションでかなり一般的な機能として、なにか面倒が起こったときに 呼ぶことのできる C の関数を定義することができるようにすることが 挙げられます。 やりたいことは、代わりに Perl サブルーチンを呼ぶということです。
An Event Driven Program@@@@@@@@@@イベント駆動プログラム
どこでコールバックが使われるかの古典的な例は、 X window アプリケーションのようなイベントドリブンなプログラムに 見られます。 この場合登録内容は、マウスのボタンが押されたりカーソルが ウィンドウやメニューアイテムを選択したといった特定のイベントが 発生したときに呼びだされるように機能します。
記述したテクニックは、Perl プログラムを C のプログラムに埋め込むときにも 適用できますが、それはこのドキュメントの本来の目的ではありません。 C に Perl を埋め込むことの詳細は perlembed を参照してください。
このドキュメントの先に進む前に、perlxs と perlguts という 二つのドキュメントを読んでおいたほうが良いでしょう。
これらの性質は例を使って説明するのが簡単であるにも関らず、あなたは まず幾つかの重要な定義を知ることが必要です。
Perl には、Perl のサブルーチンを呼ぶことを許している C の関数が たくさんあります。 それを以下に示します。
I32 call_sv(SV* sv, I32 flags);
I32 call_pv(char *subname, I32 flags);
I32 call_method(char *methname, I32 flags);
I32 call_argv(char *subname, I32 flags, register char **argv);
中心となる関数は call_sv です。 他の全ての関数は特別な状況で Perl サブルーチンを呼び出しやすくするための単純なラッパーです。 最終的にはこれらの関数はすべて call_sv を呼び出して Perl サブルーチンを起動します。
関数 call_* は Perl に対するオプションのビットマスクを 渡すのに使われる flags
引数を取ります。 このビットマスクはそれぞれの関数で全く同じように働きます。 設定可能なビットマスクは "FLAG VALUES" で述べられています。
関数のそれぞれに対する説明を始めましょう。
call_sv は二つのパラメータをとります。 第一引数が SV* である sv
です。 これにより、呼び出す Perl サブルーチンを C の文字列(この場合 最初に SV に変換されます)としても、サブルーチンに対する リファレンスとしても指定することができます。 セクション "Using call_sv" で、 どのように call_sv を使えるかを示します。
関数 call_pv は call_sv と似ていますが、 call_pv("fred", 0)
のように呼び出したい Perl サブルーチンを 指定する第一引数に C の char * が来ることを期待しているという点が 異なります。 呼び出したいサブルーチンが別のパッケージに置かれている場合、 文字列にパッケージ名を含め "pkg::fred"
のようにします。
関数 call_method は Perl のクラスからメソッドを呼び出すのに使われます。 methname
というパラメータは呼び出すメソッドの名前に対応します。 メソッドの所属するクラスは、パラメータリストではなく Perlのスタックで渡されるということに注意してください。 このクラスは、クラスの名前(静的メソッドに対する場合)であっても オブジェクトに対するリファレンスであってもかまいません。 静的メソッドと仮想メソッドに関する詳細は perlobj を、call_method を 使った例は "Using call_method" を参照してください。
call_argv はパラメータ subname
に格納された C 文字列で 指定された Perl サブルーチンを呼び出します。 これはまた、flags
パラメータを取ります。 最後のパラメータ argv
は、Perl サブルーチンに渡されるパラメータである C 文字列の、NULL で終端されたリストから構成されます。 "Using call_argv" を参照してください。
上記の関数はすべて整数値を返します。 これは、Perl サブルーチンが返したアイテムの数です。 サブルーチンから返された実際のアイテムは Perl スタックに 格納されています。
一般的な規則として、あなたは いつでも これらの関数の戻り値を チェックすべきです。 あなたが Perl サブルーチンから返される値として、 ある特定の数だけを期待していたとしても、誰かが予期しないなにかを 行うことを止める手だてはないので -- 自分は警告されていない、とは 云わないでください。
すべての call_*
関数のパラメータ flags
は、以下に定義する シンボルを“論理和”で組み合わせて用います。
Perl のサブルーチンを無効コンテキストで呼び出します。
このフラグには二つの効果があります。
サブルーチンの呼び出しが無効コンテキスト(もし wantarray を実行すると その結果は未定義値となります)において実行されることを示します。
サブルーチンから実際に返されるものがなにもないことを保証します。
関数 call_* の戻り値は Perl のサブルーチンがアイテムを幾つ 返したのかを示します。 この例の場合は、0 となります。
Perl のサブルーチンをスカラコンテキストで呼び出します。 これはすべての call_* 関数に対するデフォルトのコンテキストの設定です。
このフラグには二つの効果があります。
サブルーチンに対して、スカラコンテキストで実行されるということを 示します(wantarray を実行した場合、結果は偽となります)。
サブルーチンから実際に返されるものはスカラだけであるということを 保証します。 もちろん、サブルーチンは wantarray を無視し、リストを 返すこともできます。 そうした場合、そうしたリストの最後の要素だけが返されることになります。
関数 call_* により返された値は、Perl サブルーチンが幾つの アイテムを返したかということを示します。 この場合、0 か 1 かのいずれかになります。
0 の場合、G_DISCARD フラグが指定されたということです。
1 の場合、Perl サブルーチンが実際に返したアイテムは Perl スタックに 積まれます。 スタックにあるこの値にどのようにアクセスするかはセクション "Returning a Scalar" にあります。 Perlサブルーチンが幾つのアイテムを返したかに関係なく、最後の一つだけが スタック上でアクセス可能であるということを忘れないでください。 つまり、ただ一つの要素からなるリストのように、値が一つだけ 置かれるのです。 他のすべてのアイテムは、call_* 関数から制御が戻ったときには 存在しません。 この振る舞いについての例はセクション "Returning a list in a scalar context" にあります。
Perl サブルーチンをリストコンテキストで呼び出します。
G_SCALAR を指定したときと同様、このフラグにも二つの効果があります。
サブルーチンが、リストコンテキストで実行されることを示します (wantarray を実行すると、その結果は真となります)。
関数 call_* から制御が戻ったときに、サブルーチンから返された すべてのアイテムがアクセス可能であることを保証します。
関数 call_* から返される値は、Perl サブルーチンがアイテムを 幾つ返したかを示すものです。
0 の場合、G_DISCARD フラグが指定されたということです。
0 以外の場合、サブルーチンが返したアイテムの個数となります。 これらのアイテムは Perl スタックに置かれます。 セクション "Returning a list of values" には G_ARRAY フラグを使った例と、 Perl スタックに置かれたアイテムをアクセスする仕組みの例があります。
デフォルトでは、関数 call_* は Perl サブルーチンの返したアイテムを スタックに置きます。 こういったアイテムに用がない場合、このフラグを設定することによって Perl が自動的にこれらのアイテムを取り除くようにすることを指定できます。 このフラグを使った場合でも、 Perl サブルーチンに対して G_SCALAR か G_ARRAY のいずれかをさらに 指定することで、(Perl サブルーチンが実行される)コンテキストを 指示できるということに注意してください。
このフラグを設定しなかった場合、なんらかの一時変数(たとえば、Perl サブルーチンに渡されたパラメータであるとかサブルーチンからの戻り値)を 自分自身で破棄することを確実に行うことが非常に重要です。 "Returning a Scalar" というセクションでは、これら一時変数をどのようにして 陽に破棄するかを説明しており、 "Using Perl to dispose of temporaries" というセクションではこの 問題を無視できる特定の場所や、Perlに後始末をさせることについて 述べています。
call_* の一つを使って Perl サブルーチンを呼び出したときはいつでも、 サブルーチンに対してパラメータが渡されたということが デフォルトで仮定されます。 Perl サブルーチンに対してなんのパラメータも渡さないという場合、この フラグをセットすることで時間を少々節約することができます。 これは Perl サブルーチンに対して、@_
を生成しないという 効果を持っています。
このフラグにより提供される機能が直接的なもののように見えるにも関らず、 これを使うのはそうすべき適当な理由があるときのみにすべきでしょう。 このように用心する理由は、G_NOARGS フラグを指定した場合であっても、 呼び出された Perl サブルーチンがパラメータを渡されたと 思い込んでいる可能性があるからです。
事実、起こりうる可能性として、呼び出した Perl サブルーチンが以前の Perl サブルーチンの配列 @_
にアクセスできてしまうというものがあります。 これは、call_* 関数を実行するコード自身が、他の Perl サブルーチンから 呼ばれたときに起こり得ます。 以下のコードはこれを説明するものです。
sub fred
{ print "@_\n" }
sub joe
{ &fred }
&joe(1,2,3);
この結果は次のようになります。
1 2 3
ここで起こったことは、fred
が joe
に属する配列 @_
に アクセスしているということです。
呼び出す Perl サブルーチンを、die を陽に呼び出したり、何かが 存在しなかったことにより即座に終了させることを可能にします。 デフォルトでは、そういったイベントが起こった場合にはプロセスは即座に 終了します。 しかしこの種のイベントをトラップしたいのなら、G_EVAL フラグを指定します。 それによって、サブルーチンの呼び出しを eval { } で囲むようになります。
call_* 関数から戻ってきたときは、いつでも通常の Perl スクリプトで そうするように変数 $@
をチェックする必要があります。
call_* から返された値は、他に指定したフラグとエラーが 起きたかどうかに依存します。 以下に起こりうるすべてのケースを挙げます。
関数 call_* から正常に戻ってきた場合、戻り値は前のセクションで 説明したようなものです。
G_DISCARD が指定されていた場合、戻り値は常に 0 になります。
G_ARRAY が指定されていて、かつ、エラーが発生した場合には戻り値は 常に 0 となります。
G_SCALAR が指定されていて、かつ、エラーが発生した場合には戻り値は 1となり、そしてスタックトップにある値は undef となります。 これは $@
を検査することで既にエラーを検出していていてプログラムの 継続を望んでいる場合には、スタックから undef を忘れずに ポップしなければならないということです。
G_EVAL の使用についての詳細は "Using G_EVAL" を参照してください。
先に述べた G_EVAL フラグの使用が 常に 変数 $@
をクリアして、 呼び出したコードにエラーがなかったときにエラーを表現する文字列を セットするということに気付いたかもしれません。 この適切でない $@
のリセットは、eval {}
機構を使ったエラーの 確認において問題となりうるものです。 なぜなら、eval {}
の中で $@
に設定されたエラーが発生した時点と $@
の値をチェックする(後続の)ステートメントが 実行される間に、他のコード(たとえば、ブロック終端の処理コード)を perl が呼び出す可能性があるからです。
このシナリオは、デストラクターの中から呼ばれるようなコード、非同期な コールバック、シグナルハンドラー、__DIE__
や __WARN__
のフック、 tie
関数といったもので最も有用です。 このような状況において、$@
をクリアすることを 望まないこともあるでしょうが、 すでにある $@
の内容に新たなエラーを単に追加するだけです。
G_KEEPERR フラグは、実装したコードを使用する call_* において G_EVAL と組み合わせて使われます。 このフラグは G_EVAL が使われていないときにはなんの効果も持ちません。
G_KEEPERR が使われたとき、コードの呼び出しで発生したすべてのエラーは "\t(in cleanup)" という文字列が前置され、さらに $@
の現在の値が 追加されます。 $@
の最後に既に同じエラーメッセージがある場合、エラーは追加されません。
更に、追加した文字列を使って警告が生成されます。 これは no warnings 'misc'
を使って無効化できます。
G_KEEPERR フラグは Perl のバージョン 5.002 で導入されました。
このフラグを使うことが正当である状況の例が "Using G_KEEPERR" にあります。
先に説明したように、wantarray を使ってサブルーチンが実行されている コンテキストを判定することができます。 これと同じことが、GIMME_V
マクロを使うことでも可能です。 このマクロはリストコンテキストで 呼ばれた場合には G_ARRAY
を、スカラコンテキストで呼ばれた場合には G_SCALAR
を、無効コンテキストの場合(たとえば戻り値が 使われないとき)には G_VOID
を返します。 このマクロの古いバージョンは GIMME
という名前で、 無効コンテキストのときに G_VOID
の代わりに G_SCALAR
を返していました。 GIMME_V
マクロの使用例は セクション "Using GIMME_V" にあります。
定義の話は十分でしょうから、いくつか例を示します。
Perl では、Perl スタックをアクセスする手助けのためのマクロをたくさん 用意しています。 Perl の内部ルーチンとのインターフェースには、 常にこれらのマクロを使うようにすべきでしょう。 将来 Perl に施される変更に対しても、これを使うことで、コードの方への 影響が少なくなるはずです。
もう一つ余計なことを言っておくと、最初のいくつかの例では、 call_pv 関数だけを使っています。 これは、単にみなさんがこの話題に入り込みやすいようにと 考えただけのことです。 call_pv と call_sv のどちらも使える場合、常に call_sv を 使うことを試してください。 詳しくは "Using call_sv" を参照してください。
最初の明快な例は、プロセスの UID を出力するために Perl サブルーチン PrintUID を呼びだします。
sub PrintUID
{
print "UID is $<\n";
}
と、これを呼ぶ C 側です
static void
call_PrintUID()
{
dSP;
PUSHMARK(SP);
call_pv("PrintUID", G_DISCARD|G_NOARGS);
}
ね、単純でしょう。
この例についていくつか注意点をあげておきましょう。
今のところ、dSP
と PUSHMARK(SP)
は無視してください。 これについては、次の例でお話します。
PrintUID に引数を渡しませんので、G_NOARGS を指定できます。
PrintUID から返されるものは、特に必要ありませんので G_DISCARD を 指定しています。 PrintUID が何か値を返すように変更されても、 G_DISCARD を指定しておくと call_pv から制御が戻るときにその値が 捨てられることになります。
call_pv が使われていますから、Perl サブルーチンは C の文字列として 表現されています。
G_DISCARD を指定しましたので、call_sv からの戻り値をチェックする 必要はありません。 常に 0 となります。
さて、今度はもう少し込み入った例です。 今回は、二つの引数として、 文字列 ($s) と整数 ($n) をとる Perl サブルーチン LeftString
を 呼び出してみましょう -- このサブルーチンでは、単純に文字列の最初の $n 文字を出力します。
Perl サブルーチンは以下のようなものです:
sub LeftString
{
my($s, $n) = @_;
print substr($s, 0, $n), "\n";
}
LeftString を呼ぶための C の関数は、以下のようになります:
static void
call_LeftString(a, b)
char * a;
int b;
{
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(a, 0)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
call_pv("LeftString", G_DISCARD);
FREETMPS;
LEAVE;
}
C の関数 call_LeftString の注意点を示します。
パラメータは、Perl スタックを使って Perl サブルーチンに渡されます。 これが、dSP
で始まり PUTBACK
行で終わるコードの目的です。 dSP
はスタックポインタのローカルなコピーを宣言します。 このローカルなコピーは 常に SP
として アクセスするようにすべきです。
Perl スタックに何かを置こうとする場合には、どこにおけばよいかを 知る必要があります。 これが、マクロ dSP
の目的です -- Perl スタックポインタの ローカルな コピーを宣言し、初期化します。
この例で使う他のすべてのマクロは、このマクロの使用を前提にしています。
Perl サブルーチンを直接 XSUB 関数から呼ぶ場合はこの規則の例外で、 dSP
マクロを陽に使う必要はありません -- 自動的に宣言されます。
スタック上に積まれるパラメータはすべて、PUSHMARK
マクロと PUTBACK
マクロで囲まなければなりません。 この 二つのマクロは、 この文脈では、自動的にプッシュした引数の数を数えるために使われます。 これによりPerl がサブルーチンに対して @_
配列を作るときに、 その大きさがわかるという仕組みになっているのです。
PUSHMARK
マクロは、Perl に対して、内的にその時点のスタックポインタに 注目するように伝えます。 (例 1 の場合のように) 引数を渡さない場合であっても、call_* 関数を 呼ぶ場合には、その前に PUSHMARK
マクロを呼ばなくてはなりません -- Perl からすると、引数が ないことを知る必要があるのです。
少し先へ飛んで、PUTBACK
マクロは、グローバルなスタックポインタを、 先に作ったローカルなものに合わせます。 これを行わないと、どこに引数を置いたかを call_pv が 判断することができません -- ここまで、すべてのスタックポインタの 操作は、ローカルなものに対して行なってきたのであって、 グローバルなものは触っていなかったのです。
元に戻って、次に XPUSH を引数分呼んでいます。 ここで、実際に引数がスタックに積まれます。 今回の場合、文字列と整数を積んでいます。
XPUSH マクロがどのように動作するのかについて詳しくは、 "XSUBs and the Argument Stack" in perlguts を参照してください。
私たちはここで一時的な値を(sv_2motral() の呼び出しによって)作り出したので、 Perl のスタックを調整することと mortal な SV を消去する必要が生じます。
これが関数の先頭に
ENTER;
SAVETMPS;
を置き、
FREETMPS;
LEAVE;
を関数の末尾に置く理由です。 ENTER
/SAVETMPS
のペアは作成した一時変数に対する境界を 生成します。 つまり、私たちが取り扱う一時変数がこれらの呼び出しの後で 生成されたものに限定されるだろうということです。
FREETMPS
/LEAVE
のペアは Perl のサブルーチンが返す任意の値を扱い (次の例を参照してください)、それに加えて私たちが作成した mortal な SV を ダンプします。 コードの先頭で ENTER
/SAVETMPS
を使うことによって、mortals 以外の ものが削除されないようにします。
これらのマクロは、Perl を使っているときに {
と }
を使った ローカル変数のスコープの制限に似たような働きをすると考えてください。
これらのマクロを使った別の例については セクション "Using Perl to dispose of temporaries" を 参照してください。
ここまでで、LeftString を call_pv 関数を介して呼ぶことが できます。 今回指定しているフラグは G_DISCARD のみです。 今回 Perl サブルーチン に 二つのパラメータを渡しますので、G_NOARGS は 指定していません。
さて、Perl サブルーチンからの戻り値を扱う例を見てみましょう。
ここに挙げる Perl サブルーチンは、二つの整数引数をとって単にその和を 返す Adder というものです。
sub Adder
{
my($a, $b) = @_;
$a + $b;
}
Adder からの戻り値を扱う必要がありますので、C 関数側は今回、 多少複雑になります。
static void
call_Adder(a, b)
int a;
int b;
{
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(a)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
count = call_pv("Adder", G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Big trouble\n");
printf ("The sum of %d and %d is %d\n", a, b, POPi);
PUTBACK;
FREETMPS;
LEAVE;
}
ここでの注意点は、
今回は、フラグとして G_SCALAR だけを使用しています。 これは、@_
配列が作られ、Adder から返された値は、call_pv の 呼び出し後も存在することを表わします。
SPAGAIN
マクロの目的は、ローカルなスタックポインタを リフレッシュすることです。 call_pv の呼び出しの間に再配置された Perl スタックへメモリ配置を 行なうことができますから、これが必要になります。
コードの中で Perl スタックポインタを利用する場合には、call_* 関数や 他の Perl の内部関数を利用するときには必ず、SPAGAIN を使って ローカルなポインタをリフレッシュしなくてはなりません。
Adder から返されるのは、単一の値のみのはずですが、いずれにしても call_pv からの返却値をチェックするのが良いでしょう。
単一の値を期待するのは、一つであることを知っていることとは違います。 誰かが Adder を改造してリストを返すようにし、その可能性を チェックしていなかったときにこの操作を行なってしまうと、Perl スタックの 状態は矛盾したものになってしまいます。 こんなことは誰も望みはしないでしょう。
スタックから、返却値をポップするのに、ここでは POPi
マクロを 使用しています。 ここでは整数が必要であったため、POPi
を使用したのです。
返された値の型に応じて、以下の POP マクロを使用することができます。
POPs SV
POPp pointer
POPn double
POPi integer
POPl long
最後の PUTBACK
は、関数を抜ける前に、Perl スタックを矛盾の無い 状態にしておくために使用しています。 これは、POPi
でスタックから返却値を取り出したときに、ローカルな スタックポインタのみを更新するため、必要となります。 先の例で説明したように PUTBACK
は、グローバルなスタックポインタを ローカルなスタックポインタの値にあわせるように設定します。
さて、今度は、先の例を改造して、二つの引数の和と差の両方を返すように してみましょう。
Perl サブルーチンは
sub AddSubtract
{
my($a, $b) = @_;
($a+$b, $a-$b);
}
のようになり、C 関数は
static void
call_AddSubtract(a, b)
int a;
int b;
{
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(a)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
count = call_pv("AddSubtract", G_ARRAY);
SPAGAIN;
if (count != 2)
croak("Big trouble\n");
printf ("%d - %d = %d\n", a, b, POPi);
printf ("%d + %d = %d\n", a, b, POPi);
PUTBACK;
FREETMPS;
LEAVE;
}
call_AddSubtract が以下のように呼ばれた場合、
call_AddSubtract(7, 4);
出力はこうなります。
7 - 4 = 3
7 + 4 = 11
注意点
リストコンテキストが必要なので、G_ARRAY を使用します。
スタックから 二つの値を取り出すために今回 二つの POPi
を 使っていることは驚くに値しないでしょう。 それよりも注目すべきは、POP*
マクロを使ってスタックから 取り出したときに 逆順 となることです。
前のセクションにあった Perl サブルーチンは、この例のように スカラコンテキストで呼ばれていました。
static void
call_AddSubScalar(a, b)
int a;
int b;
{
dSP;
int count;
int i;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(a)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
count = call_pv("AddSubtract", G_SCALAR);
SPAGAIN;
printf ("Items Returned = %d\n", count);
for (i = 1; i <= count; ++i)
printf ("Value %d = %d\n", i, POPi);
PUTBACK;
FREETMPS;
LEAVE;
}
別の変更点は、call_AddSubScalar が Perl サブルーチンから返された アイテムの数を出力するようになり、サブルーチンの戻り値 (単純化のために、ここではこれは整数と仮定します)を 出力するようになったと言うことです。 ですから、call_AddSubScalar は
call_AddSubScalar(7, 4);
のように呼び出され、以下のような出力を行います。
Items Returned = 1
Value 1 = 3
この場合に注意すべき点は、サブルーチンからは(AddSubtract が実際に call_AddSubScalar に返しているのと同じ)リストの最後にある アイテムだけが返されるということです。
引数リストを使って直接値を返すことも可能です。 ただし、これが実際に望ましい方法であるか否かについては、まったく別の 問題です。
以下の Perl サブルーチン Inc は二つの引数をとり、それぞれを インクリメントします。
sub Inc
{
++ $_[0];
++ $_[1];
}
そして、これを呼び出す C 関数です。
static void
call_Inc(a, b)
int a;
int b;
{
dSP;
int count;
SV * sva;
SV * svb;
ENTER;
SAVETMPS;
sva = sv_2mortal(newSViv(a));
svb = sv_2mortal(newSViv(b));
PUSHMARK(SP);
XPUSHs(sva);
XPUSHs(svb);
PUTBACK;
count = call_pv("Inc", G_DISCARD);
if (count != 0)
croak ("call_Inc: expected 0 values from 'Inc', got %d\n",
count);
printf ("%d + 1 = %d\n", a, SvIV(sva));
printf ("%d + 1 = %d\n", b, SvIV(svb));
FREETMPS;
LEAVE;
}
call_pv からリターンした後で、スタック上にプッシュされた 二つのパラメータにアクセスするために、これらのアドレスを記録しておく 必要があります -- このため 二つの変数 sva と svb を使っています。
これらの値を保持する Perl スタックのエリアは、call_pv から 制御が戻るときまでに何ものかによって破壊されていることが十分に 有り得るので、こういった操作が必要になるのです。
今度は G_EVAL を使う例です。 以下は、二つの引数の差を計算する Perl サブルーチンです。 結果が負になった場合、このサブルーチンは die を呼びます。
sub Subtract
{
my ($a, $b) = @_;
die "death can be fatal\n" if $a < $b;
$a - $b;
}
これを呼ぶ C の方は、
static void
call_Subtract(a, b)
int a;
int b;
{
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(a)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
count = call_pv("Subtract", G_EVAL|G_SCALAR);
SPAGAIN;
/* Check the eval first */
if (SvTRUE(ERRSV))
{
printf ("Uh oh - %s\n", SvPV_nolen(ERRSV));
POPs;
}
else
{
if (count != 1)
croak("call_Subtract: wanted 1 value from 'Subtract', got %d\n",
count);
printf ("%d - %d = %d\n", a, b, POPi);
}
PUTBACK;
FREETMPS;
LEAVE;
}
となります。 call_Subtract が
call_Subtract(4, 5)
のように呼ばれると、以下のように表示されます。
Uh oh - death can be fatal
注意点
die を捕捉するために、G_EVAL フラグを使用しました。 このフラグを使用しないと、サブルーチン Sbutract 中にある die 文の場所でプログラムは途中終了してしまいます。
このようなコードは
if (SvTRUE(ERRSV))
{
printf ("Uh oh - %s\n", SvPV_nolen(ERRSV));
POPs;
}
Perl の書くところの以下と直接に等価です
print "Uh oh - $@\n" if $@;
PL_errgv
は、エラーを保持するシンボルテーブルのエントリーを指し示す、 型 GV *
の perl のグローバル変数です。 ですから ERRGV
は、Cプログラムににおいて $@
と等価なものを 参照します。
スタックは SvTRUE(ERRGV)
が真であるブロックの中で POPs
を 使ってポップされていることに注意してください。 これは、関数 call_* が G_EVAL|G_SCALAR をつけて起動された場合に エラーを返していて、スタックトップに undef 値があるときには常に 必要となります。 エラーを検出した後でプログラムを継続させたいので、undef を 取り除いてスタックを片付けることが重要なのです。
以下の滑稽な例について考えてみましょう。 ここでは、先の例での XS バージョンの call_Subtract を デストラクターの中で使っています。
package Foo;
sub new { bless {}, $_[0] }
sub Subtract {
my($a,$b) = @_;
die "death can be fatal" if $a < $b;
$a - $b;
}
sub DESTROY { call_Subtract(5, 4); }
sub foo { die "foo dies"; }
package main;
eval { Foo->new->foo };
print "Saw: $@" if $@; # should be, but isn't
この例では、eval {}
の内側で起きたエラーを認識するのに失敗します。 その理由はこうです: call_Subtract のコードは eval ブロックを抜ける 際にPerlが一時変数を片付ける最中に実行されます。 そして call_Subtract が G_EVAL フラグを使った call_pv を 使って実装されているので $@
をリセットするからなのです。 この結果は $@
を最も外側の検査での失敗で、エラートラップに 失敗するということです。
G_KEEPERR フラグを追加して call_Subtract の中にある call_pv 呼び出しを
count = call_pv("Subtract", G_EVAL|G_SCALAR|G_KEEPERR);
のようにすると、エラーを保存し、信頼性のあるエラーハンドリングを 取り戻します
これまでの例では、Perl サブルーチンの名前を C から呼ばれるように 扱ってきました。 ですが、ときには Perl スクリプトの中から Perl サブルーチンの名前を 指定することができないと困ることがあります。
のような Perl コードを考えてみましょう。
sub fred
{
print "Hello there\n";
}
CallSubPV("fred");
これは CallSubPV を定義する XSUB の一部です。
void
CallSubPV(name)
char * name
CODE:
PUSHMARK(SP);
call_pv(name, G_DISCARD|G_NOARGS);
今のところは、これで良いのかもしれません。 問題は、Perl サブルーチンが文字列でしか表現できないということです。 Perl 4 ではこれで十分なのですが、Perl 5 ではサブルーチンへの リファレンスや名前を持たないサブルーチンが許されています。 そういった場合に、call_sv が役に立つのです。
次の CallSubSv のコードは、CallSubPV と同一ですが、引数 name
を SV* で定義し、call_pv の代わりに call_sv を使っています。
void
CallSubSV(name)
SV * name
CODE:
PUSHMARK(SP);
call_sv(name, G_DISCARD|G_NOARGS);
fred を呼ぶのに SV を使っていますから、Perl 側では
CallSubSV("fred");
CallSubSV(\&fred);
$ref = \&fred;
CallSubSV($ref);
CallSubSV( sub { print "Hello there\n" } );
といった記法がすべて可能になります。 ご覧のように call_sv を使えば、Perl サブルーチンをかなり柔軟に 指定することができるようになります。
プログラムの後の部分で使えるように Perl サブルーチンに対応する SV (先の例では name
)に格納する必要があるのなら、SV へのポインタの コピーを格納するだけでは十分ではないということに注意すべきです。 先のプログラムが以下のようなものだったとしましょう。
static SV * rememberSub;
void
SaveSub1(name)
SV * name
CODE:
rememberSub = name;
void
CallSavedSub1()
CODE:
PUSHMARK(SP);
call_sv(rememberSub, G_DISCARD|G_NOARGS);
これがまずいという理由は、CallSavedSub1
の中で rememberSub
を 使ったときに、SaveSub1
に保持されているPerlサブルーチンをまだ 参照するかもしれない(し、しないかもしれない)ということです。 これは、特に以下のような場合に真となります。
SaveSub1(\&fred);
CallSavedSub1();
SaveSub1( sub { print "Hello there\n" } );
CallSavedSub1();
上記の SaveSub1
が実行される度に、そのパラメータに対応する SV* は存在しなくなります。 このため、
Can't use an undefined value as a subroutine reference at ...
Perl が上記のエラーメッセージを出すことが予想されます。
同様に、
$ref = \&fred;
SaveSub1($ref);
$ref = 47;
CallSavedSub1();
上記のコードを使った場合、これらのメッセージのいずれかが 出力されるでしょう(これは使っているPerlのバージョンによります)。
Not a CODE reference at ...
Undefined subroutine &main::47 called ...
変数 $ref は SaveSub1
を呼び出したときにはサブルーチン fred
を 参照するように生成されるかもしれませんが、CallSavedSub1
が 呼び出されている時点では、今や数値 47
を保持しているのです。 SaveSub1
にある元々の SV へのポインタしか保存しないので、 $ref に対するなんらかの変更はポインタ rememberSub
によって 反映され、SV* rememberSub
によって参照されるコードが実行されることが 試みられるでしょう。 しかし上記の例では、rememberSub
は整数値 47
を参照していますので、 Perl は不満を漏らすというわけです。
同様の、しかし微妙な問題を以下のプログラム片で説明します。
$ref = \&fred;
SaveSub1($ref);
$ref = \&joe;
CallSavedSub1();
CallSavedSub1
が呼び出されたときに実行する Perl サブルーチンは SaveSub1
を呼び出したときに要求した fred
ではなく、 (それがあるとして)joe
なのです。
これらの問題に対処するためには、SV の完全なコピーをとる必要があります。 以下のコードはそれを行った SaveSub2
です。
static SV * keepSub = (SV*)NULL;
void
SaveSub2(name)
SV * name
CODE:
/* Take a copy of the callback */
if (keepSub == (SV*)NULL)
/* First time, so create a new SV */
keepSub = newSVsv(name);
else
/* Been here before, so overwrite */
SvSetSV(keepSub, name);
void
CallSavedSub2()
CODE:
PUSHMARK(SP);
call_sv(keepSub, G_DISCARD|G_NOARGS);
SaveSub2
が呼び出される度に新たなSVを生成してしまうのを防ぐために、 関数はまず最初に自分が以前に呼び出されたことがあるかどうかを 確認します。 もしそれまでに呼び出されたことがなければ、新しい SV のための領域が 割り当てられ、そして Perl サブルーチンへの参照 name
が、 newSVsv
を使った操作によって変数 keepSub
へコピーされます。 その後で SaveSub2
が呼び出されたときは常に、存在するSV keepSub
が SVSetSV
を使って新しい値で上書きされます。
次に挙げるのは渡された引数を表示する Perl サブルーチンです。
sub PrintList
{
my(@list) = @_;
foreach (@list) { print "$_\n" }
}
そして、PrintList を呼ぶ call_argv の例です。
static char * words[] = {"alpha", "beta", "gamma", "delta", NULL};
static void
call_PrintList()
{
dSP;
call_argv("PrintList", G_DISCARD, words);
}
注目したいのは、この場合には、PUSHMARK
を呼ぶ必要がないということです。 call_argv 側で自動的に行なうからです。
以下のような Perl コードを考えてみましょう。
{
package Mine;
sub new
{
my($type) = shift;
bless [@_]
}
sub Display
{
my ($self, $index) = @_;
print "$index: $$self[$index]\n";
}
sub PrintID
{
my($class) = @_;
print "This is Class $class version 1.0\n";
}
}
これは配列を管理するための非常に単純なクラスを実装しています。 コンストラクター new
を除けば、一つのスタティックメソッドと一つの 仮想メソッドを宣言しています。 スタティックメソッド PrintID
は、 単純にクラス名とバージョン番号を出力します。 仮想メソッド Display
は配列の要素一つを出力します。 以下にこれを使った例を示します。
$a = Mine->new('red', 'green', 'blue');
$a->Display(1);
Mine->PrintID;
これは次のような出力をします。
1: green
This is Class Mine version 1.0
C からの Perl メソッドの呼び出しは実に直接的なものです。 以下に挙げるようなことが要求されます。
仮想メソッドのオブジェクトへの参照、もしくはスタティックメソッドの クラスの名前。
メソッドの名前。
メソッドに対するパラメータ。
以下の例は、C から PrintID
, Display
の両方のメソッドを呼び出す 仕組みを説明するための簡単なXSUBです。
void
call_Method(ref, method, index)
SV * ref
char * method
int index
CODE:
PUSHMARK(SP);
XPUSHs(ref);
XPUSHs(sv_2mortal(newSViv(index)));
PUTBACK;
call_method(method, G_DISCARD);
void
call_PrintID(class, method)
char * class
char * method
CODE:
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(class, 0)));
PUTBACK;
call_method(method, G_DISCARD);
これで PrintID
, Display
は次のようにして呼び出すことができます。
$a = Mine->new('red', 'green', 'blue');
call_Method($a, 'Display', 1);
call_PrintID('Mine', 'PrintID');
唯一注意すべきことは、スタティックメソッドと仮想メソッドの両方に おいてメソッド名はスタックを通しては渡されない、ということです -- これは call_method の第一引数として使用されます。
以下は、その時点で実行されているコンテキストを出力するちょっとした XSUB です。
void
PrintContext()
CODE:
I32 gimme = GIMME_V;
if (gimme == G_VOID)
printf ("Context is Void\n");
else if (gimme == G_SCALAR)
printf ("Context is Scalar\n");
else
printf ("Context is Array\n");
そしてこれをテストするための Perl プログラムです。
PrintContext;
$a = PrintContext;
@a = PrintContext;
出力はこうなります。
Context is Void
Context is Scalar
Context is Array
これまでのところに使った例では、すべての一時変数(call_* 関数に対してスタックを通して渡されるパラメータ、もしくはスタックを 通して関数から返される値)はコールバックの中で生成され、以下に 挙げる手法のいずれかを使って解放されていました。
call_* に対して G_DISCARD フラグを指定する。
ENTER
/SAVETMPS
- FREETMPS
/LEAVE
の組を使って陽に 破棄を行う。
これとは別の手法があります。 それは、コールバックが完了して制御を取り戻したときにはいつでも Perl に自動的に後始末をさせるというものです。 これは単に以下のような
ENTER;
SAVETMPS;
...
FREETMPS;
LEAVE;
シーケンスをコールバックの中で使うことで行なわれます (もちろん、G_DISCARD フラグは指定しません)。
この手法を使おうとするなら、非常に特定された状況においてメモリリークが 発生する可能性があることを考慮しなければなりません。 その状況を説明するには、Perl とコールバックとの間での制御の流れについて 知っておく必要があります。
本ドキュメントの最初に挙げたサンプル(エラーハンドラとイベント駆動 プログラム)は、コールバックに遭遇するような典型的な制御の流れです。 これら二つの間には非常に重要な違いがありますから、注意しましょう。
最初の例、エラーハンドラでは、制御の流れは以下の様になるでしょう。 外部ライブラリに対するインターフェースは既に作っています。 制御は以下のようにして外部ライブラリに到達できます。
perl --> XSUB --> external library
制御がライブラリにある間にエラー状況が発生します。 これに対処するためのPerlのコールバックは既に設定していますので、 それがここで実行されます。 コールバックでの処理が完了すれば、制御はPerlの元へと戻ります。 以下はそのような状況における制御の流れです。
perl --> XSUB --> external library
...
error occurs
...
external library --> call_* --> perl
|
perl <-- XSUB <-- external library <-- call_* <----+
call_* を使ったエラー処理が完了した後で、制御はほぼ即座に Perl へと戻ります。
このダイアグラムにおいて、より正確にはもっと深いスコープになります。 これは、スコープを囲む部分に戻ったり放っておいた一時変数が 解放されるようなダイアグラムの残りの部分に制御が戻ってきたのみです。
二番目の例であるイベント駆動のプログラムでは、制御の流れは以下のように なります。
perl --> XSUB --> event handler
...
event handler --> call_* --> perl
|
event handler <-- call_* <----+
...
event handler --> call_* --> perl
|
event handler <-- call_* <----+
...
event handler --> call_* --> perl
|
event handler <-- call_* <----+
この場合の制御の以下のような流れは、
event handler --> call_* --> perl
現実的なプログラムの生存期間を通じてシーケンスの繰り返しからのみ 構成されます。 これはつまり、制御は 決して そのスコープを囲む部分には 戻ってこないということです。
大きな問題っていったいなんでしょうか? そう、Perl があなたのために一時変数を用意するのを期待しているのなら、 そのために長く待たされるかもしれないということです。 Perl が一時変数を破棄するために、制御をその場所を囲んでいるスコープに 戻さなければなりません。 イベント駆動のシナリオにおいてはこれは決して起こりません。 これはつまり、 あなたのプログラムが時がたつにつれて解放されることのない一時変数を どんどん生成するということです。 こういった一時変数は幾らかのメモリを使うので、プログラムもシステムで 使えるメモリのすべてを使いきってしまうかもしれないので -- kapow!
重要な点はこうです -- コールバックの終了後に制御が(コールバックを 囲んでいる)Perl スコープに即座に戻るということを確信しているので あれば、あなたが生成したすべての一時変数を陽に破棄する必要はないのだと いうことです。 気をつけて欲しいのは、すべきことについて良く わからないことがあるのなら、整頓されたものを壊すような真似をしては いけないということです。
コールバックインターフェースを割り当てるときに現れる最も分かりづらい 潜在的な問題は、C のコールバック関数とそれと等価な Perl ルーチンとの間の マッピングをどのように格納するかということで説明することができます。
これが実際の問題になりうるのを理解するため、まず最初にコールバックが すべての C 環境においてどのようにセットアップされるのかを考えてみましょう。 典型的な C API はコールバックを登録するための関数を提供します。 この関数はその引数の一つとして関数へのポインタを期待します。 以下の例では致命的なエラーが発生したときに呼び出される C 関数を登録する仮想関数 register_fatal
を呼び出します。
register_fatal(cb1);
パラメータ cb1
は関数へのポインタなので、cb1
をプログラム中で 以下の様に定義しておかなければなりません。
static void
cb1()
{
printf ("Fatal Error\n");
exit(1);
}
ここで、register_fatal
と等価な Perl ルーチンで Perl サブルーチンを 呼ぶように変更します。
static SV * callback = (SV*)NULL;
static void
cb1()
{
dSP;
PUSHMARK(SP);
/* Call the Perl sub to process the callback */
call_sv(callback, G_DISCARD);
}
void
register_fatal(fn)
SV * fn
CODE:
/* Remember the Perl sub */
if (callback == (SV*)NULL)
callback = newSVsv(fn);
else
SvSetSV(callback, fn);
/* register the callback with the external library */
register_fatal(cb1);
コールバック pcb1
を以下の様に登録します。
# Register the sub pcb1
register_fatal(\&pcb1);
sub pcb1
{
die "I'm dying...\n";
}
C のコールバックと Perl との間のマッピングをするために、グローバル変数 callback
に格納されます。
これは単に一つのコールバックを好きなときに登録できればよい、というのなら 十分でしょう。 その一つの例は、上で説明したエラーハンドラのようなものです。 しかし忘れないで欲しいのは、register_fatal
を繰り返し呼び出すことで、 以前に登録していたコールバック関数を新しいもので 置き換えてしまうということです。
非同期ファイル入出力のライブラリに対するインターフェースが 欲しいとしましょう。 この場合、読み込み操作が終了したときに常にコールバックされるものを 登録することができるでしょう。 私たちは何かをするために、分割された Perl サブルーチンを オープンされているファイル毎に呼び出すことができます。 現状では、一度に一つのコールバックしか許していないために上の例に あるようなエラーハンドラは十分なものではありません。 私たちが必要としているのは、オープンされたファイルとそのファイルに 対応して呼び出したい Perl サブルーチンとの間のマッピングを 格納するということです。
ファイルハンドル fh
を伴った ProcessRead
という C の関数に 結び付けられた asynch_read
を持った入出力ライブラリを 考えてみましょう -- これは、その関数がファイルをオープンし、 ファイルハンドルを取得するいくつかのルーチンを提供していることを 仮定しています。
asynch_read(fh, ProcessRead)
これは以下のような形式の C の関数 ProcessRead を期待しているでしょう。
void
ProcessRead(fh, buffer)
int fh;
char * buffer;
{
...
}
このライブラリに対する Perl インターフェースを提供するためには、 パラメータ fh
と、呼び出しをしたい Perl サブルーチンとの間の マップが可能であることが必要です。 ハッシュはこのマッピングを格納するために便利な機構です。 以下のコードは可能な実装の一例です。
static HV * Mapping = (HV*)NULL;
void
asynch_read(fh, callback)
int fh
SV * callback
CODE:
/* If the hash doesn't already exist, create it */
if (Mapping == (HV*)NULL)
Mapping = newHV();
/* Save the fh -> callback mapping */
hv_store(Mapping, (char*)&fh, sizeof(fh), newSVsv(callback), 0);
/* Register with the C Library */
asynch_read(fh, asynch_read_if);
そして、asynch_read_if
は以下のようになるでしょう。
static void
asynch_read_if(fh, buffer)
int fh;
char * buffer;
{
dSP;
SV ** sv;
/* Get the callback associated with fh */
sv = hv_fetch(Mapping, (char*)&fh , sizeof(fh), FALSE);
if (sv == (SV**)NULL)
croak("Internal error...\n");
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(fh)));
XPUSHs(sv_2mortal(newSVpv(buffer, 0)));
PUTBACK;
/* Call the Perl sub */
call_sv(*sv, G_DISCARD);
}
完全のため、asynch_close
も例示します。 これはハッシュ Mapping
からエントリーを取り除く方法を示すものです。
void
asynch_close(fh)
int fh
CODE:
/* Remove the entry from the hash */
(void) hv_delete(Mapping, (char*)&fh, sizeof(fh), G_DISCARD);
/* Now call the real asynch_close */
asynch_close(fh);
このため、Perl のインターフェースは次のようになります。
sub callback1
{
my($handle, $buffer) = @_;
}
# Register the Perl callback
asynch_read($fh, \&callback1);
asynch_close($fh);
C のコールバックと Perl との間のマッピングは、このときに Mapping
という グローバルハッシュに格納されます。 ハッシュを使うことによって、登録できるコールバックの数に 制限がなくなります。
ファイルハンドルと Perl サブルーチンとのマッピングを許しているパラメータを 含んでいないコールバックによって提供されている インターフェースだとするとどうでしょう? 非同期の I/O パッケージを考えてみましょう。 コールバック関数は以下のように、buffer
パラメータのみを取ります。
void
ProcessRead(buffer)
char * buffer;
{
...
}
ファイルハンドルなしに、直接 C のコールバック関数を Perl のサブルーチンに マップする方法はありません。
このような場合に可能な方法は、Perl に対するインターフェースのように C 関数の並びをあらかじめ定義してしまうことです。 したがって、
#define MAX_CB 3
#define NULL_HANDLE -1
typedef void (*FnMap)();
struct MapStruct {
FnMap Function;
SV * PerlSub;
int Handle;
};
static void fn1();
static void fn2();
static void fn3();
static struct MapStruct Map [MAX_CB] =
{
{ fn1, NULL, NULL_HANDLE },
{ fn2, NULL, NULL_HANDLE },
{ fn3, NULL, NULL_HANDLE }
};
static void
Pcb(index, buffer)
int index;
char * buffer;
{
dSP;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(buffer, 0)));
PUTBACK;
/* Call the Perl sub */
call_sv(Map[index].PerlSub, G_DISCARD);
}
static void
fn1(buffer)
char * buffer;
{
Pcb(0, buffer);
}
static void
fn2(buffer)
char * buffer;
{
Pcb(1, buffer);
}
static void
fn3(buffer)
char * buffer;
{
Pcb(2, buffer);
}
void
array_asynch_read(fh, callback)
int fh
SV * callback
CODE:
int index;
int null_index = MAX_CB;
/* Find the same handle or an empty entry */
for (index = 0; index < MAX_CB; ++index)
{
if (Map[index].Handle == fh)
break;
if (Map[index].Handle == NULL_HANDLE)
null_index = index;
}
if (index == MAX_CB && null_index == MAX_CB)
croak ("Too many callback functions registered\n");
if (index == MAX_CB)
index = null_index;
/* Save the file handle */
Map[index].Handle = fh;
/* Remember the Perl sub */
if (Map[index].PerlSub == (SV*)NULL)
Map[index].PerlSub = newSVsv(callback);
else
SvSetSV(Map[index].PerlSub, callback);
asynch_read(fh, Map[index].Function);
void
array_asynch_close(fh)
int fh
CODE:
int index;
/* Find the file handle */
for (index = 0; index < MAX_CB; ++ index)
if (Map[index].Handle == fh)
break;
if (index == MAX_CB)
croak ("could not close fh %d\n", fh);
Map[index].Handle = NULL_HANDLE;
SvREFCNT_dec(Map[index].PerlSub);
Map[index].PerlSub = (SV*)NULL;
asynch_close(fh);
この場合、fn1
, fn2
, fn3
といった関数は呼び出される Perlサブルーチンを記憶するために使われます。 それぞれの関数は関数 Pcb
中で配列 Map
にアクセスするためと、 実際に Perl サブルーチンを呼び出すための独立した hard-wired な添え字を 保持しています。
この技法に関して、幾つかの明らかな短所があります。
第一に、前の例に比べるとプログラムがより複雑になっているということ。
第二に、同時に存在できるコールバックの数について作り付け(hard-wired)の 限界があるということです(先の例では3)。 この限界を大きくする唯一の方法は、プログラムそのものを変更して より多くの関数を使えるようにし、さらに再コンパイルするというものです。 それでもなお、関数の数を注意深く選択する限りにおいては、この方法は 実用的な解決策であり、また、一部の状況においては唯一の選択肢なのです。
まとめとして、C と Perl コールバックとの間のマッピングを格納するために 使うことのできる手法を以下に挙げました。
多くの状況で、エラーハンドラへのインターフェースと同じく、 これは十分適切な解決策となるでしょう。
C のコールバックから渡されたパラメータを区別することができなければ、 C のコールバックインターフェース関数の並びを生成して、 配列にポインタを格納する必要があるでしょう。
ハッシュは C と Perl との間のマッピングを格納するのに 最適なメカニズムです。
POP*
マクロを、Perl サブルーチンからの戻り値にアクセスすることのみに 使用するようにしたにも関らず、これらのマクロをバイパスして ST
マクロ(ST
マクロに関する記述は perlxs を参照してください)を 使ってスタックを読み取ることが可能です。
POP*
マクロが適切であるべき場合のほとんどにおける主な問題は、 それらのマクロが戻り値をシーケンシャルに処理することを 強制するということです。 これは一部のケースにおいては、値を処理する方法として最も適切な 方法ではありません。 私たちが欲しているのは、スタックに対してのアクセスをランダムな 順序で行えるということです。 ST
マクロは、XSUB をコーディングする際にこの目的のために 適切であるときに使われます。
以下に挙げたプログラム片は、セクション "Returning a list of values" に あった例で、POP*
の代わりに ST
を記録のために使っています。
static void
call_AddSubtract2(a, b)
int a;
int b;
{
dSP;
I32 ax;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(a)));
XPUSHs(sv_2mortal(newSViv(b)));
PUTBACK;
count = call_pv("AddSubtract", G_ARRAY);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
if (count != 2)
croak("Big trouble\n");
printf ("%d + %d = %d\n", a, b, SvIV(ST(0)));
printf ("%d - %d = %d\n", a, b, SvIV(ST(1)));
PUTBACK;
FREETMPS;
LEAVE;
}
注意点
ax
という変数を定義する必要があったことに注意してください。 これは、ST
マクロがその変数が存在することを期待しているからです。 XSUB の中でなければ、(すでにあるかのようにみなしてしまって)ax
を 定義する必要はなかったでしょう。
このようなコードは
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
スタックのセットアップを行うので、ST
マクロを使うことができます。
この例のオリジナルのコーディングとは異なり、戻り値は逆順で アクセスされることはありません。 このため、ST(0)
は Perl サブルーチンの戻り値の最初の 要素を参照し、ST(count-1)
は最後の要素を参照します。
既に述べてきたように、call_sv
は無名サブルーチンを起動するために 使うことができます。 しかしながら、一つの例が Perl スクリプトがどのように XSUB を起動して この操作を行うかを示しました。 C プログラムの内側でどのようにするかをお見せしましょう。
...
SV *cvrv = eval_pv("sub { print 'You will not find me cluttering any namespace!' }", TRUE);
...
call_sv(cvrv, G_VOID|G_NOARGS);
eval_pv
は無名サブルーチンをコンパイルするために 使われ、この関数は値を返します (eval_pv
の詳細は "eval_pv" in perlapi を参照してください)。 このコードリファレンスが作用してしまえば、先に挙げた例と 組み合わせることができます。
同じサブルーチンを繰り返し起動する必要がある場合もあります。 これは普通、Perl 組み込みの sort() のように、値のリストに対して動作する 関数で起こります。 sort() に比較関数を渡せますが、これは比較が必要な値の組毎に起動されます。 List::Util の first() 関数と reduce() 関数は同様なパターンに従います。
この場合、軽量コールバック API を使ってルーチンを(しばしばかなり大幅に) 高速化できます。 考え方としては、呼び出しコンテキストは作成時と破壊時に 1 回ずつしか 必要ではなく、サブルーチンはその間に任意の関数呼び出すことができます。
グローバル変数を使ってパラメータを渡すのはよくあることです (典型的には 1 パラメータ用には $_ を、あるいは 2 パラメータのためには $a と $b を) @_ よりも使われます。 (もし何をしようとしているのかが分かっているなら @_ 機構を使うことも できますが、これのための支援 API はまだありません。 これはまた、本質的に低速です。)
マクロ呼び出しのパターンは以下のようなものです:
dMULTICALL; /* Declare local variables */
I32 gimme = G_SCALAR; /* context of the call: G_SCALAR,
* G_LIST, or G_VOID */
PUSH_MULTICALL(cv); /* Set up the context for calling cv,
and set local vars appropriately */
/* loop */ {
/* set the value(s) af your parameter variables */
MULTICALL; /* Make the actual call */
} /* end of loop */
POP_MULTICALL; /* Tear down the calling context */
具体的な例としては、List::Util 1.18 の first() 関数と reduce() 関数の実装を 参照してください。 また、より古いバージョンの perl のための多重呼び出し API をエミュレートする ヘッダファイルもあります。
Paul Marquess
Special thanks to the following people who assisted in the creation of the document.
Jeff Okamoto, Tim Bunce, Nick Gianniotis, Steve Kelem, Gurusamy Sarathy and Larry Wall.
Version 1.3, 14th Apr 1997