halfcountplus has asked for the wisdom of the Perl Monks concerning the following question:

I'm turning some Inline::C modules into the more orthodox package format produced by h2xs and learning as I go. I just hit a problem when compiling some utility functions (i.e., stuff prior to the MODULE line) whereby there were complaints about 'my_perl' and various API types being undeclared.

In proper cargo cult style, I contemplated the #includes in relation to the source from a popular CPAN module, and noticed the boilerplate generated by h2xs has:

#define PERL_NO_GET_CONTEXT

Which is not in my example CPAN module, so I threw a dart and commented it out. Joy: the compile now goes fine (although I'll have to wait until later this morning to test whether everything will truly hang together properly).

I don't have the perl source at hand, so I'm wondering what this is about. It's not used in the perldoc examples (xs, xstut, etc), and searching the web just revealed various obscure bug reports where the solution was the same ("comment that out"). There are no references here on perl monks, but I'm hoping one of you can offer a brief explanation.

Replies are listed 'Best First'.
Re: Significance of #define PERL_GET_NO_CONTEXT in XS
by dave_the_m (Monsignor) on Mar 13, 2014 at 13:24 UTC
    PERL_NO_GET_CONTEXT makes your XS code more efficient on threaded perls, but you then have to write your XS code in such a way as to work with it.

    On threaded (or more accurately, MULTIPLICITY) perls, all the interpreter state is collected into a single structure which is accessed via the my_perl local var; so for example you have

    #define PL_stack_sp my_perl->Istack_sp
    Under MULTIPLICITY, most perl API functions take an extra initial my_perl argument, which you have to provide. Within perl core itself, this is handled by the pTHX and aTHX macros, which declare the extra arg, and pass that arg down to lower-level functions.

    However, if your caller didn't provide my_perl, you have to retrieve it yourself, e.g. from thread-local storage (which may be relatively slow). In the absence of PERL_NO_GET_CONTEXT, every API function call is defined in such a way that it does the (slow) retrieve of my_perl before calling that function. So it takes care of the details for you, but slowly.

    See Background and PERL_IMPLICIT_CONTEXT for more info.

    Dave.

      Thanks Dave. Thus far I've ignored the stuff in guts beyond XSUBS. Anyway, the dTHX option seems to be working out.

      I take it there's no point in defining PERL_GET_NO_CONTEXT if MULTIPLICITY is not defined, and one could therefore do:
      #ifdef MULTIPLICITY #define PERL_GET_NO_CONTEXT 1 #endif
      Would that ensure that PERL_GET_NO_CONTEXT gets defined whenever (and only whenever) it's relevant ?

      Update: Heh ... for one thing, MULTIPLICITY is not defined prior to the inclusion of the standard XS headers, so we can't use that.
      I guess we can have the Makefile pass another symbol (iff $Config{usemultiplicity} is 'define').
      Or just define PERL_GET_NO_CONTEXT, and not concern ourselves with whether perl was even built with "usemultiplicity".

      Cheers,
      Rob
        Or just define PERL_GET_NO_CONTEXT, and not concern ourselves with whether perl was even built with "usemultiplicity"
        That's the thing to do. On unthreaded builds etc, the macros will all just Do The Right Thing (which is usually to do nothing).

        To further elaborate, consider the following snippet of XS code:

        #define PERL_NO_GET_CONTEXT sv_foo(a, b, c);
        On a threaded/MULTIPLICITY build, it would macro-expand to:
        Perl_sv_foo(my_perl, a, b, c);
        Remove the PERL_NO_GET_CONTEXT and, depending on platform (this is Linux), it might expand to something like:
        Perl_sv_foo(((PerlInterpreter *)pthread_getspecific(PL_thr_key)), a, b, c);

        On a non-threaded build, it would expand to the following, regardless of whether PERL_NO_GET_CONTEXT is present:

        Perl_sv_foo(a, b, c);

        The dTHX macro basically expands to

        PerlInterpreter * my_perl = (PerlInterpreter *)pthread_getspecific(PL_thr_key);
        So it's more efficient to just calculate my_perl once per function rather than for every function call, but it's even better to get your caller to pass it to you. So declare your functions as say Foo(pTHX_ int a, int b) and call them as Foo(aTHX_ 1, 2);

        Dave.