5

perlcall (在“存储回调上下文信息的策略”部分)和扩展和嵌入 Perl(在“回调”部分)列出了 3 种不同的方法来处理从 XS/C 调用 Perl 子例程:

  1. 立即:XS 调用
  2. Deferred:将子 ref 保存为 SV* 以供以后使用
  3. 多个:保存 n 个子参考以供以后使用

上面 #3 列出的示例和详细信息使用 XS 中的哈希将 sub ref 与特定的 C 函数相关联,但它们预定义了固定数量的 C 函数,这是不够的。

我正在使用带有可选参数的回调/函数指针的 C 库的 XS 接口,例如:

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

这个库中的 C blah 最终将调用传递给它的函数以及传入的数据。

如果可能的话,我想做一个 C API 到 Perl 的一对一映射。例如

  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 结构并将其作为第一个参数传递给 call_perl_sub() 以及 Perl 子引用和该用户假定的数据。

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 回答
0

很遗憾,我不能给你一个完整的答案。相反,让我给你一些建议:

  • 您不能将 Perl 代码引用(技术上是 CV*)映射到 C 函数。Perl 代码引用实际上是数据(OP 树),附加了一些函数指针,用于在每个 OP 中执行特定的工作。(参见perl guts以了解有关 OP 结构的详细信息)。

  • 您可能能够摆脱的是编写您自己的具有所需签名的 C 函数,将其传递给 C 级等等。然后在您的 XS 代码中,获取 Perl 回调(作为 Perl 标量 (SV) 传入)。请参阅“perldoc perlapi”。查找 svtype 和 SVt_* 位。)将这些 SV 存储在某处。然后,当您希望 C 库执行回调时,您的 C 回调将获得控制权并可以分派给您的 Perl 级回调。参照。“perldoc perlcall”。

祝你好运。你将要做一些奇怪的事情。

于 2009-12-11T07:43:29.687 回答