在 XS 中为 C 库注册多个 Perl 子引用
Posted
技术标签:
【中文标题】在 XS 中为 C 库注册多个 Perl 子引用【英文标题】:Registering multiple Perl sub references for a C library in XS 【发布时间】:2010-12-25 11:16:26 【问题描述】:perlcall(在“存储回调上下文信息的策略”部分)和Extending and Embedding Perl(在“回调”部分)列出了 3 种不同的方式来处理从 XS/C 调用 Perl 子例程:
-
立即:XS 调用
延迟:将子引用保存为 SV* 以供以后使用
多个:保存 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?
【问题讨论】:
"保存我的 Perl 代码参考...以便稍后调用"?是什么触发了后来的电话?目前尚不清楚您遇到问题的部分。重新“多个”,你有它为一个工作并想要扩展它吗?或者这只是尚未完成的整个任务的一部分? 我已经更新了这个问题,希望能更清楚 【参考方案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);
【讨论】:
注意:我确信有更好的解决方案,但我还在学习 XS。【参考方案2】:很遗憾,我不能给你一个完整的答案。相反,让我给你一些建议:
您不能将 Perl 代码引用(技术上是 CV*)映射到 C 函数。 Perl 代码引用实际上是数据(OP 树),附加了一些函数指针,用于在每个 OP 中执行特定的工作。 (有关 OP 结构的详细信息,请参阅 perl guts illustrated)。
您可能能够摆脱的是编写您自己的具有所需签名的 C 函数,将其传递给 C 级等等。然后在您的 XS 代码中,获取 Perl 回调(作为 Perl 标量 (SV) 传入)。请参阅“perldoc perlapi”。查找 svtype 和 SVt_* 位。)将这些 SV 存储在某处。然后,当您希望 C 库执行回调时,您的 C 回调将获得控制权并可以分派给您的 Perl 级回调。参照。 “perldoc perlcall”。
祝你好运。你即将做出奇怪的事情。
【讨论】:
另外,让我补充一点,我的回答与我认为您正在尝试做的事情有关。我不是 100% 相信我正确理解了你的目标。 (参见 ysth 对您的问题的评论。) tsee:只有 perl 级 CV 存储为 optree,c 级 CV 不存储。 perlcall 列出了各种回调 c 到 perl 策略,许多核心函数也使用它。例如sort 使用来自 c 的可变参数调用 perl subs。 Adam Flott 的解决方案是通用的策略,但我没有仔细检查过。 rurban:你指出这一点很有趣。我写这个答案已经有一年了,从那时起我学到了很多关于内部的知识。好奇地阅读我的这个旧的半答案:)以上是关于在 XS 中为 C 库注册多个 Perl 子引用的主要内容,如果未能解决你的问题,请参考以下文章
在 perl 中如何在不使用 XS 的情况下写入调用者的变量?
如何在 Rails 4 中为多对多关联制作带有子表单的表单?
在 perl 中使用 TEXT::CSV_XS 模块将 CSV 文件转换为哈希结构
/usr/bin/perl: symbol lookup error: xxxxx: undefined symbol: Perl_xs_handshake