#define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
+/* --- Threads and multiplicity -------------------------------------------- */
+
+#ifndef NOOP
+# define NOOP
+#endif
+
+#ifndef dNOOP
+# define dNOOP
+#endif
+
+#ifndef SU_MULTIPLICITY
+# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
+# define SU_MULTIPLICITY 1
+# else
+# define SU_MULTIPLICITY 0
+# endif
+#endif
+#if SU_MULTIPLICITY && !defined(tTHX)
+# define tTHX PerlInterpreter*
+#endif
+
+#if SU_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV))
+# define SU_THREADSAFE 1
+# ifndef MY_CXT_CLONE
+# define MY_CXT_CLONE \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
+ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+# endif
+#else
+# define SU_THREADSAFE 0
+# undef dMY_CXT
+# define dMY_CXT dNOOP
+# undef MY_CXT
+# define MY_CXT su_globaldata
+# undef START_MY_CXT
+# define START_MY_CXT STATIC my_cxt_t MY_CXT;
+# undef MY_CXT_INIT
+# define MY_CXT_INIT NOOP
+# undef MY_CXT_CLONE
+# define MY_CXT_CLONE NOOP
+#endif
+
/* --- Stack manipulations ------------------------------------------------- */
#ifndef SvCANEXISTDELETE
return depth;
}
-/* --- Unwind stack -------------------------------------------------------- */
+/* --- Global data --------------------------------------------------------- */
+
+#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
typedef struct {
I32 cxix;
I32 items;
-} su_ud_unwind;
+ SV **savesp;
+ OP fakeop;
+} my_cxt_t;
+
+START_MY_CXT
+
+/* --- Unwind stack -------------------------------------------------------- */
STATIC void su_unwind(pTHX_ void *ud_) {
- su_ud_unwind *ud = (su_ud_unwind *) ud_;
- OP fakeop;
- I32 cxix = ud->cxix;
- I32 items = ud->items - 1;
- I32 gimme, mark;
+ dMY_CXT;
+ I32 cxix = MY_CXT.cxix;
+ I32 items = MY_CXT.items - 1;
+ SV **savesp = MY_CXT.savesp;
+ I32 mark;
+
+ if (savesp)
+ PL_stack_sp = savesp;
if (cxstack_ix > cxix)
dounwind(cxix);
PL_stack_sp--;
mark = PL_markstack[cxstack[cxix].blk_oldmarksp];
-
- gimme = GIMME_V;
- if (gimme == G_SCALAR) {
- *PL_markstack_ptr = PL_stack_sp - PL_stack_base;
- PL_stack_sp += items;
- } else {
- *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items;
- }
+ *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items;
SU_D({
+ I32 gimme = GIMME_V;
PerlIO_printf(Perl_debug_log,
"%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n",
- ud, cxix,
+ &MY_CXT, cxix,
gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar",
items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark);
});
PL_op = PL_ppaddr[OP_RETURN](aTHX);
*PL_markstack_ptr = mark;
- fakeop.op_next = PL_op;
- PL_op = &fakeop;
-
- Safefree(ud);
+ MY_CXT.fakeop.op_next = PL_op;
+ PL_op = &(MY_CXT.fakeop);
}
/* --- XS ------------------------------------------------------------------ */
-#define SU_GET_LEVEL(A) \
- if (items > A) { \
- SV *lsv = ST(A); \
- if (SvOK(lsv)) \
- level = SvIV(lsv); \
- if (level < 0) \
- XSRETURN(0); \
- } \
- if (level > cxstack_ix) \
- level = cxstack_ix;
+#define SU_GET_LEVEL(A) \
+ STMT_START { \
+ if (items > A) { \
+ SV *lsv = ST(A); \
+ if (SvOK(lsv)) \
+ level = SvIV(lsv); \
+ if (level < 0) \
+ XSRETURN(0); \
+ } \
+ if (level > cxstack_ix) \
+ level = cxstack_ix; \
+ } STMT_END
+
+#define SU_GET_CONTEXT(A, B) \
+ STMT_START { \
+ if (items > A) { \
+ SV *lsv = ST(B); \
+ if (SvOK(lsv)) \
+ level = SvIV(lsv); \
+ if (level < 0) \
+ level = 0; \
+ else if (level > cxix) \
+ level = cxix; \
+ } \
+ } STMT_END
#define SU_DOPOPTOCX(t) \
STMT_START { \
I32 i, cxix = cxstack_ix, level = 0; \
- if (items) { \
- SV *lsv = ST(0); \
- if (SvOK(lsv)) \
- level = SvIV(lsv); \
- if (level < 0) \
- level = 0; \
- else if (level > cxix) \
- level = cxix; \
- } \
+ SU_GET_CONTEXT(0, 0); \
for (i = cxix - level; i >= 0; --i) { \
if (CxTYPE(&cxstack[i]) == t) { \
ST(0) = sv_2mortal(newSViv(cxix - i)); \
#else
dXSARGS;
#endif
- I32 level = 0, cxix = cxstack_ix;
- su_ud_unwind *ud;
+ dMY_CXT;
+ I32 cxix = cxstack_ix, level = 0;
+
PERL_UNUSED_VAR(cv); /* -W */
PERL_UNUSED_VAR(ax); /* -Wall */
- if (items) {
- SV *lsv = ST(items - 1);
- if (SvOK(lsv))
- level = SvIV(lsv);
- if (level < 0)
- level = 0;
- else if (level > cxix)
- level = cxix;
- }
+
+ SU_GET_CONTEXT(0, items - 1);
cxix -= level;
do {
PERL_CONTEXT *cx = cxstack + cxix;
case CXt_SUB:
case CXt_EVAL:
case CXt_FORMAT:
- /* pp_entersub will try to sanitize the stack - screw that, we're insane */
- if (GIMME_V == G_SCALAR)
- PL_stack_sp = PL_stack_base + TOPMARK + 1;
- Newx(ud, 1, su_ud_unwind);
- ud->cxix = cxix;
- ud->items = items;
- SAVEDESTRUCTOR_X(su_unwind, ud);
+ MY_CXT.cxix = cxix;
+ MY_CXT.items = items;
+ /* pp_entersub will want to sanitize the stack after returning from there
+ * Screw that, we're insane */
+ if (GIMME_V == G_SCALAR) {
+ MY_CXT.savesp = PL_stack_sp;
+ /* dXSARGS calls POPMARK, so we need to match PL_markstack_ptr[1] */
+ PL_stack_sp = PL_stack_base + PL_markstack_ptr[1] + 1;
+ } else {
+ MY_CXT.savesp = NULL;
+ }
+ SAVEDESTRUCTOR_X(su_unwind, NULL);
return;
default:
break;
BOOT:
{
- HV *stash = gv_stashpv(__PACKAGE__, 1);
+ HV *stash;
+ MY_CXT_INIT;
+ stash = gv_stashpv(__PACKAGE__, 1);
newCONSTSUB(stash, "HERE", newSViv(0));
newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL);
}
+void
+CLONE(...)
+PROTOTYPE: DISABLE
+CODE:
+#if SU_THREADSAFE
+ MY_CXT_CLONE;
+#endif /* SU_THREADSAFE */
+
SV *
TOP()
PROTOTYPE:
PREINIT:
I32 cxix = cxstack_ix, level = 0;
PPCODE:
- if (items) {
- SV *lsv = ST(0);
- if (SvOK(lsv))
- level = SvIV(lsv);
- if (level < 0)
- level = 0;
- else if (level > cxix)
- level = cxix;
- }
+ SU_GET_CONTEXT(0, 0);
cxix -= level;
while (cxix > 0) {
PERL_CONTEXT *cx = cxstack + cxix--;