]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blobdiff - Magic.xs
Clone wizard objects through dup magic
[perl/modules/Variable-Magic.git] / Magic.xs
index 3fb9739614332542a19485443cc7d737c4a6fa50..a2dd6db341f4b9bb6ce3c3769dc6e81506a050db 100644 (file)
--- a/Magic.xs
+++ b/Magic.xs
@@ -55,9 +55,6 @@
 #  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, &param);
-#endif
-
- return SvREFCNT_inc(dupsv);
-}
-
-#endif /* VMG_THREADSAFE */
-
 /* --- Compatibility ------------------------------------------------------- */
 
 #ifndef Newx
@@ -518,10 +488,6 @@ typedef struct {
 #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);
@@ -548,15 +514,6 @@ STATIC void vmg_mgwiz_free(pTHX_ MGWIZ *w) {
  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);
@@ -586,11 +543,11 @@ STATIC void vmg_mgwiz_free(pTHX_ MGWIZ *w) {
 #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)
@@ -620,8 +577,6 @@ STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
  VMG_CLONE_CB(delete);
 #endif /* VMG_UVAR */
 
- z->owner = aTHX;
-
  return z;
 }
 
@@ -629,55 +584,20 @@ STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
 
 /* --- 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 */
@@ -686,7 +606,11 @@ STATIC MGVTBL vmg_wizard_vtbl = {
  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 */
@@ -696,11 +620,21 @@ STATIC MGVTBL vmg_wizard_vtbl = {
 
 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);
 
@@ -711,7 +645,11 @@ STATIC const SV *vmg_wizard_validate(pTHX_ const SV *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;
  }
 
@@ -720,52 +658,51 @@ STATIC const SV *vmg_wizard_validate(pTHX_ const SV *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 --------------------------------- */
 
@@ -1411,17 +1348,6 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
   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
@@ -1433,15 +1359,10 @@ BOOT:
  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);
@@ -1473,18 +1394,11 @@ void
 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);
@@ -1492,8 +1406,6 @@ PPCODE:
  }
  {
   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;
@@ -1511,8 +1423,6 @@ PREINIT:
  MGVTBL *t;
  SV *cb, *op_info, *copy_key;
 CODE:
- dMY_CXT;
-
  if (items != 9
 #if MGf_LOCAL
               + 1
@@ -1551,12 +1461,6 @@ CODE:
  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: