I've posted the question below on perl-xs. It seems that at least Nick I-S and me are interested in an easy way to catch Perl_croak() from within XS code without using call_xx().
I've proposed a set of macros to hide the JMPENV_* stuff, which isn't part of the public API. If nobody has objections, I'd like to add these (or similar) macros to the core (and Devel::PPPort). Marcus On 2005-01-02, at 18:30:23 +0000, Nick Ing-Simmons wrote: > Marcus Holland-Moritz <[EMAIL PROTECTED]> writes: > >I'm wondering if someone else ever wanted to do this... > > > >Deep inside my XS module I create an object and pass it to > >a function (which may pass it to other functions and so on). > >However, any of these functions may call Perl_croak(), and > >if they do, I need to destroy the object if I don't want to > >leak memory. Here's an excerpt of the original code: > > > > tag = tag_new(tagid, gs_TagTbl[tagid].vtbl); > > rv = gs_TagTbl[tagid].set(aTHX_ ptti, tag, val); > > insert_tag(ptl, tag); > > > >Calling the 'set' method in the second line may eventually > >call croak(). If it does, I just want to throw away the tag > >object and croak() again. > > > >I didn't find anything in perl(xs|guts|call|api), so I looked > >at how "eval" does it, and came up with the following macros: > > > > #define dXCPT dJMPENV; int rEtV = 0 > > > > #define XCPT_TRY_START JMPENV_PUSH(rEtV); \ > > if (rEtV == 0) > > > > #define XCPT_TRY_END JMPENV_POP; > > > > #define XCPT_CATCH if (rEtV != 0) > > > > #define XCPT_RETHROW JMPENV_JUMP(rEtV) > > > >With these macros, I can rewrite the above code as: > > > > dXCPT; > > > > tag = tag_new(tagid, gs_TagTbl[tagid].vtbl); > > > > XCPT_TRY_START { > > rv = gs_TagTbl[tagid].set(aTHX_ ptti, tag, val); > > } XCPT_TRY_END > > > > XCPT_CATCH > > { > > tag_delete(tag); > > XCPT_RETHROW; > > } > > > > insert_tag(ptl, tag); > > > >This seems to work fine, but makes use of internal API. > > Which is why I have to date avoid this and done this kind of thing > one of two ways: > A. Make the "object" a perl level object (as well) > and give the perl class a DESTROY method which discards > the C/C++ objuect. > B. Wrap the callback (your .set) in a perl XS 'cv' > and call that via call_sv(cv,G_EVAL) > and the test SvTRUE(ERRSV) I've thought of both solutions already, but both seemed like way too much overhead for what I wanted to do. > >Is this the way to do it? > > I am not entirely sure. > > >Or is there any other/better way? > > Two other ways above... > > > > >If it turns out to be correct, would it make sense to document > >it and/or add some public interface for this purpose? > > That would be good. > > > > >Marcus > -- QOTD: "Like this rose, our love will wilt and die."