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

Hi,
The perlcall documentation has a number of fine examples of an XSub retrieving a perl sub's return value. But my requirement is that the XSub then return the value that the perl sub returned (and I didn't see an example of that in the perlcall documentation).

Based on that documentation,I came up with this:
use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; SV * call_Adder(SV * a, SV * b) { dSP; I32 ax; int count; PUSHMARK(SP); XPUSHs(a); XPUSHs(b); PUTBACK; count = call_pv("Adder", G_SCALAR); SPAGAIN; SP -= count; ax = (SP - PL_stack_base) + 1; if (count != 1) croak("Big trouble\n"); /* Avoid "Attempt to free unreferenced scalar" warning */ SvREFCNT_inc(ST(0)); return ST(0); } EOC my $val = call_Adder(13,118); print $val, "\n"; my $val2 = call_Adder(14,119); print $val2, "\n"; my $val3 = call_Adder(14,8); print $val3, "\n"; sub Adder { my($a, $b) = @_; $a + $b; } __END__ Outputs (as expected): 131 133 22
As can be seen, the "call_Adder" XSub passes its arguments on to the "Adder" perl sub, and then returns the same value as "Adder" itself has returned.

Have I committed any sins with that approach ?
It varies from the perlcall examples mainly in that there's no ENTER/LEAVE and SAVETMPS/FREETMPS calls.

It seems to be working fine for me, but corrections and/or suggestions for improvement are welcome. (It's planned that this approach will eventually make it into some of my modules, so it's probably better to sort out the shortcomings *before* that happens.)

Cheers,
Rob

Replies are listed 'Best First'.
Re: [XS] Callbacks to perl
by bulk88 (Priest) on Jun 17, 2012 at 18:46 UTC
    I think you leaked ST(0). It comes from Adder already mortaled. You increased the refcount, but didn't remortal it (unless the mortal is in the C version after XSPP does its job). As I understand each sv_2mortal will put the SV once on mortal stack. Each mortal must own one notch on the refcount and it all is supposed to balance out in the end. Perl interp fatally errors if it double frees a SV. I often omit SAVE/FREETMPS, I dont omit the ENTER/LEAVE since I don't have a good understanding when its safe to omit ENTER/LEAVE. I would use a POPs rather than fix up ax and get ST() working again, smaller machine code then. I'm not sure if the count check makes sense, I think G_SCALAR will FORCE the count to be 1 or 0 (or is that 1, a immortal undef is always placed if the callee return a 0 length list?), and it will mortal and delete the excess SVs off the perl stack before giving it to you.
      I think you leaked ST(0)

      I added a wrapping of PL_sv_count to the Inline::C script:
      void wrap_count() { printf("wrap_count: %d\n", PL_sv_count); }
      If I call wrap_count() after each call to call_Adder() I find that the count has remained the same. I *think* that means that no leaking has occurred.
      Also, if I sv_2mortal(ST(0)); before returning ST(0) I get the "Attempt to free unreferenced scalar" warning again.

      I dont omit the ENTER/LEAVE since I don't have a good understanding when its safe to omit ENTER/LEAVE

      Turns out I can put them in without the script suffering any adverse effect, so I think I might do that. I could also re-instate SAVETMPS/FREETMPS if necessary, but I'll leave them out for now. (All 4 caused me some grief in my earlier attempts to get this script working, so I removed them and didn't get around to checking whether they did, in fact, really *need* to be removed.)

      I'm not sure if the count check makes sense

      Yes, it's something I've just copied verbatim from the perlcall examples, without any appreciation of it's siginificance. The error message is "Big trouble", which would be a very appropriate message if G_SCALAR is supposed to force the count as you say ;-)

      Thanks for the feedback.
      Please let me know if I'm still missing something.

      Cheers,
      Rob
        Also, if I sv_2mortal(ST(0)); before returning ST(0) I get the "Attempt to free unreferenced scalar" warning again.

        XSPP (I know your using something different), if you make a XS func with SV * as the return type, rather than void and PPCODE:, XSPP will throw in a sv_2mortal secretly on the "return" SV *. I always put " XSOPT => ' -nolinenumbers '," in my makefile.pl since the #line preprocessor that XSPP puts in drive my C debugger mad.

        I'm not sure if the count check makes sense

        Yes, it's something I've just copied verbatim from the perlcall examples, without any appreciation of it's siginificance. The error message is "Big trouble", which would be a very appropriate message if G_SCALAR is supposed to force the count as you say ;-)


        I reread the perl source code, egh, the count check makes sense, see perl.c#l2736 in perl.git and pp_hot.c#l2776 in perl.git, sometimes perl fixes up the stack, often it doesn't, I guess from reading the code. If adder() is something you wrote and control, put the count check in a assert, the runtime overhead isn't worth it. PL_sv_count tip is great. I never knew that before. I also think (its been a while since the first and last time I did it), if you leave out the PUSHMARK, the callee will inherit your XSUB's stack/@_, sometimes its what you want. I generally keep the SAVE/FREETMPS out, I know the caller/entersub will clean up the mortals for me normally. By batching more mortals together for freeing, I will presume its faster than 2 separate SV freeing sessions because of CPU caching. Of course follow the event loop warning in perlcall. The ax fixup I can't comment on.
Re: [XS] Callbacks to perl
by ikegami (Patriarch) on Jun 18, 2012 at 05:24 UTC
    The typedef for SV* includes a call to mortalise the SV, which is a postponed refcnt dec, so you need a corresponding refcnt inc. (Well, that's my guess.)
Re: [XS] Callbacks to perl
by BrowserUk (Patriarch) on Jun 17, 2012 at 16:39 UTC

    Ignore this! I was testing a different file to the one I was editing :(


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?