Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Support autovivified filehandle as arguments to Perl XS routine

Question

How can I support autovivified filehandle arguments in an XS function?

I'm XS-wrapping a C function which returns a file descriptor, and I'd like to present that file descriptor as a perl filehandle argument in the manner of open(). E.g.,

myfunc(my $fh) or die "Error: $!";
do_something_with_fh($fh);

What I've done so far

Right now I'm using a perl wrapper on top of the XS function:

# -- in perl
sub myfunc {
    my $fd = _myfunc();
    return open($_[0], '+<&=', $fd) if defined($fd);
}

/* -- in XS */
SysRet
_myfunc()
    CODE:
    RETVAL = some_c_function_returning_an_fd();

    OUTPUT:
    RETVAL

This works Just Fine (tm), but, again, I'd like to move the implementation entirely into XS.

So far I've tried sv_2io on an argument typemapped as SV *, but that throws an exception on undefined scalars. I have not tried mapping the first argument to a FILE * or PerlIO * object, since I don't know how I'd "fdreopen" (if you will) those objects.

like image 449
pilcrow Avatar asked Dec 21 '12 20:12

pilcrow


1 Answers

I would keep the myfunc() wrapper in Perl, it works and shouldn't be a bottleneck.

Reimplementing open() is tricky and requires usage of undocumented/internal API. I think this is a pretty close implementation. newGVgen() and do_openn() is part of the public API but undocumented and subject to change.

void
myfunc(sv)
    SV *sv
  PPCODE:
    {
        GV *gv = newGVgen("Mypackage");
        SV *rv = sv_2mortal(newRV_noinc((SV *)gv));
        SV *fd = sv_2mortal(newSViv(some_c_function_returning_an_fd()));

        if (!do_openn(gv, "+<&=", 4, FALSE, 0, 0, NULL, &fd, 1))
            croak("Could not fdopen descriptor: '%s'", Strerror(errno)); /* or XSRETURN_NO; */

        sv_setsv(sv, rv);
        SvSETMAGIC(sv);
        XSRETURN_YES;
    }
like image 161
chansen Avatar answered Nov 09 '22 08:11

chansen