# define VMG_MULTIPLICITY 0
# endif
#endif
-#if VMG_MULTIPLICITY && !defined(tTHX)
-# define tTHX PerlInterpreter*
-#endif
#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
# define VMG_UNLOCK(M)
#endif
-#if VMG_THREADSAFE
-
-STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) {
-#define vmg_clone(P, O) vmg_clone(aTHX_ (P), (O))
- SV *dupsv;
-
-#if VMG_HAS_PERL(5, 13, 2)
- CLONE_PARAMS *param = Perl_clone_params_new(owner, aTHX);
-
- dupsv = sv_dup(sv, param);
-
- Perl_clone_params_del(param);
-#else
- CLONE_PARAMS param;
-
- param.stashes = NULL; /* don't need it unless sv is a PVHV */
- param.flags = 0;
- param.proto_perl = owner;
-
- dupsv = sv_dup(sv, ¶m);
-#endif
-
- return SvREFCNT_inc(dupsv);
-}
-
-#endif /* VMG_THREADSAFE */
-
/* --- Compatibility ------------------------------------------------------- */
#ifndef Newx
#if VMG_UVAR
SV *cb_fetch, *cb_store, *cb_exists, *cb_delete;
#endif /* VMG_UVAR */
-
-#if VMG_MULTIPLICITY
- tTHX owner;
-#endif /* VMG_MULTIPLICITY */
} MGWIZ;
STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo);
if (!w)
return;
- /* We reach this point in dirty state when ptable_free() is called from the
- * atexit cleanup callback, and that the global table still holds a live
- * wizard. This happens before all the SV bodies are freed, so all the wizard
- * callbacks are still alive (as they are referenced by the undead wizard).
- * Hence it is safe to decrement their refcount. Later on, the wizard free
- * callback itself will trigger when the wizard body is reaped, but it will
- * be skipped as it guards against dirty state - which is good since nothing
- * has to be done anymore at that point. */
-
SvREFCNT_dec(w->cb_data);
SvREFCNT_dec(w->cb_get);
SvREFCNT_dec(w->cb_set);
#if VMG_THREADSAFE
#define VMG_CLONE_CB(N) \
- z->cb_ ## N = (w->cb_ ## N) ? vmg_clone(w->cb_ ## N, w->owner) \
+ z->cb_ ## N = (w->cb_ ## N) ? SvREFCNT_inc(sv_dup(w->cb_ ## N, params)) \
: NULL;
-STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
-#define vmg_mgwiz_clone(W) vmg_mgwiz_clone(aTHX_ (W))
+STATIC const MGWIZ *vmg_mgwiz_dup(pTHX_ const MGWIZ *w, CLONE_PARAMS *params) {
+#define vmg_mgwiz_dup(W, P) vmg_mgwiz_dup(aTHX_ (W), (P))
MGWIZ *z;
if (!w)
VMG_CLONE_CB(delete);
#endif /* VMG_UVAR */
- z->owner = aTHX;
-
return z;
}
/* --- Context-safe global data -------------------------------------------- */
-#if VMG_THREADSAFE
-
-#define PTABLE_NAME ptable
-#define PTABLE_VAL_FREE(V) vmg_mgwiz_free(VOID2(MGWIZ *, (V)))
-
-#define pPTBL pTHX
-#define pPTBL_ pTHX_
-#define aPTBL aTHX
-#define aPTBL_ aTHX_
-
-#include "ptable.h"
-
-#define ptable_store(T, K, V) ptable_store(aTHX_ (T), (K), (V))
-#define ptable_clear(T) ptable_clear(aTHX_ (T))
-#define ptable_free(T) ptable_free(aTHX_ (T))
-
-#endif /* VMG_THREADSAFE */
-
#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
typedef struct {
-#if VMG_THREADSAFE
- ptable *wizards;
- tTHX owner;
-#endif
- HV *b__op_stashes[OPc_MAX];
+ HV *b__op_stashes[OPc_MAX];
} my_cxt_t;
START_MY_CXT
-#if VMG_THREADSAFE
-
-STATIC void vmg_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
- my_cxt_t *ud = VOID2(my_cxt_t *, ud_);
- MGWIZ *w;
-
- if (ud->owner == aTHX)
- return;
-
- w = vmg_mgwiz_clone(VOID2(MGWIZ *, ent->val));
- if (w)
- ptable_store(ud->wizards, ent->key, w);
-}
-
-#endif /* VMG_THREADSAFE */
-
/* --- Wizard objects ------------------------------------------------------ */
STATIC int vmg_wizard_free(pTHX_ SV *sv, MAGIC *mg);
+#if VMG_THREADSAFE
+STATIC int vmg_wizard_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params);
+#endif
STATIC MGVTBL vmg_wizard_vtbl = {
NULL, /* get */
NULL, /* clear */
vmg_wizard_free, /* free */
NULL, /* copy */
+#if VMG_THREADSAFE
+ vmg_wizard_dup, /* dup */
+#else
NULL, /* dup */
+#endif
#if MGf_LOCAL
NULL, /* local */
#endif /* MGf_LOCAL */
STATIC SV *vmg_wizard_new(pTHX_ const MGWIZ *w) {
#define vmg_wizard_new(W) vmg_wizard_new(aTHX_ (W))
- SV *wiz = newSVuv(PTR2IV(w));
+ SV *wiz;
+
+#if VMG_THREADSAFE
+ wiz = newSV(0);
+#else
+ wiz = newSViv(PTR2IV(w));
+#endif
if (w) {
- MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl, NULL, 0);
+ MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl,
+ (const char *) w, 0);
mg->mg_private = SIG_WZO;
+#if VMG_THREADSAFE
+ mg->mg_flags |= MGf_DUP;
+#endif
}
SvREADONLY_on(wiz);
#define vmg_wizard_validate(W) vmg_wizard_validate(aTHX_ (W))
if (SvROK(wiz)) {
wiz = SvRV_const(wiz);
+#if VMG_THREADSAFE
+ if (SvTYPE(wiz) >= SVt_PVMG && SvMAGIC(wiz))
+#else
if (SvIOK(wiz))
+#endif
return wiz;
}
return NULL;
}
-#define vmg_wizard_id(W) SvIVX((const SV *) (W))
-#define vmg_wizard_main_mgwiz(W) INT2PTR(const MGWIZ *, vmg_wizard_id(W))
+#if VMG_THREADSAFE
+
+STATIC const MGWIZ *vmg_wizard_mgwiz(const SV *wiz) {
+ MAGIC *mg;
+
+ for (mg = SvMAGIC(wiz); mg; mg = mg->mg_moremagic) {
+ if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &vmg_wizard_vtbl)
+ return (const MGWIZ *) mg->mg_ptr;
+ }
+
+ return NULL;
+}
+
+#define vmg_wizard_mgwiz(W) vmg_wizard_mgwiz((const SV *) (W))
+
+#define vmg_wizard_id(W) PTR2IV(vmg_vtable_vtbl(vmg_wizard_mgwiz(W)->vtable))
+
+#else
+
+#define vmg_wizard_id(W) SvIVX((const SV *) (W))
+
+#define vmg_wizard_mgwiz(W) INT2PTR(const MGWIZ *, vmg_wizard_id(W))
+
+#endif
/* ... Wizard destructor ................................................... */
STATIC int vmg_wizard_free(pTHX_ SV *sv, MAGIC *mg) {
- MGWIZ *w;
-
if (PL_dirty) /* During global destruction, the context is already freed */
return 0;
- w = (MGWIZ *) vmg_wizard_main_mgwiz(sv);
-
-#if VMG_THREADSAFE
- {
- dMY_CXT;
- ptable_store(MY_CXT.wizards, w, NULL);
- }
-#else /* VMG_THREADSAFE */
- vmg_mgwiz_free(w);
-#endif /* !VMG_THREADSAFE */
+ vmg_mgwiz_free((MGWIZ *) mg->mg_ptr);
return 0;
}
#if VMG_THREADSAFE
-STATIC const MGWIZ *vmg_wizard_mgwiz(pTHX_ const SV *wiz) {
-#define vmg_wizard_mgwiz(W) vmg_wizard_mgwiz(aTHX_ ((const SV *) (W)))
- const MGWIZ *w;
-
- w = vmg_wizard_main_mgwiz(wiz);
- if (w->owner == aTHX)
- return w;
+STATIC int vmg_wizard_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) {
+ mg->mg_ptr = (char *) vmg_mgwiz_dup((const MGWIZ *) mg->mg_ptr, params);
- {
- dMY_CXT;
- return VOID2(const MGWIZ *, ptable_fetch(MY_CXT.wizards, w));
- }
+ return 0;
}
-#else /* VMG_THREADSAFE */
-
-#define vmg_wizard_mgwiz(W) vmg_wizard_main_mgwiz(W)
-
-#endif /* !VMG_THREADSAFE */
+#endif /* VMG_THREADSAFE */
/* --- User-level functions implementation --------------------------------- */
w->cb_ ## N = NULL; \
}
-#if VMG_THREADSAFE
-
-STATIC void vmg_cleanup(pTHX_ void *ud) {
- dMY_CXT;
-
- ptable_free(MY_CXT.wizards);
- MY_CXT.wizards = NULL;
-}
-
-#endif /* VMG_THREADSAFE */
-
/* --- XS ------------------------------------------------------------------ */
MODULE = Variable::Magic PACKAGE = Variable::Magic
HV *stash;
MY_CXT_INIT;
-#if VMG_THREADSAFE
- MY_CXT.wizards = ptable_new();
- MY_CXT.owner = aTHX;
-#endif
MY_CXT.b__op_stashes[0] = NULL;
#if VMG_THREADSAFE
MUTEX_INIT(&vmg_vtable_refcount_mutex);
MUTEX_INIT(&vmg_op_name_init_mutex);
- call_atexit(vmg_cleanup, NULL);
#endif
stash = gv_stashpv(__PACKAGE__, 1);
CLONE(...)
PROTOTYPE: DISABLE
PREINIT:
- ptable *t;
- U32 had_b__op_stash = 0;
- int c;
+ U32 had_b__op_stash = 0;
+ int c;
PPCODE:
{
- my_cxt_t ud;
dMY_CXT;
-
- ud.wizards = t = ptable_new();
- ud.owner = MY_CXT.owner;
- ptable_walk(MY_CXT.wizards, vmg_ptable_clone, &ud);
-
for (c = OPc_NULL; c < OPc_MAX; ++c) {
if (MY_CXT.b__op_stashes[c])
had_b__op_stash |= (((U32) 1) << c);
}
{
MY_CXT_CLONE;
- MY_CXT.wizards = t;
- MY_CXT.owner = aTHX;
for (c = OPc_NULL; c < OPc_MAX; ++c) {
MY_CXT.b__op_stashes[c] = (had_b__op_stash & (((U32) 1) << c))
? gv_stashpv(vmg_opclassnames[c], 1) : NULL;
MGVTBL *t;
SV *cb, *op_info, *copy_key;
CODE:
- dMY_CXT;
-
if (items != 9
#if MGf_LOCAL
+ 1
if (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete)
w->uvar = SvTRUE(copy_key) ? 2 : 1;
#endif /* VMG_UVAR */
-#if VMG_MULTIPLICITY
- w->owner = aTHX;
-#endif /* VMG_MULTIPLICITY */
-#if VMG_THREADSAFE
- ptable_store(MY_CXT.wizards, w, w);
-#endif /* VMG_THREADSAFE */
RETVAL = newRV_noinc(vmg_wizard_new(w));
OUTPUT: