amo*_*mon 9 c perl destructor perl-xs xs
我正在写一个XS模块.我分配了一些资源(例如malloc()或者SvREFCNT_inc()),然后执行一些涉及Perl API的操作,然后释放资源.这在普通的C中很好,因为C没有例外,但是使用Perl API的代码可能会croak()阻止正常的清理和泄漏资源.因此,除了相当简单的情况外,似乎不可能编写正确的XS代码.
当我croak()自己可以清理到目前为止分配的任何资源时,我可能会调用croak()直接的函数来回避我编写的任何清理代码.
伪代码来说明我的担忧:
static void some_other_function(pTHX_ Data* d) {
...
if (perhaps) croak("Could not frobnicate the data");
}
MODULE = Example PACKAGE = Example
void
xs(UV n)
CODE:
{
/* Allocate resources needed for this function */
Data* object_graph;
Newx(object_graph, 1, Data);
Data_init(object_graph, n);
/* Call functions which use the Perl API */
some_other_function(aTHX_ object_graph);
/* Clean up before returning.
* Not run if above code croak()s!
* Can this be put into the XS equivalent of a "try...finally" block?
*/
Data_destroy(object_graph);
Safefree(object_graph);
}
Run Code Online (Sandbox Code Playgroud)
那么如何安全地清理XS代码中的资源呢?如何注册在抛出异常时运行的析构函数,或者当我从XS代码返回到Perl代码时?
到目前为止我的想法和发现:
我可以创建一个在析构函数中运行必要清理的类,然后创建一个包含此类实例的凡人SV.在未来的某个时刻,Perl将释放该SV并运行我的析构函数.然而,这似乎相当倒退,必须有一个更好的方法.
XSAWYERX的XS乐趣小册子似乎讨论DESTROY连篇累牍的方法,但并非源于异常的处理中 XS码.
LEONT的Scope::OnExit模块使用XS代码SAVEDESTRUCTOR()和SAVEDESTRUCTOR_X()宏.这些似乎没有记录.
在Perl的API列表save_destructor()和save_destructor_x()功能公开,但没有证件.
声明和宏,Perl的scope.h标题(包含perl.h),没有任何进一步的解释.从上下文和代码判断,是一个函数指针和一个将被传递给的void指针._X版本用于使用宏参数声明的函数.SAVEDESTRUCTOR(f,p)SAVEDESTRUCTOR_X(f,p)Scope::OnExitfpfpTHX_
我是否在正确的轨道上?我应该酌情使用这些宏吗?他们介绍了Perl版本?是否有关于其使用的进一步指导?什么时候触发了析构函数?据推测,在涉及到一个点FREETMPS或LEAVE宏?
经过进一步的研究,事实证明,SAVEDESTRUCTOR事实证明 - 在perlguts而不是perlapi.那里记录了确切的语义.
因此,我认为它SAVEDESTRUCTOR应该被用作清理的"最终"块,并且足够安全和稳定.
摘自perlguts中的本地化更改,讨论了{ local $foo; ... }块的等价物:
有一种方法可以通过Perl API从C实现类似的任务:创建一个伪块,并安排一些更改在它结束时自动撤消,无论是显式还是通过非本地退出(通过die( )).阿块样构建体通过一对创建
ENTER/LEAVE宏(见在perlcall返回一个标量).可以专门为某些重要的本地化任务创建这样的构造,或者可以使用现有的构造(如封闭Perl子例程/块的边界,或者用于释放TMP的现有对).(在第二种情况下,额外本地化的开销几乎可以忽略不计.)请注意,任何XSUB都自动包含在ENTER/LEAVEpair中.在这样的伪块内,可以使用以下服务:
[...]
SAVEDESTRUCTOR(DESTRUCTORFUNC_NOCONTEXT_t f, void *p)在结束伪块的函数
f被调用,唯一的参数p.
SAVEDESTRUCTOR_X(DESTRUCTORFUNC_t f, void *p)在伪块结束时,
f使用隐式上下文参数(如果有)调用该函数,并且p.
该节还列出了几个专门的析构函数,喜欢SAVEFREESV(SV *sv)和SAVEMORTALIZESV(SV *sv)可能比过早更正确sv_2mortal()在某些情况下.
这些宏已基本上可用,因为它们永远有效,至少是Perl 5.6或更早版本.
| 归档时间: |
|
| 查看次数: |
163 次 |
| 最近记录: |