Perl newXS() with closure added

299 views Asked by At

I want to embed Perl in a c++ application and am looking for a method to call into c++ from perl via newXS(). Apart from the function pointer I need the associate a custom pointer to the CV created by newXS(). The pointer contains a C++ context. I dont want to use globals for this. Is there a common way to do this?

On a wider scope the question is maybe weather there is the possibility to add a closure to the CV created by newXS() and how to reference it when the c function is called that was registered with it. CvPADLIST() would seem the perfect place, however for XSubs it seems to be invalid to use when PERL_IMPLICIT_CONTEXT is set (comment in the beginning of perl's pad.c. Can it maybe be ignored?). Is there some other place I can put CV local data?

3

There are 3 answers

0
nwellnhof On BEST ANSWER

There's an ANY slot in CV that can be used for custom data and accessed with CvXSUBANY(cv). For example:

CvXSUBANY(cv).any_ptr = my_ptr;

This slot is normally used to store the index for XS ALIASes and the function pointer for XS INTERFACEs.

0
Konrad Eisele On

One possibility is the attach a PERL_MAGIC_ext magic to the SV as described in perlguts:

int  m_free (pTHX_ SV *sv, MAGIC* mg){ ... }
STATIC MGVTBL my_vtbl = { 0, 0, 0, 0, m_free, 0, 0, 0 };
struct ctx;

XS(XS_some_func)
{
    ...
    MAGIC *mg;
    if ((mg = mg_findext((SV*)cv, PERL_MAGIC_ext, &my_vtbl))) {
        ctx *priv = (ctx *)mg->mg_ptr;
    }
    ...
}

And assigning the magic when creating CV via newXS():

   ctx c;
   ...
   CV *cv = newXS(index, XS_some_func, __FILE__);
   MAGIC *mg = sv_magicext((SV *)cv,
                            0,
                            PERL_MAGIC_ext,
                            &my_vtbl,
                            (const char*)&c,
                            sizeof(c));
4
amon On

The simplest (and most likely best) approach would probably be to make the context explicit – expose an object oriented API and use methods instead of functions. When in Perl code a new instance of the class is created you put the context into that object. When your XSUB is called as a method on that object, it will receive the context as first parameter (i.e. ST(0)).

That is basically equivalent to melpomene's comment from the XS/C++ perspective, but does not require the extra wrapper closure.

If only one context per process exists, using global variables would also be legitimate – perhaps a necessary evil. Compare also Safely storing static data in XS.

I know of no mechanism to directly associate extra data with xsubs. It may be possible to pull of some magic with the CV, but that sounds unnecessarily complicated unless you can't afford to put your context into a Perl object.