5

perlcall(「コールバックコンテキスト情報を格納するための戦略」セクション)とPerlの拡張と埋め込み(「コールバック」セクション)の両方に、XS/CからのPerlサブルーチンの呼び出しを処理する3つの異なる方法がリストされています。

  1. すぐに:XS呼び出し
  2. 延期:後で使用するためにサブ参照をSV*として保存します
  3. 複数:後で使用するためにn個のサブ参照を保存します

上記の#3の例と詳細では、XSのハッシュを使用してサブ参照を特定のC関数に関連付けていますが、これらは適切ではない固定数のC関数を事前定義しています。

オプションの引数を持つコールバック/関数ポインターを使用するCライブラリへのXSインターフェイスに取り組んでいます。例:

  blah(custom_type *o, void (*func) (void *data, int more_data), const void * data);

このライブラリのCblahは、渡されたデータとともに渡された関数を呼び出すことになります。

可能であれば、CAPIからPerlへの1対1のマッピングを行いたいと思います。例えば

  blah($o, \&func, $data);

現在、上記の#2がありますが、blah()をもう一度呼び出すと、保存されたSV*が上書きされます。

上記の#3をどのように実装しますか?

4

2 に答える 2

1

これは私が思いついた解決策です:

このCライブラリのほとんどのコールバックは、ユーザーが指定したvoid *を受け取り、それを最初の引数として渡します。そこで、SV*とユーザー提供のデータを構造体に保存します。

typedef struct __saved_callback {
    SV   *func;
    void *data;
} _saved_callback;

私のXS関数は_saved_callback構造体を割り当て、それをPerlサブ参照とそのユーザーが想定するデータを使用してcall_perl_sub()への最初の引数として渡します。

void
blah(obj, func, data)
    whatever *obj
    void *func
    void *data
    CODE:
        _saved_callback *sc = NULL;
        Newx(sc, 1, _saved_callback);
        sc->func = (SV *)func;
        sc->data = data;
        blah(obj, call_perl_sub, sc);

次に、Perlサブリファレンスを呼び出します(ユーザー指定のデータ引数のスタック操作を省略しました)。

void call_perl_sub(void *data) {
    dSP;
    int count;
    _saved_callback *perl_saved_cb = data;

    count = call_sv(perl_saved_cb->func, G_DISCARD);
    if ( count != 0 )
        croak("Expected 0 value got %d\n", count);
}
于 2009-12-12T15:40:05.780 に答える