# define dNOOP
#endif
-#if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
-# define VMG_MULTIPLICITY 1
-# ifndef tTHX
-# define tTHX PerlInterpreter*
+#ifndef VMG_MULTIPLICITY
+# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
+# define VMG_MULTIPLICITY 1
+# else
+# define VMG_MULTIPLICITY 0
# endif
-#else
-# define VMG_MULTIPLICITY 0
+#endif
+#if VMG_MULTIPLICITY && !defined(tTHX)
+# define tTHX PerlInterpreter*
#endif
-#if VMG_MULTIPLICITY && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && defined(MY_CXT_CLONE)
+#if VMG_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 VMG_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 VMG_THREADSAFE 0
# undef dMY_CXT
# define dMY_CXT dNOOP
# undef MY_CXT
-# define MY_CXT vmg_globaldata
+# define MY_CXT vmg_globaldata
# undef START_MY_CXT
# define START_MY_CXT STATIC my_cxt_t MY_CXT;
# undef MY_CXT_INIT
# define MY_CXT_CLONE NOOP
#endif
+#if VMG_THREADSAFE
+
+STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) {
+#define vmg_clone(P, O) vmg_clone(aTHX_ (P), (O))
+ CLONE_PARAMS param;
+ param.stashes = NULL; /* don't need it unless sv is a PVHV */
+ param.flags = 0;
+ param.proto_perl = owner;
+ return sv_dup(sv, ¶m);
+}
+
+#endif /* VMG_THREADSAFE */
+
/* --- Compatibility ------------------------------------------------------- */
#ifndef Newx
#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
-typedef struct {
- HV *wizz;
- U16 count;
-} my_cxt_t;
+typedef HV * my_cxt_t;
START_MY_CXT
-STATIC void vmg_cxt_init
-#if defined(pMY_CXT) && defined(aMY_CXT)
- (pTHX_ pMY_CXT) {
-# define vmg_cxt_init() vmg_cxt_init(aTHX_ aMY_CXT)
-#else
- (pTHX) {
- dMY_CXT;
-# define vmg_cxt_init() vmg_cxt_init(aTHX)
-#endif
- MY_CXT.wizz = newHV();
-#ifdef USE_ITHREADS
- HvSHAREKEYS_off(MY_CXT.wizz);
-#endif
- MY_CXT.count = 0;
- return;
-}
-
/* --- Signatures ---------------------------------------------------------- */
#define SIG_MIN ((U16) (1u << 8))
do {
sig = SIG_NBR * Drand01() + SIG_MIN;
- } while (hv_exists(MY_CXT.wizz, buf, sprintf(buf, "%u", sig)));
+ } while (hv_exists(MY_CXT, buf, sprintf(buf, "%u", sig)));
return sig;
}
#if VMG_UVAR
SV *cb_fetch, *cb_store, *cb_exists, *cb_delete;
#endif /* VMG_UVAR */
+#if VMG_MULTIPLICITY
+ tTHX owner;
+#endif /* VMG_MULTIPLICITY */
} MGWIZ;
#define MGWIZ2SV(W) (newSVuv(PTR2UV(W)))
if (w->cb_copy)
mg->mg_flags |= MGf_COPY;
#endif /* MGf_COPY */
-#if MGf_DUP
+#if 0 /* MGf_DUP */
if (w->cb_dup)
mg->mg_flags |= MGf_DUP;
#endif /* MGf_DUP */
STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
/* So that it can survive tmp cleanup in vmg_cb_call */
SvREFCNT_inc(sv);
+#if !VMG_HAS_PERL_AND(32686, 5, 11, 0)
+ /* The previous magic tokens were freed but the magic chain wasn't updated, so
+ * if you access the sv from the callback the old deleted magics will trigger
+ * and cause memory misreads. Change 32686 solved it that way : */
+ SvMAGIC_set(sv, mg);
+#endif
/* Perl_mg_free will get rid of the magic and decrement mg->mg_obj and
* mg->mg_ptr reference count */
return vmg_cb_call1(SV2MGWIZ(mg->mg_ptr)->cb_free, sv, mg->mg_obj);
STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) {
char buf[8];
MGWIZ *w;
- dMY_CXT;
if (PL_dirty) /* during global destruction, the context is already freed */
return 0;
w = SV2MGWIZ(wiz);
+#if VMG_MULTIPLICITY
+ if (w->owner != aTHX)
+ return 0;
+ w->owner = NULL;
+#endif /* VMG_MULTIPLICITY */
- if (hv_delete(MY_CXT.wizz, buf, sprintf(buf, "%u", w->sig), 0)) {
- --MY_CXT.count;
+ {
+ dMY_CXT;
+ if (hv_delete(MY_CXT, buf, sprintf(buf, "%u", w->sig), 0) != wiz)
+ return 0;
}
SvFLAGS(wiz) |= SVf_BREAK;
FREETMPS;
#if MGf_COPY
if (w->cb_copy != NULL) { SvREFCNT_dec(SvRV(w->cb_copy)); }
#endif /* MGf_COPY */
-#if MGf_DUP
+#if 0 /* MGf_DUP */
if (w->cb_dup != NULL) { SvREFCNT_dec(SvRV(w->cb_dup)); }
#endif /* MGf_DUP */
#if MGf_LOCAL
if (w->cb_exists != NULL) { SvREFCNT_dec(SvRV(w->cb_exists)); }
if (w->cb_delete != NULL) { SvREFCNT_dec(SvRV(w->cb_delete)); }
#endif /* VMG_UVAR */
+
Safefree(w->vtbl);
Safefree(w);
return sig;
}
+STATIC U16 vmg_wizard_sig(pTHX_ SV *wiz) {
+#define vmg_wizard_sig(W) vmg_wizard_sig(aTHX_ (W))
+ char buf[8];
+ U16 sig;
+
+ if (SvROK(wiz)) {
+ sig = SV2MGWIZ(SvRV(wiz))->sig;
+ } else if (SvOK(wiz)) {
+ sig = vmg_sv2sig(wiz);
+ } else {
+ croak(vmg_invalid_wiz);
+ }
+
+ {
+ dMY_CXT;
+ if (!hv_fetch(MY_CXT, buf, sprintf(buf, "%u", sig), 0))
+ sig = 0;
+ }
+ return sig;
+}
+
+STATIC SV *vmg_wizard_wiz(pTHX_ SV *wiz) {
+#define vmg_wizard_wiz(W) vmg_wizard_wiz(aTHX_ (W))
+ char buf[8];
+ SV **old;
+ U16 sig;
+
+ if (SvROK(wiz)) {
+ wiz = SvRV(wiz);
+#if VMG_MULTIPLICITY
+ if (SV2MGWIZ(wiz)->owner == aTHX)
+ return wiz;
+#endif /* VMG_MULTIPLICITY */
+ sig = SV2MGWIZ(wiz)->sig;
+ } else if (SvOK(wiz)) {
+ sig = vmg_sv2sig(wiz);
+ } else {
+ croak(vmg_invalid_wiz);
+ }
+
+ {
+ dMY_CXT;
+ return (old = hv_fetch(MY_CXT, buf, sprintf(buf, "%u", sig), 0))
+ ? *old : NULL;
+ }
+}
+
#define VMG_SET_CB(S, N) \
cb = (S); \
w->cb_ ## N = (SvOK(cb) && SvROK(cb)) ? newRV_inc(SvRV(cb)) : NULL;
w->cb_ ## N = NULL; \
}
+#if VMG_THREADSAFE
+
+#define VMG_CLONE_CB(N) \
+ z->cb_ ## N = (w->cb_ ## N) ? newRV_noinc(vmg_clone(SvRV(w->cb_ ## N), \
+ w->owner)) \
+ : NULL;
+
+STATIC MGWIZ *vmg_wizard_clone(pTHX_ const MGWIZ *w) {
+#define vmg_wizard_clone(W) vmg_wizard_clone(aTHX_ (W))
+ MGVTBL *t;
+ MGWIZ *z;
+
+ Newx(t, 1, MGVTBL);
+ Copy(w->vtbl, t, 1, MGVTBL);
+
+ Newx(z, 1, MGWIZ);
+ VMG_CLONE_CB(data);
+ VMG_CLONE_CB(get);
+ VMG_CLONE_CB(set);
+ VMG_CLONE_CB(len);
+ VMG_CLONE_CB(clear);
+ VMG_CLONE_CB(free);
+#if MGf_COPY
+ VMG_CLONE_CB(copy);
+#endif /* MGf_COPY */
+#if MGf_DUP
+ VMG_CLONE_CB(dup);
+#endif /* MGf_DUP */
+#if MGf_LOCAL
+ VMG_CLONE_CB(local);
+#endif /* MGf_LOCAL */
+#if VMG_UVAR
+ VMG_CLONE_CB(fetch);
+ VMG_CLONE_CB(store);
+ VMG_CLONE_CB(exists);
+ VMG_CLONE_CB(delete);
+#endif /* VMG_UVAR */
+ z->owner = aTHX;
+ z->vtbl = t;
+ z->sig = w->sig;
+ z->uvar = w->uvar;
+
+ return z;
+}
+
+#endif /* VMG_THREADSAFE */
/* --- XS ------------------------------------------------------------------ */
{
HV *stash;
MY_CXT_INIT;
- vmg_cxt_init();
+ MY_CXT = newHV();
+ hv_iterinit(MY_CXT); /* Allocate iterator */
stash = gv_stashpv(__PACKAGE__, 1);
newCONSTSUB(stash, "SIG_MIN", newSVuv(SIG_MIN));
newCONSTSUB(stash, "SIG_MAX", newSVuv(SIG_MAX));
void
CLONE(...)
PROTOTYPE: DISABLE
+PREINIT:
+ HV *hv;
CODE:
-#ifdef MY_CXT_CLONE
- MY_CXT_CLONE;
- vmg_cxt_init();
-#endif
+#if VMG_THREADSAFE
+ {
+ HE *key;
+ dMY_CXT;
+ hv = newHV();
+ hv_iterinit(hv); /* Allocate iterator */
+ hv_iterinit(MY_CXT);
+ while ((key = hv_iternext(MY_CXT))) {
+ STRLEN len;
+ char *sig = HePV(key, len);
+ SV *sv;
+ MAGIC *mg;
+ sv = MGWIZ2SV(vmg_wizard_clone(SV2MGWIZ(HeVAL(key))));
+ mg = sv_magicext(sv, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl, NULL, 0);
+ mg->mg_private = SIG_WIZ;
+ SvREADONLY_on(sv);
+ hv_store(hv, sig, len, sv, HeHASH(key));
+ }
+ }
+ {
+ MY_CXT_CLONE;
+ MY_CXT = hv;
+ }
+#endif /* VMG_THREADSAFE */
SV *_wizard(...)
PROTOTYPE: DISABLE
if (SvOK(svsig)) {
SV **old;
sig = vmg_sv2sig(svsig);
- if ((old = hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0))) {
+ if ((old = hv_fetch(MY_CXT, buf, sprintf(buf, "%u", sig), 0))) {
ST(0) = sv_2mortal(newRV_inc(*old));
XSRETURN(1);
}
} else {
- if (MY_CXT.count >= SIG_NBR) { croak(vmg_toomanysigs); }
+ if (HvKEYS(MY_CXT) >= SIG_NBR) { croak(vmg_toomanysigs); }
sig = vmg_gensig();
}
VMG_SET_CB(ST(i++), exists);
VMG_SET_CB(ST(i++), delete);
#endif /* VMG_UVAR */
+#if VMG_MULTIPLICITY
+ w->owner = aTHX;
+#endif /* VMG_MULTIPLICITY */
w->vtbl = t;
w->sig = sig;
mg->mg_private = SIG_WIZ;
SvREADONLY_on(sv);
- hv_store(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), sv, 0);
- ++MY_CXT.count;
+ hv_store(MY_CXT, buf, sprintf(buf, "%u", sig), sv, 0);
RETVAL = newRV_noinc(sv);
OUTPUT:
PROTOTYPE:
CODE:
dMY_CXT;
- if (MY_CXT.count >= SIG_NBR) { croak(vmg_toomanysigs); }
+ if (HvKEYS(MY_CXT) >= SIG_NBR) { croak(vmg_toomanysigs); }
RETVAL = newSVuv(vmg_gensig());
OUTPUT:
RETVAL
AV *args = NULL;
SV *ret;
CODE:
- dMY_CXT;
- if (SvROK(wiz)) {
- wiz = SvRV(wiz);
- } else if (SvOK(wiz)) {
- char buf[8];
- SV **old;
- U16 sig = vmg_sv2sig(wiz);
- if ((old = hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0))) {
- wiz = *old;
- } else {
- XSRETURN_UNDEF;
- }
- } else {
- croak(vmg_invalid_sig);
- }
+ wiz = vmg_wizard_wiz(wiz);
+ if (!wiz)
+ XSRETURN_UNDEF;
if (items > 2) {
I32 i;
args = newAV();
SV *data;
U16 sig;
CODE:
- dMY_CXT;
- if (SvROK(wiz)) {
- sig = SV2MGWIZ(SvRV(wiz))->sig;
- } else if (SvOK(wiz)) {
- char buf[8];
- sig = vmg_sv2sig(wiz);
- if (!hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
- XSRETURN_UNDEF;
- }
- } else {
- croak(vmg_invalid_wiz);
- }
+ sig = vmg_wizard_sig(wiz);
+ if (!sig)
+ XSRETURN_UNDEF;
data = vmg_data_get(SvRV(sv), sig);
if (!data) { XSRETURN_UNDEF; }
ST(0) = data;
PREINIT:
U16 sig;
CODE:
- dMY_CXT;
- if (SvROK(wiz)) {
- sig = SV2MGWIZ(SvRV(wiz))->sig;
- } else if (SvOK(wiz)) {
- char buf[8];
- sig = vmg_sv2sig(wiz);
- if (!hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
- XSRETURN_UNDEF;
- }
- } else {
- croak(vmg_invalid_wiz);
- }
+ sig = vmg_wizard_sig(wiz);
+ if (!sig)
+ XSRETURN_UNDEF;
RETVAL = newSVuv(vmg_dispell(SvRV(sv), sig));
OUTPUT:
RETVAL