私は、書き込み可能なストリーム インターフェイスとして、ライブラリの一部を Perl コードに公開する XS コードを書き込もうとしています。以下の
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
関数が呼び出されるので、これまでのところ完全に失敗していません。$fh
(debug printf ステートメントを挿入することでこれを確認しました。) しかし、PerlIO オブジェクトがスコープ外になったときに閉じられるようにしたいと思います
open
。しかし、現時点では、このmylib_close
関数はインタープリターのシャットダウン中にのみ呼び出されます。
直接呼び出すとclose
正常に機能しますが、に設定$fh
するとundef
機能しません。
更新:池上のアドバイスに従って、 と を使用Devel::Peek::Dump
しsv_dump
たところ、返されたハンドルget_stream
関数が を指す「RV」であることがわかりましたSV = PVGV(...)
。グロブ ( PVGV
) の参照カウンターが 3 に設定されていますが、これは正しくないようです。
追加した
CLEANUP:
SvREFCNT_dec (SvRV (ST(0)));
SvREFCNT_dec (SvRV (ST(0)));
これにより症状が治り
ます。ブロックの最後で範囲外になるclose
と、関数が呼び出されます。$fh
しかし、私はまだ根本的な問題をよく理解していません。
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 になるのですか?