【发布时间】:2012-09-25 14:58:07
【问题描述】:
我正在尝试编写一些 XS 代码,将库中的片段公开给
Perl 代码作为可以写入的流接口。这
get_stream 下面的函数应该是一个构造函数
准备并返回一个 PerlIO 对象。我想我只需要
Write 和 Close 方法,所以我将所有其他函数槽留空。
typedef struct {
struct _PerlIO base;
mylib_context* ctx;
} PerlIOmylib;
/* [...] */
PERLIO_FUNCS_DECL(PerlIO_mylib_funcs) = {
.fsize = sizeof(PerlIO_funcs),
.name = "mylib",
.size = sizeof(PerlIOmylib,
.Write = mylib_write,
.Close = mylib_close,
};
/* XS below */
PerlIO*
get_stream (SV* context_obj)
CODE:
mylib_context* ctx = (mylib_context*) SvIV (SvRV (context_obj));
PerlIO* f = PerlIO_allocate (aTHX);
f = PerlIO_push (aTHX, f, PERLIO_FUNCS_CAST(&PerlIO_mylib_funcs), "a", NULL);
PerlIOSelf(f, PerlIOmylib)->ctx = ctx;
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
RETVAL = f;
OUTPUT:
RETVAL
当我像这样使用提供的界面时......
{
my $fh = MyLib::get_stream($lib_ctx);
print $fh "x" x 300;
}
...mylib_write 函数被调用,所以我还没有完全
到目前为止搞砸了。 (我通过插入调试 printf 验证了这一点
声明。)但是,我希望 PerlIO 对象在
$fh 超出范围,就像正常工作一样
由open 创建的文件句柄。但目前,mylib_close
函数仅在解释器关闭期间调用。
直接调用close 可以正常工作,将$fh 设置为undef 可以
不是。
更新:按照 ikegami 的建议,我使用了 Devel::Peek::Dump 和 sv_dump
并发现返回的句柄get_stream 函数是“RV”
它指向SV = PVGV(...)。 glob (PVGV) 有它的
参考计数器设置为 3,这似乎不正确。
我加了
CLEANUP:
SvREFCNT_dec (SvRV (ST(0)));
SvREFCNT_dec (SvRV (ST(0)));
治标不治本:$fh 时调用close 函数
在块的末尾超出范围。但我还是不太懂
了解根本问题。
这是为 OUTPUT 部分生成的 C 代码:
ST(0) = sv_newmortal();
{
GV *gv = newGVgen("MyLib");
if (do_open(gv, "+<&", 3, FALSE, 0, 0, RETVAL) )
sv_setsv(ST(0), sv_bless(newRV((SV*)gv), gv_stashpv("MyLib",1)));
else
ST(0) = &PL_sv_undef;
}
XSRETURN(1);
GV 的引用计数如何以 3 结束?
【问题讨论】:
-
ug,同一篇文章中的全新问题?