代码之家  ›  专栏  ›  技术社区  ›  Adam Flott

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

  •  5
  • Adam Flott  · 技术社区  · 16 年前

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

    1. 立即:XS呼叫
    2. 延迟:将子引用保存为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 API。例如

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

    目前,我在上面有2,但是对blah()的另一个调用将覆盖保存的SV*。

    我将如何实现上面的3?

    2 回复  |  直到 16 年前
        1
  •  1
  •   Adam Flott    16 年前

    这就是我提出的解决方案:

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

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

    我的xs函数将分配一个_saved_回调结构,并将其作为第一个参数传递,以使用perl子引用和用户假定的数据调用_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);
    }
    
        2
  •  0
  •   tsee    16 年前

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

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

    • 你可能能摆脱的是用所需的签名编写你自己的C函数,并将其传递给C级blah。然后在XS代码中,获取Perl回调(它作为Perl标量(SV)传入)。请参见“Perldoc Perlapi”。寻找svtype和svt_ux位。)将这些sv存储在某个地方。然后,当您希望C库进行回调时,您的C回调将获得控制权,并可以调度到Perl级回调。参见“perldoc perlcall”。

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