>>By the way what is the reason you do a PREINIT which does no init rather
>>than 
>>
>>CODE:
>> {
>>  char *chartext;
>>  ...
>> }
>>
>>? 
>>
>I once fell foul of the problem described in the PREINIT entry in the 
>perlxs manpage, namely: "If a variable is declared inside a CODE: 
>section it will follow any typemap code that is emitted for the input 
>parameters. This may result in the declaration ending up after C code, 
>which is C syntax error."
>
>I was very new to XS at the time (even newer than I am now ;), and was 
>confused for ages by it.  I've used PREINIT to declare all my variables 
>ever since then just to play it safe.
>
>Is there a problem with using PREINIT all the time in this way?

Don't know - but I tend to use {} after CODE: - which creates
a new C block which can declare things. 
>At this point I have:
>
>    void
>    hello(...)
>        PREINIT:
>            char    *chartext;
>
>        CODE:
>            Newz(0, chartext, 13, char);
>            strcpy(chartext, "Hello, world");
>            ST(0) = newSV(0);

             ST(0) = sv_newmortal(); // like above but does sv_2mortal for you

>            sv_usepvn(ST(0), chartext, 13);
>            XSRETURN(1);
>
>    void
>    callhello()
>        PREINIT:
>            SV *val;
>
>        CODE:
>            dSP;
>            PUSHMARK(SP);
>            PUTBACK;
>            call_pv("Foo::hello", G_SCALAR);
>            SPAGAIN;
>            val = POPs;
>            PUTBACK;
>            ST(0) = val;
>            PUTBACK;       // this one is not necessary
>            XSRETURN(1);
>
>So it seems that you can, after all, assign to ST(0) even when an xsub 
>is called with no arguments from another xsub.  I'm puzzled by that: I 
>thought that before assigning to ST(0), ..., ST(n) you had to call 
>EXTEND(SP, n + 1).  Calling EXTEND(SP, n) would suffice when the xsub is 
>called from Perl, but not when called from another xsub.  In this case 
>we are calling from another xsub; n is 0, so I thought I would have 
>needed to call EXTEND(SP, 1) first.

I think there is one free slot - but I may be wrong.

>
>There's one other problem too: The above code leaks if I call 
>callhello() a million times over in a for loop.  Where is the leak 
>coming from?

You haven't made its return value mortal.

>>
>The SAVETMPS/FREETMPS was to have the (mortal) argument that I'm passing 
>to Foo::hello free()'d; I'd forgotten that it free()'s any mortal return 
>values as well.
>
>Here's the example with hello() returning a mortal SV * that has its own 
>char * space:
>
>    void
>    hello(...)
>        PREINIT:
>            char    *chartext;
>
>        CODE:
>            Newz(0, chartext, 13, char);
>            strcpy(chartext, "Hello, world");
>            ST(0) = sv_2mortal(newSVpv(chartext, 13));
>            XSRETURN(1);
>
>    void
>    callhello()
>        PREINIT:
>            SV *val;
>
>        CODE:
>            dSP;
>            ENTER;
>            SAVETMPS;
>            PUSHMARK(SP);
>            XPUSHs(sv_2mortal(newSViv(1)));
>            PUTBACK;
>            call_pv("Foo::hello", G_SCALAR);
>            SPAGAIN;
>            val = POPs;
>            PUTBACK;
>            ST(0) = val;
>            PUTBACK;
>            FREETMPS;
>            LEAVE;
>            XSRETURN(1);
>
>It does indeed result in callhello()'s caller getting undef.
>
>So how would I avoid coming a cropper like that?  
>I want the arguments 
>that callhello() passes to hello() to be freed before callhello() 
>returns, but I don't want hello()'s return value to be free()'d then as 
>well.
>
>This seems to work:
>
>        ...
>        call_pv("Foo::hello", G_SCALAR);
>        SPAGAIN;
>        val = newSVsv(POPs);
>        PUTBACK;
>        FREETMPS;
>        LEAVE;
>        ST(0) = sv_2mortal(val);
>        PUTBACK;
>        XSRETURN(1);
>
>Is that OK 

That moral equivalent of what perl does ...


>or is there a more efficient way to do this?

Slightly.

             val = POPs;
             PUTBACK;
             SvREFCNT_inc(val);  // save it from destruction 
             FREETMPS;
             LEAVE;
             // now back in outer "scope".   
             ST(0) = sv_2mortal(val); 
             XSRETURN(1);


>
>- Steve

Reply via email to