]> git.vpit.fr Git - perl/modules/Variable-Magic.git/commitdiff
Clone wizard objects through dup magic
authorVincent Pit <vince@profvince.com>
Wed, 26 Oct 2011 14:52:27 +0000 (16:52 +0200)
committerVincent Pit <vince@profvince.com>
Wed, 26 Oct 2011 14:52:27 +0000 (16:52 +0200)
ptable.h is no longer needed.

MANIFEST
Magic.xs
ptable.h [deleted file]

index f533af0ee870763e404f3314157906aa3671891e..d984750422c45381c6530aef0fc62b19ec36112c 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -6,7 +6,6 @@ Magic.xs
 Makefile.PL
 README
 lib/Variable/Magic.pm
-ptable.h
 samples/copy.pl
 samples/magic.pl
 samples/synopsis.pl
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:
diff --git a/ptable.h b/ptable.h
deleted file mode 100644 (file)
index 5e9e8ed..0000000
--- a/ptable.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* This file is part of the Variable::Magic Perl module.
- * See http://search.cpan.org/dist/Variable-Magic/ */
-
-/* This is a pointer table implementation essentially copied from the ptr_table
- * implementation in perl's sv.c, except that it has been modified to use memory
- * shared across threads.
- * Copyright goes to the original authors, bug reports to me. */
-
-/* This header is designed to be included several times with different
- * definitions for PTABLE_NAME and PTABLE_VAL_FREE(). */
-
-#undef VOID2
-#ifdef __cplusplus
-# define VOID2(T, P) static_cast<T>(P)
-#else
-# define VOID2(T, P) (P)
-#endif
-
-#undef pPTBLMS
-#undef pPTBLMS_
-#undef aPTBLMS
-#undef aPTBLMS_
-
-/* Context for PerlMemShared_* functions */
-
-#ifdef PERL_IMPLICIT_SYS
-# define pPTBLMS  pTHX
-# define pPTBLMS_ pTHX_
-# define aPTBLMS  aTHX
-# define aPTBLMS_ aTHX_
-#else
-# define pPTBLMS  void
-# define pPTBLMS_
-# define aPTBLMS
-# define aPTBLMS_
-#endif
-
-#ifndef pPTBL
-# define pPTBL  pPTBLMS
-#endif
-#ifndef pPTBL_
-# define pPTBL_ pPTBLMS_
-#endif
-#ifndef aPTBL
-# define aPTBL  aPTBLMS
-#endif
-#ifndef aPTBL_
-# define aPTBL_ aPTBLMS_
-#endif
-
-#ifndef PTABLE_NAME
-# define PTABLE_NAME ptable
-#endif
-
-#ifndef PTABLE_VAL_FREE
-# define PTABLE_VAL_FREE(V)
-#endif
-
-#ifndef PTABLE_JOIN
-# define PTABLE_PASTE(A, B) A ## B
-# define PTABLE_JOIN(A, B)  PTABLE_PASTE(A, B)
-#endif
-
-#ifndef PTABLE_PREFIX
-# define PTABLE_PREFIX(X) PTABLE_JOIN(PTABLE_NAME, X)
-#endif
-
-#ifndef ptable_ent
-typedef struct ptable_ent {
- struct ptable_ent *next;
- const void *       key;
- void *             val;
-} ptable_ent;
-#define ptable_ent ptable_ent
-#endif /* !ptable_ent */
-
-#ifndef ptable
-typedef struct ptable {
- ptable_ent **ary;
- size_t       max;
- size_t       items;
-} ptable;
-#define ptable ptable
-#endif /* !ptable */
-
-#ifndef ptable_new
-STATIC ptable *ptable_new(pPTBLMS) {
-#define ptable_new() ptable_new(aPTBLMS)
- ptable *t = VOID2(ptable *, PerlMemShared_malloc(sizeof *t));
- t->max    = 15;
- t->items  = 0;
- t->ary    = VOID2(ptable_ent **,
-                              PerlMemShared_calloc(t->max + 1, sizeof *t->ary));
- return t;
-}
-#endif /* !ptable_new */
-
-#ifndef PTABLE_HASH
-# define PTABLE_HASH(ptr) \
-     ((PTR2UV(ptr) >> 3) ^ (PTR2UV(ptr) >> (3 + 7)) ^ (PTR2UV(ptr) >> (3 + 17)))
-#endif
-
-#ifndef ptable_find
-STATIC ptable_ent *ptable_find(const ptable * const t, const void * const key) {
-#define ptable_find ptable_find
- ptable_ent *ent;
- const UV hash = PTABLE_HASH(key);
-
- ent = t->ary[hash & t->max];
- for (; ent; ent = ent->next) {
-  if (ent->key == key)
-   return ent;
- }
-
- return NULL;
-}
-#endif /* !ptable_find */
-
-#ifndef ptable_fetch
-STATIC void *ptable_fetch(const ptable * const t, const void * const key) {
-#define ptable_fetch ptable_fetch
- const ptable_ent *const ent = ptable_find(t, key);
-
- return ent ? ent->val : NULL;
-}
-#endif /* !ptable_fetch */
-
-#ifndef ptable_split
-STATIC void ptable_split(pPTBLMS_ ptable * const t) {
-#define ptable_split(T) ptable_split(aPTBLMS_ (T))
- ptable_ent **ary = t->ary;
- const size_t oldsize = t->max + 1;
- size_t newsize = oldsize * 2;
- size_t i;
-
- ary = VOID2(ptable_ent **, PerlMemShared_realloc(ary, newsize * sizeof(*ary)));
- Zero(&ary[oldsize], newsize - oldsize, sizeof(*ary));
- t->max = --newsize;
- t->ary = ary;
-
- for (i = 0; i < oldsize; i++, ary++) {
-  ptable_ent **curentp, **entp, *ent;
-  if (!*ary)
-   continue;
-  curentp = ary + oldsize;
-  for (entp = ary, ent = *ary; ent; ent = *entp) {
-   if ((newsize & PTABLE_HASH(ent->key)) != i) {
-    *entp     = ent->next;
-    ent->next = *curentp;
-    *curentp  = ent;
-    continue;
-   } else
-    entp = &ent->next;
-  }
- }
-}
-#endif /* !ptable_split */
-
-STATIC void PTABLE_PREFIX(_store)(pPTBL_ ptable * const t, const void * const key, void * const val) {
- ptable_ent *ent = ptable_find(t, key);
-
- if (ent) {
-  void *oldval = ent->val;
-  PTABLE_VAL_FREE(oldval);
-  ent->val = val;
- } else if (val) {
-  const size_t i = PTABLE_HASH(key) & t->max;
-  ent = VOID2(ptable_ent *, PerlMemShared_malloc(sizeof *ent));
-  ent->key  = key;
-  ent->val  = val;
-  ent->next = t->ary[i];
-  t->ary[i] = ent;
-  t->items++;
-  if (ent->next && t->items > t->max)
-   ptable_split(t);
- }
-}
-
-STATIC void PTABLE_PREFIX(_delete)(pPTBL_ ptable * const t, const void * const key) {
- ptable_ent *prev, *ent;
- const size_t i = PTABLE_HASH(key) & t->max;
-
- prev = NULL;
- ent  = t->ary[i];
- for (; ent; prev = ent, ent = ent->next) {
-  if (ent->key == key)
-   break;
- }
-
- if (ent) {
-  if (prev)
-   prev->next = ent->next;
-  else
-   t->ary[i]  = ent->next;
-  PTABLE_VAL_FREE(ent->val);
-  PerlMemShared_free(ent);
- }
-}
-
-#ifndef ptable_walk
-STATIC void ptable_walk(pTHX_ ptable * const t, void (*cb)(pTHX_ ptable_ent *ent, void *userdata), void *userdata) {
-#define ptable_walk(T, CB, UD) ptable_walk(aTHX_ (T), (CB), (UD))
- if (t && t->items) {
-  register ptable_ent ** const array = t->ary;
-  size_t i = t->max;
-  do {
-   ptable_ent *entry;
-   for (entry = array[i]; entry; entry = entry->next)
-    if (entry->val)
-     cb(aTHX_ entry, userdata);
-  } while (i--);
- }
-}
-#endif /* !ptable_walk */
-
-STATIC void PTABLE_PREFIX(_clear)(pPTBL_ ptable * const t) {
- if (t && t->items) {
-  register ptable_ent ** const array = t->ary;
-  size_t i = t->max;
-
-  do {
-   ptable_ent *entry = array[i];
-   while (entry) {
-    ptable_ent * const oentry = entry;
-    void *val = oentry->val;
-    entry = entry->next;
-    PTABLE_VAL_FREE(val);
-    PerlMemShared_free(oentry);
-   }
-   array[i] = NULL;
-  } while (i--);
-
-  t->items = 0;
- }
-}
-
-STATIC void PTABLE_PREFIX(_free)(pPTBL_ ptable * const t) {
- if (!t)
-  return;
- PTABLE_PREFIX(_clear)(aPTBL_ t);
- PerlMemShared_free(t->ary);
- PerlMemShared_free(t);
-}
-
-#undef pPTBL
-#undef pPTBL_
-#undef aPTBL
-#undef aPTBL_
-
-#undef PTABLE_NAME
-#undef PTABLE_VAL_FREE