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.
Is this the way to do it?
Or is there any other/better way?
If it turns out to be correct, would it make sense to document
it and/or add some public interface for this purpose?
Marcus
--
Bender: "Like most of life's problems, this one can be solved with bending."