两个perlcall(在“存储回调上下文信息的策略”部分)和Extending and Embedding Perl(在“回调”部分中)列出了处理从XS / C调用Perl子例程的3种不同方法:
上面列出的#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?
答案 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”。