Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Recursing in XS?

by the.jxc (Novice)
on Apr 19, 2013 at 05:49 UTC ( #1029459=perlquestion: print w/replies, xml ) Need Help??
the.jxc has asked for the wisdom of the Perl Monks concerning the following question:

My question: How from within XS do I recursively (and efficiently) call my own XS function?

I can see call_sv and it various variants, by which I can call a Perl function from XS. But how do I call myself?

I have a nasty little parser that I am migrating from PP to XS, and it needs to recurse... help please!

Replies are listed 'Best First'.
Re: Recursing in XS?
by syphilis (Chancellor) on Apr 19, 2013 at 06:57 UTC
    Here's an XS file for a module and package My::Mod.
    It contains a function named foo() that recursively calls itself until the supplied integer argument has been incremented to 20 (whereupon it returns the value '20').
    If the supplied integer argument is >= 20, it returns that value immediately ... and if the supplied integer argument is a *lot* less than 20, then it might take a while to complete.
    #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int foo(int x) { if(x >= 20) return x; x++; x = foo(x); } MODULE = My::Mod PACKAGE = My::Mod PROTOTYPES: DISABLE int foo (x) int x
Re: Recursing in XS?
by salva (Abbot) on Apr 19, 2013 at 07:41 UTC
    break the XS code in two layers: in one side a set of C functions implementing the parser logic and on the other side the XS wrapping code (you can put all the code in the XS file, if you wish). That way, from you C code, you can call the C functions directly, without going through Perl.

    If you have several XS modules and want to call from one into other, you may like to use Module::CAPIMaker, that provides an efficient and portable way to expose a C API from a module.

Re: Recursing in XS?
by bulk88 (Priest) on Apr 20, 2013 at 04:28 UTC
    use call_sv or call_pv to call yourself again. You can also do the hackish
    PUSHMARK(SP); PUSHs(somesv); PUTBACK; XS_Foo__Bar_Func(aTHX_ cv); SPAGAIN; retval = POPs; /* did we get 1 elem? this code just assumes*/ /* ?????? */
    Which bypasses the Interp almost completely and is more efficient. The problem with the above is, if the child XSUB being called raw dies/croaks, the error message will put the blame as the parent XSUB since the global state info wasn't updated in the interp. Also note the parent XSUB is passing its CV to the child XSUB, so ALIAS/XSANY will break if the parent isn't the child and the child relies on XSANY/ALIAS to operate. How to calculate the number of items XS_Foo__Bar_Func returned IDK. It probably involves the delta between C auto SV * mark and SP and +0, +1 or -1 SV*. Another thing, Perl uses malloc memory to implement pure perl opcode recursion, XSUBs use C stack memory. You might get an access vio/segv on deep recursion instead of a descriptive fatal error in pure perl.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1029459]
Approved by Corion
[stevieb]: ffs... an hour I've been trying to get a Pi to communicate I2C to an Arduino. Had to slow down the communication channel. Sigh

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2017-06-22 22:31 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (531 votes). Check out past polls.