在XS中为C库注册多个Perl子引用

时间:2009-12-10 22:38:09

标签: perl xs

两个perlcall(在“存储回调上下文信息的策略”部分)和Extending and Embedding Perl(在“回调”部分中)列出了处理从XS / C调用Perl子例程的3种不同方法:

  1. 立即:XS致电
  2. 延迟:将子参考保存为SV *以供日后使用
  3. 多个:保存n个子参考以供日后使用
  4. 上面列出的#3的示例和细节在XS中使用散列将子ref与特定的C函数相关联,但它们预定义了固定数量的C函数,这是不够的。

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

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

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

    如果可能的话,我想将C API的一对一映射到Perl。 e.g。

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

    目前,我上面有#2,但是另一次调用blah()会覆盖保存的SV *。

    我如何实施上述#3?

2 个答案:

答案 0 :(得分:1)

这是我提出的解决方案:

此C库中的大多数回调将使用用户提供的void *并将其作为第一个参数传递。所以我将SV *和用户提供的数据保存在struct:

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);
}

答案 1 :(得分:0)

不幸的是,我无法给你一个完整的答案。相反,让我给你一些指示:

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

  • 你可以逃脱的是使用所需的签名编写自己的C函数,将其传递给C级别的blah。然后在您的XS代码中,获取Perl回调(它作为Perl标量(SV)传入)。见“perldoc perlapi”。查找svtype和SVt_ *位。)将这些SV存储在某处。然后,当您希望C库执行回调时,您的C回调将获得控制权并可以调度到您的Perl级回调。参看“perldoc perlcall”。

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