develooper Front page | perl.perl5.porters | Postings from January 2005

Add exception handling macros for XS code (was: Re: CatchingPerl_croak() from XS)

Thread Next
From:
Marcus Holland-Moritz
Date:
January 2, 2005 13:07
Subject:
Add exception handling macros for XS code (was: Re: CatchingPerl_croak() from XS)
Message ID:
20050102220730.1d08b7a3@r2d2
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 <mhx-perl@gmx.net> 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."

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About