This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
threads::shared 1.13
[perl5.git] / ext / threads / shared / shared.xs
index 876fb97..4115bf1 100644 (file)
-/*    sharedsv.c
+/*    shared.xs
  *
- *    Copyright (c) 2001, Larry Wall
+ *    Copyright (c) 2001-2002, 2006 Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  *
+ * "Hand any two wizards a piece of rope and they would instinctively pull in
+ * opposite directions."
+ *                         --Sourcery
+ *
+ * Contributed by Artur Bergman <sky AT crucially DOT net>
+ * Pulled in the (an)other direction by Nick Ing-Simmons
+ *      <nick AT ing-simmons DOT net>
+ * CPAN version produced by Jerry D. Hedden <jdhedden AT cpan DOT org>
  */
 
 /*
-* Contributed by Arthur Bergman arthur@contiller.se
-*
-* "Hand any two wizards a piece of rope and they would instinctively pull in
-* opposite directions."
-*                         --Sourcery
-*
-*/
+ * Shared variables are implemented by a scheme similar to tieing.
+ * Each thread has a proxy SV with attached magic -- "private SVs" --
+ * which all point to a single SV in a separate shared interpreter
+ * (PL_sharedsv_space) -- "shared SVs".
+ *
+ * The shared SV holds the variable's true values, and its state is
+ * copied between the shared and private SVs with the usual
+ * mg_get()/mg_set() arrangement.
+ *
+ * Aggregates (AVs and HVs) are implemented using tie magic, except that
+ * the vtable used is one defined in this file rather than the standard one.
+ * This means that where a tie function like FETCH is normally invoked by
+ * the tie magic's mg_get() function, we completely bypass the calling of a
+ * perl-level function, and directly call C-level code to handle it. On
+ * the other hand, calls to functions like PUSH are done directly by code
+ * in av.c, etc., which we can't bypass. So the best we can do is to provide
+ * XS versions of these functions. We also have to attach a tie object,
+ * blessed into the class threads::shared::tie, to keep the method-calling
+ * code happy.
+ *
+ * Access to aggregate elements is done the usual tied way by returning a
+ * proxy PVLV element with attached element magic.
+ *
+ * Pointers to the shared SV are squirrelled away in the mg->mg_ptr field
+ * of magic (with mg_len == 0), and in the IV2PTR(SvIV(sv)) field of tied
+ * object SVs. These pointers have to be hidden like this because they
+ * cross interpreter boundaries, and we don't want sv_clear() and friends
+ * following them.
+ *
+ * The three basic shared types look like the following:
+ *
+ * -----------------
+ *
+ * Shared scalar (my $s : shared):
+ *
+ *  SV = PVMG(0x7ba238) at 0x7387a8
+ *   FLAGS = (PADMY,GMG,SMG)
+ *   MAGIC = 0x824d88
+ *     MG_TYPE = PERL_MAGIC_shared_scalar(n)
+ *     MG_PTR = 0x810358                <<<< pointer to the shared SV
+ *
+ * -----------------
+ *
+ * Shared aggregate (my @a : shared;  my %h : shared):
+ *
+ * SV = PVAV(0x7175d0) at 0x738708
+ *   FLAGS = (PADMY,RMG)
+ *   MAGIC = 0x824e48
+ *     MG_TYPE = PERL_MAGIC_tied(P)
+ *     MG_OBJ = 0x7136e0                <<<< ref to the tied object
+ *     SV = RV(0x7136f0) at 0x7136e0
+ *       RV = 0x738640
+ *       SV = PVMG(0x7ba238) at 0x738640 <<<< the tied object
+ *         FLAGS = (OBJECT,IOK,pIOK)
+ *         IV = 8455000                 <<<< pointer to the shared AV
+ *         STASH = 0x80abf0 "threads::shared::tie"
+ *     MG_PTR = 0x810358 ""             <<<< another pointer to the shared AV
+ *   ARRAY = 0x0
+ *
+ * -----------------
+ *
+ * Aggregate element (my @a : shared; $a[0])
+ *
+ * SV = PVLV(0x77f628) at 0x713550
+ *   FLAGS = (GMG,SMG,RMG,pIOK)
+ *   MAGIC = 0x72bd58
+ *     MG_TYPE = PERL_MAGIC_shared_scalar(n)
+ *     MG_PTR = 0x8103c0 ""             <<<< pointer to the shared element
+ *   MAGIC = 0x72bd18
+ *     MG_TYPE = PERL_MAGIC_tiedelem(p)
+ *     MG_OBJ = 0x7136e0                <<<< ref to the tied object
+ *     SV = RV(0x7136f0) at 0x7136e0
+ *       RV = 0x738660
+ *       SV = PVMG(0x7ba278) at 0x738660 <<<< the tied object
+ *         FLAGS = (OBJECT,IOK,pIOK)
+ *         IV = 8455064                 <<<< pointer to the shared AV
+ *         STASH = 0x80ac30 "threads::shared::tie"
+ *   TYPE = t
+ *
+ * Note that PERL_MAGIC_tiedelem(p) magic doesn't have a pointer to a
+ * shared SV in mg_ptr; instead this is used to store the hash key,
+ * if any, like normal tied elements. Note also that element SVs may have
+ * pointers to both the shared aggregate and the shared element.
+ *
+ *
+ * Userland locks:
+ *
+ * If a shared variable is used as a perl-level lock or condition
+ * variable, then PERL_MAGIC_ext magic is attached to the associated
+ * *shared* SV, whose mg_ptr field points to a malloc'ed structure
+ * containing the necessary mutexes and condition variables.
+ *
+ * Nomenclature:
+ *
+ * In this file, any variable name prefixed with 's' (e.g., ssv, stmp or sobj)
+ * usually represents a shared SV which corresponds to a private SV named
+ * without the prefix (e.g., sv, tmp or obj).
+ */
 
 #define PERL_NO_GET_CONTEXT
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#ifdef HAS_PPPORT_H
+#  define NEED_vnewSVpvf
+#  define NEED_warner
+#  include "ppport.h"
+#  include "shared.h"
+#endif
 
-PerlInterpreter        *PL_sharedsv_space;             /* The shared sv space */
-perl_mutex      PL_sharedsv_space_mutex;       /* Mutex protecting the shared sv space */
+#ifdef USE_ITHREADS
 
-typedef struct {
-    SV                 *sv;             /* The actual SV */
-    perl_mutex          mutex;          /* Our mutex */
-    perl_cond           cond;           /* Our condition variable */
-    perl_cond           user_cond;      /* For user-level conditions */
-    IV                  locks;          /* Number of locks held */
-    PerlInterpreter    *owner;          /* Who owns the lock? */
-    U16                 index;          /* Update index */
-} shared_sv;
-
-#define SHAREDSvGET(a)      (a->sv)
-#define SHAREDSvLOCK(a)     Perl_sharedsv_lock(aTHX_ a)
-#define SHAREDSvUNLOCK(a)   Perl_sharedsv_unlock(aTHX_ a)
-
-#define SHAREDSvEDIT(a)     STMT_START {                                \
-                                MUTEX_LOCK(&PL_sharedsv_space_mutex);   \
-                                SHAREDSvLOCK((a));                      \
-                                PERL_SET_CONTEXT(PL_sharedsv_space);    \
-                            } STMT_END
-
-#define SHAREDSvRELEASE(a)  STMT_START {                                \
-                                PERL_SET_CONTEXT((a)->owner);           \
-                                SHAREDSvUNLOCK((a));                    \
-                                MUTEX_UNLOCK(&PL_sharedsv_space_mutex); \
-                            } STMT_END
-
-extern void    Perl_sharedsv_init(pTHX);
-extern shared_sv*      Perl_sharedsv_new(pTHX);
-extern shared_sv*      Perl_sharedsv_find(pTHX_ SV* sv);
-extern void    Perl_sharedsv_lock(pTHX_ shared_sv* ssv);
-extern void    Perl_sharedsv_unlock(pTHX_ shared_sv* ssv);
-extern void    Perl_sharedsv_unlock_scope(pTHX_ shared_sv* ssv);
-extern void    Perl_sharedsv_thrcnt_inc(pTHX_ shared_sv* ssv);
-extern void    Perl_sharedsv_thrcnt_dec(pTHX_ shared_sv* ssv);
+/* Magic signature(s) for mg_private to make PERL_MAGIC_ext magic safer */
+#define UL_MAGIC_SIG 0x554C  /* UL = user lock */
 
 /*
-  Shared SV
+ * The shared things need an intepreter to live in ...
+ */
+PerlInterpreter *PL_sharedsv_space;             /* The shared sv space */
+/* To access shared space we fake aTHX in this scope and thread's context */
+
+/* Bug #24255: We include ENTER+SAVETMPS/FREETMPS+LEAVE with
+ * SHARED_CONTEXT/CALLER_CONTEXT macros, so that any mortals, etc. created
+ * while in the shared interpreter context don't languish */
+
+#define SHARED_CONTEXT                                  \
+    STMT_START {                                        \
+        PERL_SET_CONTEXT((aTHX = PL_sharedsv_space));   \
+        ENTER;                                          \
+        SAVETMPS;                                       \
+    } STMT_END
+
+/* So we need a way to switch back to the caller's context... */
+/* So we declare _another_ copy of the aTHX variable ... */
+#define dTHXc PerlInterpreter *caller_perl = aTHX
+
+/* ... and use it to switch back */
+#define CALLER_CONTEXT                                  \
+    STMT_START {                                        \
+        FREETMPS;                                       \
+        LEAVE;                                          \
+        PERL_SET_CONTEXT((aTHX = caller_perl));         \
+    } STMT_END
 
-  Shared SV is a structure for keeping the backend storage
-  of shared svs.
+/*
+ * Only one thread at a time is allowed to mess with shared space.
+ */
 
-*/
+typedef struct {
+    perl_mutex          mutex;
+    PerlInterpreter    *owner;
+    I32                 locks;
+    perl_cond           cond;
+#ifdef DEBUG_LOCKS
+    char *              file;
+    int                 line;
+#endif
+} recursive_lock_t;
+
+recursive_lock_t PL_sharedsv_lock;   /* Mutex protecting the shared sv space */
 
-/*
+void
+recursive_lock_init(pTHX_ recursive_lock_t *lock)
+{
+    Zero(lock,1,recursive_lock_t);
+    MUTEX_INIT(&lock->mutex);
+    COND_INIT(&lock->cond);
+}
 
- =head1 Shared SV Functions
+void
+recursive_lock_destroy(pTHX_ recursive_lock_t *lock)
+{
+    MUTEX_DESTROY(&lock->mutex);
+    COND_DESTROY(&lock->cond);
+}
 
- =for apidoc sharedsv_init 
+void
+recursive_lock_release(pTHX_ recursive_lock_t *lock)
+{
+    MUTEX_LOCK(&lock->mutex);
+    if (lock->owner == aTHX) {
+        if (--lock->locks == 0) {
+            lock->owner = NULL;
+            COND_SIGNAL(&lock->cond);
+        }
+    }
+    MUTEX_UNLOCK(&lock->mutex);
+}
+
+void
+recursive_lock_acquire(pTHX_ recursive_lock_t *lock, char *file, int line)
+{
+    assert(aTHX);
+    MUTEX_LOCK(&lock->mutex);
+    if (lock->owner == aTHX) {
+        lock->locks++;
+    } else {
+        while (lock->owner) {
+#ifdef DEBUG_LOCKS
+            Perl_warn(aTHX_ " %p waiting - owned by %p %s:%d\n",
+                      aTHX, lock->owner, lock->file, lock->line);
+#endif
+            COND_WAIT(&lock->cond,&lock->mutex);
+        }
+        lock->locks = 1;
+        lock->owner = aTHX;
+#ifdef DEBUG_LOCKS
+        lock->file  = file;
+        lock->line  = line;
+#endif
+    }
+    MUTEX_UNLOCK(&lock->mutex);
+    SAVEDESTRUCTOR_X(recursive_lock_release,lock);
+}
+
+#define ENTER_LOCK                                                          \
+    STMT_START {                                                            \
+        ENTER;                                                              \
+        recursive_lock_acquire(aTHX_ &PL_sharedsv_lock, __FILE__, __LINE__);\
+    } STMT_END
 
-Saves a space for keeping SVs wider than an interpreter,
-currently only stores a pointer to the first interpreter.
+/* The unlocking is done automatically at scope exit */
+#define LEAVE_LOCK      LEAVE
 
- =cut
 
+/* A common idiom is to acquire access and switch in ... */
+#define SHARED_EDIT     \
+    STMT_START {        \
+        ENTER_LOCK;     \
+        SHARED_CONTEXT; \
+    } STMT_END
+
+/* ... then switch out and release access. */
+#define SHARED_RELEASE  \
+    STMT_START {        \
+        CALLER_CONTEXT; \
+        LEAVE_LOCK;     \
+    } STMT_END
+
+
+/* User-level locks:
+   This structure is attached (using ext magic) to any shared SV that
+   is used by user-level locking or condition code
 */
 
-void
-Perl_sharedsv_init(pTHX)
+typedef struct {
+    recursive_lock_t    lock;           /* For user-levl locks */
+    perl_cond           user_cond;      /* For user-level conditions */
+} user_lock;
+
+/* Magic used for attaching user_lock structs to shared SVs
+
+   The vtable used has just one entry - when the SV goes away
+   we free the memory for the above.
+ */
+
+int
+sharedsv_userlock_free(pTHX_ SV *sv, MAGIC *mg)
 {
-  PerlInterpreter* old_context = PERL_GET_CONTEXT;
-  PL_sharedsv_space = perl_alloc();
-  perl_construct(PL_sharedsv_space);
-  PERL_SET_CONTEXT(old_context);
-  MUTEX_INIT(&PL_sharedsv_space_mutex);
+    user_lock *ul = (user_lock *) mg->mg_ptr;
+    assert(aTHX == PL_sharedsv_space);
+    if (ul) {
+        recursive_lock_destroy(aTHX_ &ul->lock);
+        COND_DESTROY(&ul->user_cond);
+        PerlMemShared_free(ul);
+        mg->mg_ptr = NULL;
+    }
+    return (0);
 }
 
+MGVTBL sharedsv_userlock_vtbl = {
+    0,                          /* get */
+    0,                          /* set */
+    0,                          /* len */
+    0,                          /* clear */
+    sharedsv_userlock_free,     /* free */
+    0,                          /* copy */
+    0,                          /* dup */
+#ifdef MGf_LOCAL
+    0,                          /* local */
+#endif
+};
+
 /*
- =for apidoc sharedsv_new
+ * Access to shared things is heavily based on MAGIC
+ *      - in mg.h/mg.c/sv.c sense
+ */
+
+/* In any thread that has access to a shared thing there is a "proxy"
+   for it in its own space which has 'MAGIC' associated which accesses
+   the shared thing.
+ */
+
+extern MGVTBL sharedsv_scalar_vtbl;    /* Scalars have this vtable */
+extern MGVTBL sharedsv_array_vtbl;     /* Hashes and arrays have this
+                                            - like 'tie' */
+extern MGVTBL sharedsv_elem_vtbl;      /* Elements of hashes and arrays have
+                                          this _AS WELL AS_ the scalar magic:
+   The sharedsv_elem_vtbl associates the element with the array/hash and
+   the sharedsv_scalar_vtbl associates it with the value
+ */
 
-Allocates a new shared sv struct, you must yourself create the SV/AV/HV.
- =cut
-*/
 
-shared_sv *
-Perl_sharedsv_new(pTHX)
+/* Get shared aggregate SV pointed to by threads::shared::tie magic object */
+
+STATIC SV *
+S_sharedsv_from_obj(pTHX_ SV *sv)
 {
-    shared_sv* ssv;
-    New(2555,ssv,1,shared_sv);
-    MUTEX_INIT(&ssv->mutex);
-    COND_INIT(&ssv->cond);
-    COND_INIT(&ssv->user_cond);
-    ssv->owner = 0;
-    ssv->locks = 0;
-    ssv->index = 0;
-    return ssv;
+     return ((SvROK(sv)) ? INT2PTR(SV *, SvIV(SvRV(sv))) : NULL);
 }
 
 
-/*
- =for apidoc sharedsv_find
+/* Return the user_lock structure (if any) associated with a shared SV.
+ * If create is true, create one if it doesn't exist
+ */
+STATIC user_lock *
+S_get_userlock(pTHX_ SV* ssv, bool create)
+{
+    MAGIC *mg;
+    user_lock *ul = NULL;
+
+    assert(ssv);
+    /* XXX Redesign the storage of user locks so we don't need a global
+     * lock to access them ???? DAPM */
+    ENTER_LOCK;
+
+    /* Version of mg_find that also checks the private signature */
+    for (mg = SvMAGIC(ssv); mg; mg = mg->mg_moremagic) {
+        if ((mg->mg_type == PERL_MAGIC_ext) &&
+            (mg->mg_private == UL_MAGIC_SIG))
+        {
+            break;
+        }
+    }
 
-Tries to find if a given SV has a shared backend, either by
-looking at magic, or by checking if it is tied again threads::shared.
+    if (mg) {
+        ul = (user_lock*)(mg->mg_ptr);
+    } else if (create) {
+        dTHXc;
+        SHARED_CONTEXT;
+        ul = (user_lock *) PerlMemShared_malloc(sizeof(user_lock));
+        Zero(ul, 1, user_lock);
+        /* Attach to shared SV using ext magic */
+        mg = sv_magicext(ssv, NULL, PERL_MAGIC_ext, &sharedsv_userlock_vtbl,
+                            (char *)ul, 0);
+        mg->mg_private = UL_MAGIC_SIG;  /* Set private signature */
+        recursive_lock_init(aTHX_ &ul->lock);
+        COND_INIT(&ul->user_cond);
+        CALLER_CONTEXT;
+    }
+    LEAVE_LOCK;
+    return (ul);
+}
 
- =cut
-*/
 
-shared_sv *
-Perl_sharedsv_find(pTHX_ SV* sv)
+/* Given a private side SV tries to find if the SV has a shared backend,
+ * by looking for the magic.
+ */
+SV *
+Perl_sharedsv_find(pTHX_ SV *sv)
 {
-  /* does all it can to find a shared_sv struct, returns NULL otherwise */
-    shared_sv* ssv = NULL;
-    switch (SvTYPE(sv)) {
-        case SVt_PVMG:
+    MAGIC *mg;
+    if (SvTYPE(sv) >= SVt_PVMG) {
+        switch(SvTYPE(sv)) {
         case SVt_PVAV:
-        case SVt_PVHV: {
-            MAGIC* mg = mg_find(sv, PERL_MAGIC_ext);
-            if(mg) {
-               if(strcmp(mg->mg_ptr,"threads::shared"))
-                    break;
-                ssv = INT2PTR(shared_sv *, SvIV(mg->mg_obj));
-               break;
-             }
-       
-            mg = mg_find(sv,PERL_MAGIC_tied);
-             if(mg) {
-                 SV* obj = SvTIED_obj(sv,mg);
-                if(sv_derived_from(obj, "threads::shared"))
-                     ssv = INT2PTR(shared_sv *, SvIV(SvRV(obj)));
-                 break;
-             }
-       }
+        case SVt_PVHV:
+            if ((mg = mg_find(sv, PERL_MAGIC_tied))
+                && mg->mg_virtual == &sharedsv_array_vtbl) {
+                return ((SV *)mg->mg_ptr);
+            }
+            break;
+        default:
+            /* This should work for elements as well as they
+             * have scalar magic as well as their element magic
+             */
+            if ((mg = mg_find(sv, PERL_MAGIC_shared_scalar))
+                && mg->mg_virtual == &sharedsv_scalar_vtbl) {
+                return ((SV *)mg->mg_ptr);
+            }
+            break;
+        }
+    }
+    /* Just for tidyness of API also handle tie objects */
+    if (SvROK(sv) && sv_derived_from(sv, "threads::shared::tie")) {
+        return (S_sharedsv_from_obj(aTHX_ sv));
     }
-    return ssv;
+    return (NULL);
 }
 
-/*
- =for apidoc sharedsv_lock
 
-Recursive locks on a sharedsv.
-Locks are dynamically scoped at the level of the first lock.
- =cut
-*/
+/* Associate a private SV  with a shared SV by pointing the appropriate
+ * magics at it.
+ * Assumes lock is held.
+ */
 void
-Perl_sharedsv_lock(pTHX_ shared_sv* ssv)
+Perl_sharedsv_associate(pTHX_ SV *sv, SV *ssv)
 {
-    if(!ssv)
-        return;
-    MUTEX_LOCK(&ssv->mutex);
-    if(ssv->owner && ssv->owner == my_perl) {
-        ssv->locks++;
-       MUTEX_UNLOCK(&ssv->mutex);
-        return;
+    MAGIC *mg = 0;
+
+    /* If we are asked for any private ops we need a thread */
+    assert ( aTHX !=  PL_sharedsv_space );
+
+    /* To avoid need for recursive locks require caller to hold lock */
+    assert ( PL_sharedsv_lock.owner == aTHX );
+
+    switch(SvTYPE(sv)) {
+    case SVt_PVAV:
+    case SVt_PVHV:
+        if (!(mg = mg_find(sv, PERL_MAGIC_tied))
+            || mg->mg_virtual != &sharedsv_array_vtbl
+            || (SV*) mg->mg_ptr != ssv)
+        {
+            SV *obj = newSV(0);
+            sv_setref_iv(obj, "threads::shared::tie", PTR2IV(ssv));
+            if (mg) {
+                sv_unmagic(sv, PERL_MAGIC_tied);
+            }
+            mg = sv_magicext(sv, obj, PERL_MAGIC_tied, &sharedsv_array_vtbl,
+                            (char *)ssv, 0);
+            mg->mg_flags |= (MGf_COPY|MGf_DUP);
+            SvREFCNT_inc_void(ssv);
+            SvREFCNT_dec(obj);
+        }
+        break;
+
+    default:
+        if ((SvTYPE(sv) < SVt_PVMG)
+            || !(mg = mg_find(sv, PERL_MAGIC_shared_scalar))
+            || mg->mg_virtual != &sharedsv_scalar_vtbl
+            || (SV*) mg->mg_ptr != ssv)
+        {
+            if (mg) {
+                sv_unmagic(sv, PERL_MAGIC_shared_scalar);
+            }
+            mg = sv_magicext(sv, Nullsv, PERL_MAGIC_shared_scalar,
+                            &sharedsv_scalar_vtbl, (char *)ssv, 0);
+            mg->mg_flags |= (MGf_DUP
+#ifdef MGf_LOCAL
+                                    |MGf_LOCAL
+#endif
+                            );
+            SvREFCNT_inc_void(ssv);
+        }
+        break;
     }
-    while(ssv->owner)
-      COND_WAIT(&ssv->cond,&ssv->mutex);
-    ssv->locks++;
-    ssv->owner = my_perl;
-    if(ssv->locks == 1)
-        SAVEDESTRUCTOR_X(Perl_sharedsv_unlock_scope,ssv);
-    MUTEX_UNLOCK(&ssv->mutex);
+
+    assert ( Perl_sharedsv_find(aTHX_ sv) == ssv );
 }
 
-/*
- =for apidoc sharedsv_unlock
 
-Recursively unlocks a shared sv.
+/* Given a private SV, create and return an associated shared SV.
+ * Assumes lock is held.
+ */
+STATIC SV *
+S_sharedsv_new_shared(pTHX_ SV *sv)
+{
+    dTHXc;
+    SV *ssv;
+
+    assert(PL_sharedsv_lock.owner == aTHX);
+    assert(aTHX !=  PL_sharedsv_space);
+
+    SHARED_CONTEXT;
+    ssv = newSV(0);
+    SvREFCNT(ssv) = 0; /* Will be upped to 1 by Perl_sharedsv_associate */
+    sv_upgrade(ssv, SvTYPE(sv));
+    CALLER_CONTEXT;
+    Perl_sharedsv_associate(aTHX_ sv, ssv);
+    return (ssv);
+}
 
- =cut
-*/
 
-void
-Perl_sharedsv_unlock(pTHX_ shared_sv* ssv)
+/* Given a shared SV, create and return an associated private SV.
+ * Assumes lock is held.
+ */
+STATIC SV *
+S_sharedsv_new_private(pTHX_ SV *ssv)
 {
-    MUTEX_LOCK(&ssv->mutex);
-    if(ssv->owner != my_perl) {
-        Perl_croak(aTHX_ "panic: Perl_sharedsv_unlock unlocking mutex that we don't own");
-        MUTEX_UNLOCK(&ssv->mutex);
+    SV *sv;
+
+    assert(PL_sharedsv_lock.owner == aTHX);
+    assert(aTHX !=  PL_sharedsv_space);
+
+    sv = newSV(0);
+    sv_upgrade(sv, SvTYPE(ssv));
+    Perl_sharedsv_associate(aTHX_ sv, ssv);
+    return (sv);
+}
+
+
+/* A threadsafe version of SvREFCNT_dec(ssv) */
+
+STATIC void
+S_sharedsv_dec(pTHX_ SV* ssv)
+{
+    if (! ssv)
         return;
+    ENTER_LOCK;
+    if (SvREFCNT(ssv) > 1) {
+        /* No side effects, so can do it lightweight */
+        SvREFCNT_dec(ssv);
+    } else {
+        dTHXc;
+        SHARED_CONTEXT;
+        SvREFCNT_dec(ssv);
+        CALLER_CONTEXT;
     }
+    LEAVE_LOCK;
+}
 
-    if(--ssv->locks == 0) {
-        ssv->owner = NULL;
-       COND_SIGNAL(&ssv->cond);
-    }
-    MUTEX_UNLOCK(&ssv->mutex);
- }
+
+/* Implements Perl-level share() and :shared */
 
 void
-Perl_sharedsv_unlock_scope(pTHX_ shared_sv* ssv)
+Perl_sharedsv_share(pTHX_ SV *sv)
 {
-    MUTEX_LOCK(&ssv->mutex);
-    if(ssv->owner != my_perl) {
-        MUTEX_UNLOCK(&ssv->mutex);
-        return;
+    switch(SvTYPE(sv)) {
+    case SVt_PVGV:
+        Perl_croak(aTHX_ "Cannot share globs yet");
+        break;
+
+    case SVt_PVCV:
+        Perl_croak(aTHX_ "Cannot share subs yet");
+        break;
+
+    default:
+        ENTER_LOCK;
+        (void) S_sharedsv_new_shared(aTHX_ sv);
+        LEAVE_LOCK;
+        SvSETMAGIC(sv);
+        break;
     }
-    ssv->locks = 0;
-    ssv->owner = NULL;
-    COND_SIGNAL(&ssv->cond);
-    MUTEX_UNLOCK(&ssv->mutex);
 }
 
-/*
- =for apidoc sharedsv_thrcnt_inc
 
-Increments the threadcount of a sharedsv.
- =cut
-*/
-void
-Perl_sharedsv_thrcnt_inc(pTHX_ shared_sv* ssv)
+#ifdef WIN32
+/* Number of milliseconds from 1/1/1601 to 1/1/1970 */
+#define EPOCH_BIAS      11644473600000.
+
+/* Returns relative time in milliseconds.  (Adapted from Time::HiRes.) */
+STATIC DWORD
+S_abs_2_rel_milli(double abs)
 {
-  SHAREDSvLOCK(ssv);
-  SvREFCNT_inc(ssv->sv);
-  SHAREDSvUNLOCK(ssv);
+    double rel;
+
+    /* Get current time (in units of 100 nanoseconds since 1/1/1601) */
+    union {
+        FILETIME ft;
+        __int64  i64;   /* 'signed' to keep compilers happy */
+    } now;
+
+    GetSystemTimeAsFileTime(&now.ft);
+
+    /* Relative time in milliseconds */
+    rel = (abs * 1000.) - (((double)now.i64 / 10000.) - EPOCH_BIAS);
+    if (rel <= 0.0) {
+        return (0);
+    }
+    return (DWORD)rel;
 }
 
-/*
- =for apidoc sharedsv_thrcnt_dec
+#else
+# if defined(OS2)
+#  define ABS2RELMILLI(abs)             \
+    do {                                \
+        abs -= (double)time(NULL);      \
+        if (abs > 0) { abs *= 1000; }   \
+        else         { abs  = 0;    }   \
+    } while (0)
+# endif /* OS2 */
+#endif /* WIN32 */
+
+/* Do OS-specific condition timed wait */
+
+bool
+Perl_sharedsv_cond_timedwait(perl_cond *cond, perl_mutex *mut, double abs)
+{
+#if defined(NETWARE) || defined(FAKE_THREADS) || defined(I_MACH_CTHREADS)
+    Perl_croak_nocontext("cond_timedwait not supported on this platform");
+#else
+#  ifdef WIN32
+    int got_it = 0;
+
+    cond->waiters++;
+    MUTEX_UNLOCK(mut);
+    /* See comments in win32/win32thread.h COND_WAIT vis-a-vis race */
+    switch (WaitForSingleObject(cond->sem, S_abs_2_rel_milli(abs))) {
+        case WAIT_OBJECT_0:   got_it = 1; break;
+        case WAIT_TIMEOUT:                break;
+        default:
+            /* WAIT_FAILED? WAIT_ABANDONED? others? */
+            Perl_croak_nocontext("panic: cond_timedwait (%ld)",GetLastError());
+            break;
+    }
+    MUTEX_LOCK(mut);
+    cond->waiters--;
+    return (got_it);
+#  else
+#    ifdef OS2
+    int rc, got_it = 0;
+    STRLEN n_a;
+
+    ABS2RELMILLI(abs);
+
+    if ((rc = DosResetEventSem(*cond,&n_a)) && (rc != ERROR_ALREADY_RESET))
+        Perl_rc = rc, croak_with_os2error("panic: cond_timedwait-reset");
+    MUTEX_UNLOCK(mut);
+    if (CheckOSError(DosWaitEventSem(*cond,abs))
+        && (rc != ERROR_INTERRUPT))
+        croak_with_os2error("panic: cond_timedwait");
+    if (rc == ERROR_INTERRUPT) errno = EINTR;
+    MUTEX_LOCK(mut);
+    return (got_it);
+#    else         /* Hope you're I_PTHREAD! */
+    struct timespec ts;
+    int got_it = 0;
+
+    ts.tv_sec = (long)abs;
+    abs -= (NV)ts.tv_sec;
+    ts.tv_nsec = (long)(abs * 1000000000.0);
+
+    switch (pthread_cond_timedwait(cond, mut, &ts)) {
+        case 0:         got_it = 1; break;
+        case ETIMEDOUT:             break;
+#ifdef OEMVS
+        case -1:
+            if (errno == ETIMEDOUT || errno == EAGAIN)
+                break;
+#endif
+        default:
+            Perl_croak_nocontext("panic: cond_timedwait");
+            break;
+    }
+    return (got_it);
+#    endif /* OS2 */
+#  endif /* WIN32 */
+#endif /* NETWARE || FAKE_THREADS || I_MACH_CTHREADS */
+}
 
-Decrements the threadcount of a shared sv. When a threads frontend is freed
-this function should be called.
 
- =cut
-*/
+/* Given a shared RV, copy it's value to a private RV, also copying the
+ * object status of the referent.
+ * If the private side is already an appropriate RV->SV combination, keep
+ * it if possible.
+ */
+STATIC void
+S_get_RV(pTHX_ SV *sv, SV *ssv) {
+    SV *sobj = SvRV(ssv);
+    SV *obj;
+    if (! (SvROK(sv) &&
+           ((obj = SvRV(sv))) &&
+           (Perl_sharedsv_find(aTHX_ obj) == sobj) &&
+           (SvTYPE(obj) == SvTYPE(sobj))))
+    {
+        /* Can't reuse obj */
+        if (SvROK(sv)) {
+            SvREFCNT_dec(SvRV(sv));
+        } else {
+            assert(SvTYPE(sv) >= SVt_RV);
+            sv_setsv_nomg(sv, &PL_sv_undef);
+            SvROK_on(sv);
+        }
+        obj = S_sharedsv_new_private(aTHX_ SvRV(ssv));
+        SvRV_set(sv, obj);
+    }
 
+    if (SvOBJECT(obj)) {
+        /* Remove any old blessing */
+        SvREFCNT_dec(SvSTASH(obj));
+        SvOBJECT_off(obj);
+    }
+    if (SvOBJECT(sobj)) {
+        /* Add any new old blessing */
+        STRLEN len;
+        char* stash_ptr = SvPV((SV*) SvSTASH(sobj), len);
+        HV* stash = gv_stashpvn(stash_ptr, len, TRUE);
+        SvOBJECT_on(obj);
+        SvSTASH_set(obj, (HV*)SvREFCNT_inc(stash));
+    }
+}
+
+
+/* ------------ PERL_MAGIC_shared_scalar(n) functions -------------- */
+
+/* Get magic for PERL_MAGIC_shared_scalar(n) */
+
+int
+sharedsv_scalar_mg_get(pTHX_ SV *sv, MAGIC *mg)
+{
+    SV *ssv = (SV *) mg->mg_ptr;
+    assert(ssv);
+
+    ENTER_LOCK;
+    if (SvROK(ssv)) {
+        S_get_RV(aTHX_ sv, ssv);
+    } else {
+        sv_setsv_nomg(sv, ssv);
+    }
+    LEAVE_LOCK;
+    return (0);
+}
+
+/* Copy the contents of a private SV to a shared SV.
+ * Used by various mg_set()-type functions.
+ * Assumes lock is held.
+ */
 void
-Perl_sharedsv_thrcnt_dec(pTHX_ shared_sv* ssv)
+sharedsv_scalar_store(pTHX_ SV *sv, SV *ssv)
 {
-    SV* sv;
-    SHAREDSvLOCK(ssv);
-    sv = SHAREDSvGET(ssv);
-    if (SvREFCNT(sv) == 1) {
-        switch (SvTYPE(sv)) {
-        case SVt_RV:
-            if (SvROK(sv))
-            Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv *, SvIV(SvRV(sv))));
-            break;
-        case SVt_PVAV: {
-            SV **src_ary  = AvARRAY((AV *)sv);
-            SSize_t items = AvFILLp((AV *)sv) + 1;
-
-            while (items-- > 0) {
-            if(SvTYPE(*src_ary))
-                Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv *, SvIV(*src_ary)));
-                src_ary++;
+    dTHXc;
+    bool allowed = TRUE;
+
+    assert(PL_sharedsv_lock.owner == aTHX);
+    if (SvROK(sv)) {
+        SV *obj = SvRV(sv);
+        SV *sobj = Perl_sharedsv_find(aTHX_ obj);
+        if (sobj) {
+            SHARED_CONTEXT;
+            (void)SvUPGRADE(ssv, SVt_RV);
+            sv_setsv_nomg(ssv, &PL_sv_undef);
+
+            SvRV_set(ssv, SvREFCNT_inc(sobj));
+            SvROK_on(ssv);
+            if (SvOBJECT(sobj)) {
+                /* Remove any old blessing */
+                SvREFCNT_dec(SvSTASH(sobj));
+                SvOBJECT_off(sobj);
             }
-            break;
+            if (SvOBJECT(obj)) {
+              SV* fake_stash = newSVpv(HvNAME_get(SvSTASH(obj)),0);
+              SvOBJECT_on(sobj);
+              SvSTASH_set(sobj, (HV*)fake_stash);
+            }
+            CALLER_CONTEXT;
+        } else {
+            allowed = FALSE;
         }
-        case SVt_PVHV: {
-            HE *entry;
-            (void)hv_iterinit((HV *)sv);
-            while ((entry = hv_iternext((HV *)sv)))
-                Perl_sharedsv_thrcnt_dec(
-                    aTHX_ INT2PTR(shared_sv *, SvIV(hv_iterval((HV *)sv, entry)))
-                );
-            break;
+    } else {
+        SvTEMP_off(sv);
+        SHARED_CONTEXT;
+        sv_setsv_nomg(ssv, sv);
+        if (SvOBJECT(ssv)) {
+            /* Remove any old blessing */
+            SvREFCNT_dec(SvSTASH(ssv));
+            SvOBJECT_off(ssv);
         }
+        if (SvOBJECT(sv)) {
+          SV* fake_stash = newSVpv(HvNAME_get(SvSTASH(sv)),0);
+          SvOBJECT_on(ssv);
+          SvSTASH_set(ssv, (HV*)fake_stash);
         }
+        CALLER_CONTEXT;
+    }
+    if (!allowed) {
+        Perl_croak(aTHX_ "Invalid value for shared scalar");
     }
-    Perl_sv_free(PL_sharedsv_space,SHAREDSvGET(ssv));
-    SHAREDSvUNLOCK(ssv);
 }
 
+/* Set magic for PERL_MAGIC_shared_scalar(n) */
+
+int
+sharedsv_scalar_mg_set(pTHX_ SV *sv, MAGIC *mg)
+{
+    SV *ssv = (SV*)(mg->mg_ptr);
+    assert(ssv);
+    ENTER_LOCK;
+    if (SvTYPE(ssv) < SvTYPE(sv)) {
+        dTHXc;
+        SHARED_CONTEXT;
+        sv_upgrade(ssv, SvTYPE(sv));
+        CALLER_CONTEXT;
+    }
+    sharedsv_scalar_store(aTHX_ sv, ssv);
+    LEAVE_LOCK;
+    return (0);
+}
 
-MGVTBL svtable;
+/* Free magic for PERL_MAGIC_shared_scalar(n) */
 
-#define shared_sv_attach_sv(sv,shared) Perl_shared_sv_attach_sv(aTHX_ sv,shared)
+int
+sharedsv_scalar_mg_free(pTHX_ SV *sv, MAGIC *mg)
+{
+    S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
+    return (0);
+}
 
-SV* Perl_shared_sv_attach_sv (pTHX_ SV* sv, shared_sv* shared) {
-    HV* shared_hv = get_hv("threads::shared::shared", FALSE);
-    SV* id = newSViv(PTR2IV(shared));
-    STRLEN length = sv_len(id);
-    SV* tiedobject;
-    SV** tiedobject_ = hv_fetch(shared_hv, SvPV(id,length), length, 0);
-    if(tiedobject_) {
-       tiedobject = (*tiedobject_);
-       if(sv) {
-            SvROK_on(sv);
-            SvRV(sv) = SvRV(tiedobject);
-       } else {
-           sv = newRV(SvRV(tiedobject));
-       }
-    } else {
-       switch(SvTYPE(SHAREDSvGET(shared))) {
-           case SVt_PVAV: {
-               SV* weakref;
-               SV* obj_ref = newSViv(0);
-               SV* obj = newSVrv(obj_ref,"threads::shared::av");
-               AV* hv = newAV();
-               sv_setiv(obj,PTR2IV(shared));
-               weakref = newRV((SV*)hv);
-               sv = newRV_noinc((SV*)hv);
-               sv_rvweaken(weakref);
-               sv_magic((SV*) hv, obj_ref, PERL_MAGIC_tied, Nullch, 0);
-               hv_store(shared_hv, SvPV(id,length), length, weakref, 0);
-               Perl_sharedsv_thrcnt_inc(aTHX_ shared);         
-           }
-           break;
-           case SVt_PVHV: {
-               SV* weakref;
-               SV* obj_ref = newSViv(0);
-               SV* obj = newSVrv(obj_ref,"threads::shared::hv");
-               HV* hv = newHV();
-               sv_setiv(obj,PTR2IV(shared));
-               weakref = newRV((SV*)hv);
-               sv = newRV_noinc((SV*)hv);
-               sv_rvweaken(weakref);
-               sv_magic((SV*) hv, obj_ref, PERL_MAGIC_tied, Nullch, 0);
-               hv_store(shared_hv, SvPV(id,length), length, weakref, 0);
-               Perl_sharedsv_thrcnt_inc(aTHX_ shared);         
-           }
-           break;
-           default: {
-               MAGIC* shared_magic;
-               SV* value = newSVsv(SHAREDSvGET(shared));
-               SV* obj = newSViv(PTR2IV(shared));
-               sv_magic(value, 0, PERL_MAGIC_ext, "threads::shared", 16);
-               shared_magic = mg_find(value, PERL_MAGIC_ext);
-               shared_magic->mg_virtual = &svtable;
-               shared_magic->mg_obj = newSViv(PTR2IV(shared));
-               shared_magic->mg_flags |= MGf_REFCOUNTED;
-               shared_magic->mg_private = 0;
-               SvMAGICAL_on(value);
-               sv = newRV_noinc(value);
-               value = newRV(value);
-               sv_rvweaken(value);
-               hv_store(shared_hv, SvPV(id,length),length, value, 0);
-               Perl_sharedsv_thrcnt_inc(aTHX_ shared);
-           }
-               
-       }
+/*
+ * Called during cloning of PERL_MAGIC_shared_scalar(n) magic in new thread
+ */
+int
+sharedsv_scalar_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
+{
+    SvREFCNT_inc_void(mg->mg_ptr);
+    return (0);
+}
+
+#ifdef MGf_LOCAL
+/*
+ * Called during local $shared
+ */
+int
+sharedsv_scalar_mg_local(pTHX_ SV* nsv, MAGIC *mg)
+{
+    MAGIC *nmg;
+    SV *ssv = (SV *) mg->mg_ptr;
+    if (ssv) {
+        ENTER_LOCK;
+        SvREFCNT_inc_void(ssv);
+        LEAVE_LOCK;
     }
-    return sv;
+    nmg = sv_magicext(nsv, mg->mg_obj, mg->mg_type, mg->mg_virtual,
+                           mg->mg_ptr, mg->mg_len);
+    nmg->mg_flags   = mg->mg_flags;
+    nmg->mg_private = mg->mg_private;
+
+    return (0);
 }
+#endif
+
+MGVTBL sharedsv_scalar_vtbl = {
+    sharedsv_scalar_mg_get,     /* get */
+    sharedsv_scalar_mg_set,     /* set */
+    0,                          /* len */
+    0,                          /* clear */
+    sharedsv_scalar_mg_free,    /* free */
+    0,                          /* copy */
+    sharedsv_scalar_mg_dup,     /* dup */
+#ifdef MGf_LOCAL
+    sharedsv_scalar_mg_local,   /* local */
+#endif
+};
 
+/* ------------ PERL_MAGIC_tiedelem(p) functions -------------- */
 
-int shared_sv_fetch_mg (pTHX_ SV* sv, MAGIC *mg) {
-    shared_sv* shared = INT2PTR(shared_sv*, SvIV(mg->mg_obj));
-    SHAREDSvLOCK(shared);
-    if(mg->mg_private != shared->index) {
-        if(SvROK(SHAREDSvGET(shared))) {
-            shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(shared))));
-           shared_sv_attach_sv(sv, target);
+/* Get magic for PERL_MAGIC_tiedelem(p) */
+
+int
+sharedsv_elem_mg_FETCH(pTHX_ SV *sv, MAGIC *mg)
+{
+    dTHXc;
+    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    SV** svp;
+
+    ENTER_LOCK;
+    if (SvTYPE(saggregate) == SVt_PVAV) {
+        assert ( mg->mg_ptr == 0 );
+        SHARED_CONTEXT;
+        svp = av_fetch((AV*) saggregate, mg->mg_len, 0);
+    } else {
+        char *key = mg->mg_ptr;
+        STRLEN len = mg->mg_len;
+        assert ( mg->mg_ptr != 0 );
+        if (mg->mg_len == HEf_SVKEY) {
+           key = SvPV((SV *) mg->mg_ptr, len);
+        }
+        SHARED_CONTEXT;
+        svp = hv_fetch((HV*) saggregate, key, len, 0);
+    }
+    CALLER_CONTEXT;
+    if (svp) {
+        /* Exists in the array */
+        if (SvROK(*svp)) {
+            S_get_RV(aTHX_ sv, *svp);
         } else {
-            sv_setsv(sv, SHAREDSvGET(shared));
+            /* XXX Can this branch ever happen? DAPM */
+            /* XXX assert("no such branch"); */
+            Perl_sharedsv_associate(aTHX_ sv, *svp);
+            sv_setsv(sv, *svp);
         }
-        mg->mg_private = shared->index;
+    } else {
+        /* Not in the array */
+        sv_setsv(sv, &PL_sv_undef);
     }
-    SHAREDSvUNLOCK(shared);
-
-    return 0;
+    LEAVE_LOCK;
+    return (0);
 }
 
-int shared_sv_store_mg (pTHX_ SV* sv, MAGIC *mg) {
-    shared_sv* shared = INT2PTR(shared_sv*, SvIV(mg->mg_obj));
-    SHAREDSvLOCK(shared);
-    if(SvROK(SHAREDSvGET(shared)))
-        Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(shared)))));
-    if(SvROK(sv)) {
-        shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(sv));
-        if(!target) {
-            sv_setsv(sv,SHAREDSvGET(shared));
-            SHAREDSvUNLOCK(shared);
-            Perl_croak(aTHX_ "You cannot assign a non shared reference to a shared scalar");
-        }
-        SHAREDSvEDIT(shared);
-        Perl_sv_free(PL_sharedsv_space,SHAREDSvGET(shared));
-        SHAREDSvGET(shared) = newRV_noinc(newSViv(PTR2IV(target)));
+/* Set magic for PERL_MAGIC_tiedelem(p) */
+
+int
+sharedsv_elem_mg_STORE(pTHX_ SV *sv, MAGIC *mg)
+{
+    dTHXc;
+    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    SV **svp;
+    /* Theory - SV itself is magically shared - and we have ordered the
+       magic such that by the time we get here it has been stored
+       to its shared counterpart
+     */
+    ENTER_LOCK;
+    assert(saggregate);
+    if (SvTYPE(saggregate) == SVt_PVAV) {
+        assert ( mg->mg_ptr == 0 );
+        SHARED_CONTEXT;
+        svp = av_fetch((AV*) saggregate, mg->mg_len, 1);
     } else {
-            SHAREDSvEDIT(shared);
-       sv_setsv(SHAREDSvGET(shared), sv);
+        char *key = mg->mg_ptr;
+        STRLEN len = mg->mg_len;
+        assert ( mg->mg_ptr != 0 );
+        if (mg->mg_len == HEf_SVKEY)
+           key = SvPV((SV *) mg->mg_ptr, len);
+        SHARED_CONTEXT;
+        svp = hv_fetch((HV*) saggregate, key, len, 1);
     }
-    shared->index++;
-    mg->mg_private = shared->index;
-    SHAREDSvRELEASE(shared);
-    if(SvROK(SHAREDSvGET(shared)))
-       Perl_sharedsv_thrcnt_inc(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(shared)))));
-    SHAREDSvUNLOCK(shared);
-    return 0;
+    CALLER_CONTEXT;
+    Perl_sharedsv_associate(aTHX_ sv, *svp);
+    sharedsv_scalar_store(aTHX_ sv, *svp);
+    LEAVE_LOCK;
+    return (0);
 }
 
-int 
-shared_sv_destroy_mg (pTHX_ SV* sv, MAGIC *mg) 
+/* Clear magic for PERL_MAGIC_tiedelem(p) */
+
+int
+sharedsv_elem_mg_DELETE(pTHX_ SV *sv, MAGIC *mg)
 {
-    shared_sv* shared = INT2PTR(shared_sv*, SvIV(mg->mg_obj));
-    if (shared) {
-       HV* shared_hv = get_hv("threads::shared::shared", FALSE);
-        SV* id = newSViv(PTR2IV(shared));
-        STRLEN length = sv_len(id);
-        hv_delete(shared_hv, SvPV(id,length), length,0);
-       Perl_sharedsv_thrcnt_dec(aTHX_ shared);
+    dTHXc;
+    MAGIC *shmg;
+    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    ENTER_LOCK;
+    sharedsv_elem_mg_FETCH(aTHX_ sv, mg);
+    if ((shmg = mg_find(sv, PERL_MAGIC_shared_scalar)))
+        sharedsv_scalar_mg_get(aTHX_ sv, shmg);
+    if (SvTYPE(saggregate) == SVt_PVAV) {
+        SHARED_CONTEXT;
+        av_delete((AV*) saggregate, mg->mg_len, G_DISCARD);
+    } else {
+        char *key = mg->mg_ptr;
+        STRLEN len = mg->mg_len;
+        assert ( mg->mg_ptr != 0 );
+        if (mg->mg_len == HEf_SVKEY)
+           key = SvPV((SV *) mg->mg_ptr, len);
+        SHARED_CONTEXT;
+        hv_delete((HV*) saggregate, key, len, G_DISCARD);
     }
-    return 0;
+    CALLER_CONTEXT;
+    LEAVE_LOCK;
+    return (0);
 }
 
-MGVTBL svtable = {MEMBER_TO_FPTR(shared_sv_fetch_mg),
-                 MEMBER_TO_FPTR(shared_sv_store_mg),
-                 0,
-                 0,
-                 MEMBER_TO_FPTR(shared_sv_destroy_mg)
+/* Called during cloning of PERL_MAGIC_tiedelem(p) magic in new
+ * thread */
+
+int
+sharedsv_elem_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
+{
+    SvREFCNT_inc_void(S_sharedsv_from_obj(aTHX_ mg->mg_obj));
+    assert(mg->mg_flags & MGf_DUP);
+    return (0);
+}
+
+MGVTBL sharedsv_elem_vtbl = {
+    sharedsv_elem_mg_FETCH,     /* get */
+    sharedsv_elem_mg_STORE,     /* set */
+    0,                          /* len */
+    sharedsv_elem_mg_DELETE,    /* clear */
+    0,                          /* free */
+    0,                          /* copy */
+    sharedsv_elem_mg_dup,       /* dup */
+#ifdef MGf_LOCAL
+    0,                          /* local */
+#endif
 };
 
-MODULE = threads::shared               PACKAGE = threads::shared               
+/* ------------ PERL_MAGIC_tied(P) functions -------------- */
 
+/* Len magic for PERL_MAGIC_tied(P) */
 
-PROTOTYPES: ENABLE
+U32
+sharedsv_array_mg_FETCHSIZE(pTHX_ SV *sv, MAGIC *mg)
+{
+    dTHXc;
+    SV *ssv = (SV *) mg->mg_ptr;
+    U32 val;
+    SHARED_EDIT;
+    if (SvTYPE(ssv) == SVt_PVAV) {
+        val = av_len((AV*) ssv);
+    } else {
+        /* Not actually defined by tie API but ... */
+        val = HvKEYS((HV*) ssv);
+    }
+    SHARED_RELEASE;
+    return (val);
+}
 
+/* Clear magic for PERL_MAGIC_tied(P) */
 
-SV*
-ptr(ref)
-       SV* ref
-       CODE:
-       RETVAL = newSViv(SvIV(SvRV(ref)));
-       OUTPUT:
-       RETVAL
-
-
-SV*
-_thrcnt(ref)
-        SV* ref
-       CODE:
-        shared_sv* shared;
-       if(SvROK(ref))
-           ref = SvRV(ref);
-       shared = Perl_sharedsv_find(aTHX, ref);
-        if(!shared)
-           croak("thrcnt can only be used on shared values");
-       SHAREDSvLOCK(shared);
-        RETVAL = newSViv(SvREFCNT(SHAREDSvGET(shared)));
-        SHAREDSvUNLOCK(shared);
-       OUTPUT:
-        RETVAL
+int
+sharedsv_array_mg_CLEAR(pTHX_ SV *sv, MAGIC *mg)
+{
+    dTHXc;
+    SV *ssv = (SV *) mg->mg_ptr;
+    SHARED_EDIT;
+    if (SvTYPE(ssv) == SVt_PVAV) {
+        av_clear((AV*) ssv);
+    } else {
+        hv_clear((HV*) ssv);
+    }
+    SHARED_RELEASE;
+    return (0);
+}
 
+/* Free magic for PERL_MAGIC_tied(P) */
 
-void
-thrcnt_inc(ref,perl)
-        SV* ref
-       SV* perl
-        CODE:
-       shared_sv* shared;
-       PerlInterpreter* origperl = INT2PTR(PerlInterpreter*, SvIV(perl));
-       PerlInterpreter* oldperl = PERL_GET_CONTEXT;
-        if(SvROK(ref))
-            ref = SvRV(ref);
-        shared = Perl_sharedsv_find(aTHX, ref);
-        if(!shared)
-           croak("thrcnt can only be used on shared values");
-       PERL_SET_CONTEXT(origperl);
-       Perl_sharedsv_thrcnt_inc(aTHX_ shared);
-       PERL_SET_CONTEXT(oldperl);      
+int
+sharedsv_array_mg_free(pTHX_ SV *sv, MAGIC *mg)
+{
+    S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
+    return (0);
+}
+
+/*
+ * Copy magic for PERL_MAGIC_tied(P)
+ * This is called when perl is about to access an element of
+ * the array -
+ */
+int
+sharedsv_array_mg_copy(pTHX_ SV *sv, MAGIC* mg,
+                       SV *nsv, const char *name, int namlen)
+{
+    MAGIC *nmg = sv_magicext(nsv,mg->mg_obj,
+                            toLOWER(mg->mg_type),&sharedsv_elem_vtbl,
+                            name, namlen);
+    nmg->mg_flags |= MGf_DUP;
+    return (1);
+}
+
+/* Called during cloning of PERL_MAGIC_tied(P) magic in new thread */
+
+int
+sharedsv_array_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
+{
+    SvREFCNT_inc_void((SV*)mg->mg_ptr);
+    assert(mg->mg_flags & MGf_DUP);
+    return (0);
+}
+
+MGVTBL sharedsv_array_vtbl = {
+    0,                          /* get */
+    0,                          /* set */
+    sharedsv_array_mg_FETCHSIZE,/* len */
+    sharedsv_array_mg_CLEAR,    /* clear */
+    sharedsv_array_mg_free,     /* free */
+    sharedsv_array_mg_copy,     /* copy */
+    sharedsv_array_mg_dup,      /* dup */
+#ifdef MGf_LOCAL
+    0,                          /* local */
+#endif
+};
+
+
+/* Recursively unlocks a shared sv. */
 
 void
-_thrcnt_dec(ref)
-        SV* ref
-        CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(ref));
-        if(!shared)
-           croak("thrcnt can only be used on shared values");
-       Perl_sharedsv_thrcnt_dec(aTHX_ shared);
+Perl_sharedsv_unlock(pTHX_ SV *ssv)
+{
+    user_lock *ul = S_get_userlock(aTHX_ ssv, 0);
+    assert(ul);
+    recursive_lock_release(aTHX_ &ul->lock);
+}
+
 
+/* Recursive locks on a sharedsv.
+ * Locks are dynamically scoped at the level of the first lock.
+ */
 void
-unlock_enabled(ref)
-       SV* ref
-       PROTOTYPE: \[$@%]
-       CODE:
-       shared_sv* shared;
-       if(SvROK(ref))
-           ref = SvRV(ref);
-       shared = Perl_sharedsv_find(aTHX, ref);
-        if(!shared)
-           croak("unlock can only be used on shared values");
-       SHAREDSvUNLOCK(shared);
+Perl_sharedsv_lock(pTHX_ SV *ssv)
+{
+    user_lock *ul;
+    if (! ssv)
+        return;
+    ul = S_get_userlock(aTHX_ ssv, 1);
+    recursive_lock_acquire(aTHX_ &ul->lock, __FILE__, __LINE__);
+}
+
+/* Handles calls from lock() builtin via PL_lockhook */
 
 void
-lock_enabled(ref)
-        SV* ref
-        CODE:
-        shared_sv* shared;
-        if(SvROK(ref))
-            ref = SvRV(ref);
-        shared = Perl_sharedsv_find(aTHX, ref);
-        if(!shared)
-           croak("lock can only be used on shared values");
-        SHAREDSvLOCK(shared);
+Perl_sharedsv_locksv(pTHX_ SV *sv)
+{
+    SV *ssv;
+
+    if (SvROK(sv))
+        sv = SvRV(sv);
+    ssv = Perl_sharedsv_find(aTHX_ sv);
+    if (!ssv)
+       croak("lock can only be used on shared values");
+    Perl_sharedsv_lock(aTHX_ ssv);
+}
 
 
+/* Saves a space for keeping SVs wider than an interpreter. */
+
 void
-cond_wait_enabled(ref)
-       SV* ref
-       PROTOTYPE: \[$@%]
-       CODE:
-       shared_sv* shared;
-       int locks;
-       if(SvROK(ref))
-           ref = SvRV(ref);
-       shared = Perl_sharedsv_find(aTHX_ ref);
-       if(!shared)
-           croak("cond_wait can only be used on shared values");
-       if(shared->owner != PERL_GET_CONTEXT)
-           croak("You need a lock before you can cond_wait");
-       MUTEX_LOCK(&shared->mutex);
-       shared->owner = NULL;
-       locks = shared->locks = 0;
-       COND_WAIT(&shared->user_cond, &shared->mutex);
-       shared->owner = PERL_GET_CONTEXT;
-       shared->locks = locks;
-       MUTEX_UNLOCK(&shared->mutex);
-
-void cond_signal_enabled(ref)
-       SV* ref
-       PROTOTYPE: \[$@%]
-       CODE:
-       shared_sv* shared;
-       if(SvROK(ref))
-           ref = SvRV(ref);
-       shared = Perl_sharedsv_find(aTHX_ ref);
-       if(!shared)
-           croak("cond_signal can only be used on shared values");
-       COND_SIGNAL(&shared->user_cond);
-
-
-void cond_broadcast_enabled(ref)
-       SV* ref
-       PROTOTYPE: \[$@%]
-       CODE:
-       shared_sv* shared;
-       if(SvROK(ref))
-           ref = SvRV(ref);
-       shared = Perl_sharedsv_find(aTHX_ ref);
-       if(!shared)
-           croak("cond_broadcast can only be used on shared values");
-       COND_BROADCAST(&shared->user_cond);
-
-MODULE = threads::shared               PACKAGE = threads::shared::sv           
-
-SV*
-new(class, value)
-       SV* class
-       SV* value
-       CODE:
-       shared_sv* shared = Perl_sharedsv_new(aTHX);
-        MAGIC* shared_magic;
-       SV* obj = newSViv(PTR2IV(shared));
-       SHAREDSvEDIT(shared);
-       SHAREDSvGET(shared) = newSVsv(value);
-        SHAREDSvRELEASE(shared);
-       sv_magic(value, 0, PERL_MAGIC_ext, "threads::shared", 16);
-        shared_magic = mg_find(value, PERL_MAGIC_ext);
-        shared_magic->mg_virtual = &svtable;
-        shared_magic->mg_obj = newSViv(PTR2IV(shared));
-        shared_magic->mg_flags |= MGf_REFCOUNTED;
-        shared_magic->mg_private = 0;
-        SvMAGICAL_on(value);
-        RETVAL = obj;
-        OUTPUT:                
-        RETVAL
+Perl_sharedsv_init(pTHX)
+{
+    dTHXc;
+    /* This pair leaves us in shared context ... */
+    PL_sharedsv_space = perl_alloc();
+    perl_construct(PL_sharedsv_space);
+    CALLER_CONTEXT;
+    recursive_lock_init(aTHX_ &PL_sharedsv_lock);
+    PL_lockhook = &Perl_sharedsv_locksv;
+    PL_sharehook = &Perl_sharedsv_share;
+}
 
+#endif /* USE_ITHREADS */
 
-MODULE = threads::shared               PACKAGE = threads::shared::av
-
-SV*
-new(class, value)
-       SV* class
-       SV* value
-       CODE:
-       shared_sv* shared = Perl_sharedsv_new(aTHX);
-       SV* obj = newSViv(PTR2IV(shared));
-        SHAREDSvEDIT(shared);
-        SHAREDSvGET(shared) = (SV*) newAV();
-        SHAREDSvRELEASE(shared);
-        RETVAL = obj;
-        OUTPUT:
-        RETVAL
+MODULE = threads::shared        PACKAGE = threads::shared::tie
+
+PROTOTYPES: DISABLE
+
+#ifdef USE_ITHREADS
 
 void
-STORE(self, index, value)
-        SV* self
-       SV* index
-        SV* value
-        CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-        shared_sv* slot;
-        SV* aentry;
-       SV** aentry_;
-       if(SvROK(value)) {
-           shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(value));
-           if(!target) {
-                Perl_croak(aTHX_ "You cannot assign a non shared reference to a shared array");
-           }
-            value = newRV_noinc(newSViv(PTR2IV(target)));
+PUSH(SV *obj, ...)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        int i;
+        for (i = 1; i < items; i++) {
+            SV* tmp = newSVsv(ST(i));
+            SV *stmp;
+            ENTER_LOCK;
+            stmp = S_sharedsv_new_shared(aTHX_ tmp);
+            sharedsv_scalar_store(aTHX_ tmp, stmp);
+            SHARED_CONTEXT;
+            av_push((AV*) sobj, stmp);
+            SvREFCNT_inc_void(stmp);
+            SHARED_RELEASE;
+            SvREFCNT_dec(tmp);
         }
-       SHAREDSvLOCK(shared);
-       aentry_ = av_fetch((AV*) SHAREDSvGET(shared), SvIV(index), 0);
-       if(aentry_ && SvIV((*aentry_))) {
-           aentry = (*aentry_);
-            slot = INT2PTR(shared_sv*, SvIV(aentry));
-            if(SvROK(SHAREDSvGET(slot)))
-                Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-            SHAREDSvEDIT(slot);
-            sv_setsv(SHAREDSvGET(slot), value);
-            SHAREDSvRELEASE(slot);
-       } else {
-            slot = Perl_sharedsv_new(aTHX);
-            SHAREDSvEDIT(shared);
-            SHAREDSvGET(slot) = newSVsv(value);
-            aentry = newSViv(PTR2IV(slot));
-            av_store((AV*) SHAREDSvGET(shared), SvIV(index), aentry);
-            SHAREDSvRELEASE(shared);
-       }
-        if(SvROK(SHAREDSvGET(slot)))
-            Perl_sharedsv_thrcnt_inc(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-
-        SHAREDSvUNLOCK(shared);
-
-SV*
-FETCH(self, index)
-        SV* self
-       SV* index
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-       SV* aentry;
-       SV** aentry_;
-       SV* retval;
-       SHAREDSvLOCK(shared);
-       aentry_ = av_fetch((AV*) SHAREDSvGET(shared), SvIV(index),0);
-       if(aentry_) {
-           aentry = (*aentry_);
-            if(SvTYPE(aentry) == SVt_NULL) {
-               retval = &PL_sv_undef;
-           } else {
-               slot = INT2PTR(shared_sv*, SvIV(aentry));
-               if(SvROK(SHAREDSvGET(slot))) {
-                    shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                    retval = Perl_shared_sv_attach_sv(aTHX_ NULL,target);
-               } else {
-                    retval = newSVsv(SHAREDSvGET(slot));
-               }
-            }
-       } else {
-           retval = &PL_sv_undef;
-       }
-        SHAREDSvUNLOCK(shared);        
-        RETVAL = retval;
-        OUTPUT:
-        RETVAL
+
 
 void
-PUSH(self, ...)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
+UNSHIFT(SV *obj, ...)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
         int i;
-        SHAREDSvLOCK(shared);
-       for(i = 1; i < items; i++) {
-           shared_sv* slot = Perl_sharedsv_new(aTHX);
-           SV* tmp = ST(i);
-           if(SvROK(tmp)) {
-                 shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(tmp));
-                 if(!target) {
-                     Perl_croak(aTHX_ "You cannot assign a non shared reference to a shared array");
-                 }
-                 tmp = newRV_noinc(newSViv(PTR2IV(target)));
-            }
-            SHAREDSvEDIT(slot);
-           SHAREDSvGET(slot) = newSVsv(tmp);
-           av_push((AV*) SHAREDSvGET(shared), newSViv(PTR2IV(slot)));
-           SHAREDSvRELEASE(slot);
-           if(SvROK(SHAREDSvGET(slot)))
-                Perl_sharedsv_thrcnt_inc(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-       }
-        SHAREDSvUNLOCK(shared);
+        ENTER_LOCK;
+        SHARED_CONTEXT;
+        av_unshift((AV*)sobj, items - 1);
+        CALLER_CONTEXT;
+        for (i = 1; i < items; i++) {
+            SV *tmp = newSVsv(ST(i));
+            SV *stmp = S_sharedsv_new_shared(aTHX_ tmp);
+            sharedsv_scalar_store(aTHX_ tmp, stmp);
+            SHARED_CONTEXT;
+            av_store((AV*) sobj, i - 1, stmp);
+            SvREFCNT_inc_void(stmp);
+            CALLER_CONTEXT;
+            SvREFCNT_dec(tmp);
+        }
+        LEAVE_LOCK;
+
 
 void
-UNSHIFT(self, ...)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-        int i;
-        SHAREDSvLOCK(shared);
-       SHAREDSvEDIT(shared);
-       av_unshift((AV*)SHAREDSvGET(shared), items - 1);
-       SHAREDSvRELEASE(shared);
-       for(i = 1; i < items; i++) {
-           shared_sv* slot = Perl_sharedsv_new(aTHX);
-           SV* tmp = ST(i);
-           if(SvROK(tmp)) {
-                 shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(tmp));
-                 if(!target) {
-                     Perl_croak(aTHX_ "You cannot assign a non shared reference to a shared array");
-                 }
-                 tmp = newRV_noinc(newSViv(PTR2IV(target)));
-            }
-            SHAREDSvEDIT(slot);
-           SHAREDSvGET(slot) = newSVsv(tmp);
-           av_store((AV*) SHAREDSvGET(shared), i - 1, newSViv(PTR2IV(slot)));
-           SHAREDSvRELEASE(slot);
-           if(SvROK(SHAREDSvGET(slot)))
-                Perl_sharedsv_thrcnt_inc(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-       }
-        SHAREDSvUNLOCK(shared);
-
-SV*
-POP(self)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-       SV* retval;
-       SHAREDSvLOCK(shared);
-       SHAREDSvEDIT(shared);
-       retval = av_pop((AV*)SHAREDSvGET(shared));
-       SHAREDSvRELEASE(shared);
-       if(retval && SvIV(retval)) {
-           slot = INT2PTR(shared_sv*, SvIV(retval));
-           if(SvROK(SHAREDSvGET(slot))) {
-                shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                retval = Perl_shared_sv_attach_sv(aTHX_ NULL,target);
-           } else {
-                retval = newSVsv(SHAREDSvGET(slot));
-            }
-            Perl_sharedsv_thrcnt_dec(aTHX_ slot);
-       } else {
-            retval = &PL_sv_undef;
-       }
-       SHAREDSvUNLOCK(shared);
-       RETVAL = retval;
-       OUTPUT:
-       RETVAL
-
-
-SV*
-SHIFT(self)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-       SV* retval;
-       SHAREDSvLOCK(shared);
-       SHAREDSvEDIT(shared);
-       retval = av_shift((AV*)SHAREDSvGET(shared));
-       SHAREDSvRELEASE(shared);
-       if(retval && SvIV(retval)) {
-           slot = INT2PTR(shared_sv*, SvIV(retval));
-            if(SvROK(SHAREDSvGET(slot))) {
-                 shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                 retval = Perl_shared_sv_attach_sv(aTHX_ NULL,target);
-            } else {
-                 retval = newSVsv(SHAREDSvGET(slot));
-            }
-            Perl_sharedsv_thrcnt_dec(aTHX_ slot);
-       } else {
-            retval = &PL_sv_undef;
-       }
-       SHAREDSvUNLOCK(shared);
-       RETVAL = retval;
-       OUTPUT:
-       RETVAL
+POP(SV *obj)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV* ssv;
+        ENTER_LOCK;
+        SHARED_CONTEXT;
+        ssv = av_pop((AV*)sobj);
+        CALLER_CONTEXT;
+        ST(0) = sv_newmortal();
+        Perl_sharedsv_associate(aTHX_ ST(0), ssv);
+        SvREFCNT_dec(ssv);
+        LEAVE_LOCK;
+        /* XSRETURN(1); - implied */
+
 
 void
-CLEAR(self)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-       SV** svp;
-       I32 i;
-       SHAREDSvLOCK(shared);
-       svp = AvARRAY((AV*)SHAREDSvGET(shared));
-       i   = AvFILLp((AV*)SHAREDSvGET(shared));
-       while ( i >= 0) {
-           if(SvIV(svp[i])) {
-               Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv*, SvIV(svp[i])));
-           }
-           i--;
-       }
-       SHAREDSvEDIT(shared);
-       av_clear((AV*)SHAREDSvGET(shared));
-       SHAREDSvRELEASE(shared);
-       SHAREDSvUNLOCK(shared);
-       
+SHIFT(SV *obj)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV* ssv;
+        ENTER_LOCK;
+        SHARED_CONTEXT;
+        ssv = av_shift((AV*)sobj);
+        CALLER_CONTEXT;
+        ST(0) = sv_newmortal();
+        Perl_sharedsv_associate(aTHX_ ST(0), ssv);
+        SvREFCNT_dec(ssv);
+        LEAVE_LOCK;
+        /* XSRETURN(1); - implied */
+
+
 void
-EXTEND(self, count)
-       SV* self
-       SV* count
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       SHAREDSvEDIT(shared);
-       av_extend((AV*)SHAREDSvGET(shared), (I32) SvIV(count));
-       SHAREDSvRELEASE(shared);
-
-
-
-
-SV*
-EXISTS(self, index)
-       SV* self
-       SV* index
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       I32 exists;
-       SHAREDSvLOCK(shared);
-       exists = av_exists((AV*) SHAREDSvGET(shared), (I32) SvIV(index));
-       if(exists) {
-           RETVAL = &PL_sv_yes;
-       } else {
-           RETVAL = &PL_sv_no;
-       }
-       SHAREDSvUNLOCK(shared);
+EXTEND(SV *obj, IV count)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SHARED_EDIT;
+        av_extend((AV*)sobj, count);
+        SHARED_RELEASE;
+
 
 void
-STORESIZE(self,count)
-       SV* self
-       SV* count
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       SHAREDSvEDIT(shared);
-       av_fill((AV*) SHAREDSvGET(shared), (I32) SvIV(count));
-       SHAREDSvRELEASE(shared);
-
-SV*
-FETCHSIZE(self)
-       SV* self
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       SHAREDSvLOCK(shared);
-       RETVAL = newSViv(av_len((AV*) SHAREDSvGET(shared)) + 1);
-       SHAREDSvUNLOCK(shared);
-       OUTPUT:
-       RETVAL
-
-SV*
-DELETE(self,index)
-       SV* self
-       SV* index
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-       SHAREDSvLOCK(shared);
-       if(av_exists((AV*) SHAREDSvGET(shared), (I32) SvIV(index))) {
-           SV* tmp;
-           SHAREDSvEDIT(shared);
-           tmp = av_delete((AV*)SHAREDSvGET(shared), (I32) SvIV(index),0);
-           SHAREDSvRELEASE(shared);
-           if(SvIV(tmp)) {
-               slot = INT2PTR(shared_sv*, SvIV(tmp));
-                if(SvROK(SHAREDSvGET(slot))) {
-                   shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                   RETVAL = Perl_shared_sv_attach_sv(aTHX_ NULL,target);
-                } else {
-                   RETVAL = newSVsv(SHAREDSvGET(slot));
-                }
-                Perl_sharedsv_thrcnt_dec(aTHX_ slot);
-           } else {
-                RETVAL = &PL_sv_undef;
-           }   
-       } else {
-           RETVAL = &PL_sv_undef;
-       }       
-       SHAREDSvUNLOCK(shared);
-       OUTPUT:
-       RETVAL
-
-AV*
-SPLICE(self, offset, length, ...)
-       SV* self
-       SV* offset
-       SV* length
-       CODE:
-       croak("Splice is not implmented for shared arrays");
-       
-MODULE = threads::shared               PACKAGE = threads::shared::hv
-
-SV*
-new(class, value)
-       SV* class
-       SV* value
-       CODE:
-       shared_sv* shared = Perl_sharedsv_new(aTHX);
-       SV* obj = newSViv(PTR2IV(shared));
-        SHAREDSvEDIT(shared);
-        SHAREDSvGET(shared) = (SV*) newHV();
-        SHAREDSvRELEASE(shared);
-        RETVAL = obj;
-        OUTPUT:
-        RETVAL
+STORESIZE(SV *obj,IV count)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SHARED_EDIT;
+        av_fill((AV*) sobj, count);
+        SHARED_RELEASE;
+
 
 void
-STORE(self, key, value)
-        SV* self
-        SV* key
-        SV* value
-        CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-        shared_sv* slot;
-        SV* hentry;
-        SV** hentry_;
-       STRLEN len;
-       char* ckey = SvPV(key, len);
-        SHAREDSvLOCK(shared);
-       if(SvROK(value)) {
-           shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(value));
-           if(!target) {
-               Perl_croak(aTHX_ "You cannot assign a non shared reference to a shared hash");
-            }
-           SHAREDSvEDIT(shared);
-           value = newRV_noinc(newSViv(PTR2IV(target)));
-           SHAREDSvRELEASE(shared);
-       }
-        hentry_ = hv_fetch((HV*) SHAREDSvGET(shared), ckey, len, 0);
-        if(hentry_ && SvIV((*hentry_))) {
-            hentry = (*hentry_);
-            slot = INT2PTR(shared_sv*, SvIV(hentry));
-            if(SvROK(SHAREDSvGET(slot)))
-                Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-            SHAREDSvEDIT(slot);
-            sv_setsv(SHAREDSvGET(slot), value);
-            SHAREDSvRELEASE(slot);
+EXISTS(SV *obj, SV *index)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        bool exists;
+        if (SvTYPE(sobj) == SVt_PVAV) {
+            SHARED_EDIT;
+            exists = av_exists((AV*) sobj, SvIV(index));
         } else {
-            slot = Perl_sharedsv_new(aTHX);
-            SHAREDSvEDIT(shared);
-            SHAREDSvGET(slot) = newSVsv(value);
-            hentry = newSViv(PTR2IV(slot));
-            hv_store((HV*) SHAREDSvGET(shared), ckey,len , hentry, 0);
-            SHAREDSvRELEASE(shared);
+            STRLEN len;
+            char *key = SvPV(index,len);
+            SHARED_EDIT;
+            exists = hv_exists((HV*) sobj, key, len);
         }
-       if(SvROK(SHAREDSvGET(slot)))
-           Perl_sharedsv_thrcnt_inc(aTHX_ INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot)))));
-        SHAREDSvUNLOCK(shared);
-
-
-SV*
-FETCH(self, key)
-        SV* self
-        SV* key
-        CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-        shared_sv* slot;
-        SV* hentry;
-        SV** hentry_;
-        SV* retval;
-       STRLEN len;
-       char* ckey = SvPV(key, len);
-        SHAREDSvLOCK(shared);
-        hentry_ = hv_fetch((HV*) SHAREDSvGET(shared), ckey, len,0);
-        if(hentry_) {
-            hentry = (*hentry_);
-            if(SvTYPE(hentry) == SVt_NULL) {
-                retval = &PL_sv_undef;
-            } else {
-                slot = INT2PTR(shared_sv*, SvIV(hentry));
-               if(SvROK(SHAREDSvGET(slot))) {
-                   shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                   retval = Perl_shared_sv_attach_sv(aTHX_ NULL, target);
-               } else {
-                   retval = newSVsv(SHAREDSvGET(slot));
-               }
-            }
+        SHARED_RELEASE;
+        ST(0) = (exists) ? &PL_sv_yes : &PL_sv_no;
+        /* XSRETURN(1); - implied */
+
+
+void
+FIRSTKEY(SV *obj)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        char* key = NULL;
+        I32 len = 0;
+        HE* entry;
+        ENTER_LOCK;
+        SHARED_CONTEXT;
+        hv_iterinit((HV*) sobj);
+        entry = hv_iternext((HV*) sobj);
+        if (entry) {
+            key = hv_iterkey(entry,&len);
+            CALLER_CONTEXT;
+            ST(0) = sv_2mortal(newSVpv(key, len));
         } else {
-            retval = &PL_sv_undef;
+            CALLER_CONTEXT;
+            ST(0) = &PL_sv_undef;
         }
-        SHAREDSvUNLOCK(shared);
-        RETVAL = retval;
-        OUTPUT:
-        RETVAL
+        LEAVE_LOCK;
+        /* XSRETURN(1); - implied */
+
 
 void
-CLEAR(self)
-       SV* self
-       CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-        shared_sv* slot;
-       HE* entry;
-       SHAREDSvLOCK(shared);
-       Perl_hv_iterinit(PL_sharedsv_space, (HV*) SHAREDSvGET(shared));
-       entry = Perl_hv_iternext(PL_sharedsv_space, (HV*) SHAREDSvGET(shared));
-       while(entry) {
-               slot = INT2PTR(shared_sv*, SvIV(Perl_hv_iterval(PL_sharedsv_space, (HV*) SHAREDSvGET(shared), entry)));
-               Perl_sharedsv_thrcnt_dec(aTHX_ slot);
-               entry = Perl_hv_iternext(PL_sharedsv_space,(HV*) SHAREDSvGET(shared));
-       }
-       SHAREDSvEDIT(shared);
-       hv_clear((HV*) SHAREDSvGET(shared));
-       SHAREDSvRELEASE(shared);
-       SHAREDSvUNLOCK(shared);
-
-SV*
-FIRSTKEY(self)
-       SV* self
-       CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       char* key = NULL;
-       I32 len;
-       HE* entry;
-       SHAREDSvLOCK(shared);
-        Perl_hv_iterinit(PL_sharedsv_space, (HV*) SHAREDSvGET(shared));
-        entry = Perl_hv_iternext(PL_sharedsv_space, (HV*) SHAREDSvGET(shared));
-       if(entry) {
-                key = Perl_hv_iterkey(PL_sharedsv_space, entry,&len);
-               RETVAL = newSVpv(key, len);
-        } else {
-            RETVAL = &PL_sv_undef;
-       }
-        SHAREDSvUNLOCK(shared);
-       OUTPUT:
-       RETVAL
-
-
-SV*
-NEXTKEY(self, oldkey)
-        SV* self
-       SV* oldkey
-        CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
+NEXTKEY(SV *obj, SV *oldkey)
+    CODE:
+        dTHXc;
+        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
         char* key = NULL;
-        I32 len;
+        I32 len = 0;
         HE* entry;
-        SHAREDSvLOCK(shared);
-        entry = Perl_hv_iternext(PL_sharedsv_space, (HV*) SHAREDSvGET(shared));
-        if(entry) {
-                key = Perl_hv_iterkey(PL_sharedsv_space, entry,&len);
-                RETVAL = newSVpv(key, len);
+
+        PERL_UNUSED_VAR(oldkey);
+
+        ENTER_LOCK;
+        SHARED_CONTEXT;
+        entry = hv_iternext((HV*) sobj);
+        if (entry) {
+            key = hv_iterkey(entry,&len);
+            CALLER_CONTEXT;
+            ST(0) = sv_2mortal(newSVpv(key, len));
         } else {
-             RETVAL = &PL_sv_undef;
+            CALLER_CONTEXT;
+            ST(0) = &PL_sv_undef;
         }
-        SHAREDSvUNLOCK(shared);
-        OUTPUT:
-        RETVAL
+        LEAVE_LOCK;
+        /* XSRETURN(1); - implied */
 
 
-SV*
-EXISTS(self, key)
-       SV* self
-       SV* key
-       CODE:
-       shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       STRLEN len;
-       char* ckey = SvPV(key, len);
-       SHAREDSvLOCK(shared);
-       if(hv_exists((HV*)SHAREDSvGET(shared), ckey, len)) {
-               RETVAL = &PL_sv_yes;
-       } else {
-               RETVAL = &PL_sv_no;
-       }
-       SHAREDSvUNLOCK(shared);
-       OUTPUT:
-       RETVAL
-
-SV*
-DELETE(self, key)
-        SV* self
-        SV* key
-        CODE:
-        shared_sv* shared = INT2PTR(shared_sv*, SvIV(SvRV(self)));
-       shared_sv* slot;
-        STRLEN len;
-        char* ckey = SvPV(key, len);
-        SV* tmp;
-       SHAREDSvLOCK(shared);
-       SHAREDSvEDIT(shared);
-       tmp = hv_delete((HV*) SHAREDSvGET(shared), ckey, len,0);
-       SHAREDSvRELEASE(shared);
-       if(tmp) {
-               slot = INT2PTR(shared_sv*, SvIV(tmp));
-               if(SvROK(SHAREDSvGET(slot))) {
-                   shared_sv* target = INT2PTR(shared_sv*, SvIV(SvRV(SHAREDSvGET(slot))));
-                   RETVAL = Perl_shared_sv_attach_sv(aTHX_ NULL, target);
-               } else {
-                   RETVAL = newSVsv(SHAREDSvGET(slot));
-               }
-               Perl_sharedsv_thrcnt_dec(aTHX_ slot);
-       } else {
-               RETVAL = &PL_sv_undef;
-       }
-        SHAREDSvUNLOCK(shared);
-        OUTPUT:
+MODULE = threads::shared        PACKAGE = threads::shared
+
+PROTOTYPES: ENABLE
+
+void
+_id(SV *ref)
+    PROTOTYPE: \[$@%]
+    PREINIT:
+        SV *ssv;
+    CODE:
+        ref = SvRV(ref);
+        if (SvROK(ref))
+            ref = SvRV(ref);
+        ssv = Perl_sharedsv_find(aTHX_ ref);
+        if (! ssv)
+            XSRETURN_UNDEF;
+        ST(0) = sv_2mortal(newSVuv(PTR2UV(ssv)));
+        /* XSRETURN(1); - implied */
+
+
+void
+_refcnt(SV *ref)
+    PROTOTYPE: \[$@%]
+    PREINIT:
+        SV *ssv;
+    CODE:
+        ref = SvRV(ref);
+        if (SvROK(ref))
+            ref = SvRV(ref);
+        ssv = Perl_sharedsv_find(aTHX_ ref);
+        if (! ssv) {
+            if (ckWARN(WARN_THREADS)) {
+                Perl_warner(aTHX_ packWARN(WARN_THREADS),
+                                "%" SVf " is not shared", ST(0));
+            }
+            XSRETURN_UNDEF;
+        }
+        ST(0) = sv_2mortal(newSViv(SvREFCNT(ssv)));
+        /* XSRETURN(1); - implied */
+
+
+void
+share(SV *ref)
+    PROTOTYPE: \[$@%]
+    CODE:
+        if (! SvROK(ref))
+            Perl_croak(aTHX_ "Argument to share needs to be passed as ref");
+        ref = SvRV(ref);
+        if (SvROK(ref))
+            ref = SvRV(ref);
+        Perl_sharedsv_share(aTHX_ ref);
+        ST(0) = sv_2mortal(newRV_inc(ref));
+        /* XSRETURN(1); - implied */
+
+
+void
+cond_wait(SV *ref_cond, SV *ref_lock = 0)
+    PROTOTYPE: \[$@%];\[$@%]
+    PREINIT:
+        SV *ssv;
+        perl_cond* user_condition;
+        int locks;
+        user_lock *ul;
+    CODE:
+        if (!SvROK(ref_cond))
+            Perl_croak(aTHX_ "Argument to cond_wait needs to be passed as ref");
+        ref_cond = SvRV(ref_cond);
+        if (SvROK(ref_cond))
+            ref_cond = SvRV(ref_cond);
+        ssv = Perl_sharedsv_find(aTHX_ ref_cond);
+        if (! ssv)
+            Perl_croak(aTHX_ "cond_wait can only be used on shared values");
+        ul = S_get_userlock(aTHX_ ssv, 1);
+
+        user_condition = &ul->user_cond;
+        if (ref_lock && (ref_cond != ref_lock)) {
+            if (!SvROK(ref_lock))
+                Perl_croak(aTHX_ "cond_wait lock needs to be passed as ref");
+            ref_lock = SvRV(ref_lock);
+            if (SvROK(ref_lock)) ref_lock = SvRV(ref_lock);
+            ssv = Perl_sharedsv_find(aTHX_ ref_lock);
+            if (! ssv)
+                Perl_croak(aTHX_ "cond_wait lock must be a shared value");
+            ul = S_get_userlock(aTHX_ ssv, 1);
+        }
+        if (ul->lock.owner != aTHX)
+            croak("You need a lock before you can cond_wait");
+
+        /* Stealing the members of the lock object worries me - NI-S */
+        MUTEX_LOCK(&ul->lock.mutex);
+        ul->lock.owner = NULL;
+        locks = ul->lock.locks;
+        ul->lock.locks = 0;
+
+        /* Since we are releasing the lock here, we need to tell other
+         * people that it is ok to go ahead and use it */
+        COND_SIGNAL(&ul->lock.cond);
+        COND_WAIT(user_condition, &ul->lock.mutex);
+        while (ul->lock.owner != NULL) {
+            /* OK -- must reacquire the lock */
+            COND_WAIT(&ul->lock.cond, &ul->lock.mutex);
+        }
+        ul->lock.owner = aTHX;
+        ul->lock.locks = locks;
+        MUTEX_UNLOCK(&ul->lock.mutex);
+
+
+int
+cond_timedwait(SV *ref_cond, double abs, SV *ref_lock = 0)
+    PROTOTYPE: \[$@%]$;\[$@%]
+    PREINIT:
+        SV *ssv;
+        perl_cond* user_condition;
+        int locks;
+        user_lock *ul;
+    CODE:
+        if (! SvROK(ref_cond))
+            Perl_croak(aTHX_ "Argument to cond_timedwait needs to be passed as ref");
+        ref_cond = SvRV(ref_cond);
+        if (SvROK(ref_cond))
+            ref_cond = SvRV(ref_cond);
+        ssv = Perl_sharedsv_find(aTHX_ ref_cond);
+        if (! ssv)
+            Perl_croak(aTHX_ "cond_timedwait can only be used on shared values");
+        ul = S_get_userlock(aTHX_ ssv, 1);
+
+        user_condition = &ul->user_cond;
+        if (ref_lock && (ref_cond != ref_lock)) {
+            if (! SvROK(ref_lock))
+                Perl_croak(aTHX_ "cond_timedwait lock needs to be passed as ref");
+            ref_lock = SvRV(ref_lock);
+            if (SvROK(ref_lock)) ref_lock = SvRV(ref_lock);
+            ssv = Perl_sharedsv_find(aTHX_ ref_lock);
+            if (! ssv)
+                Perl_croak(aTHX_ "cond_timedwait lock must be a shared value");
+            ul = S_get_userlock(aTHX_ ssv, 1);
+        }
+        if (ul->lock.owner != aTHX)
+            Perl_croak(aTHX_ "You need a lock before you can cond_wait");
+
+        MUTEX_LOCK(&ul->lock.mutex);
+        ul->lock.owner = NULL;
+        locks = ul->lock.locks;
+        ul->lock.locks = 0;
+        /* Since we are releasing the lock here, we need to tell other
+         * people that it is ok to go ahead and use it */
+        COND_SIGNAL(&ul->lock.cond);
+        RETVAL = Perl_sharedsv_cond_timedwait(user_condition, &ul->lock.mutex, abs);
+        while (ul->lock.owner != NULL) {
+            /* OK -- must reacquire the lock... */
+            COND_WAIT(&ul->lock.cond, &ul->lock.mutex);
+        }
+        ul->lock.owner = aTHX;
+        ul->lock.locks = locks;
+        MUTEX_UNLOCK(&ul->lock.mutex);
+
+        if (RETVAL == 0)
+            XSRETURN_UNDEF;
+    OUTPUT:
         RETVAL
 
+
+void
+cond_signal(SV *ref)
+    PROTOTYPE: \[$@%]
+    PREINIT:
+        SV *ssv;
+        user_lock *ul;
+    CODE:
+        if (! SvROK(ref))
+            Perl_croak(aTHX_ "Argument to cond_signal needs to be passed as ref");
+        ref = SvRV(ref);
+        if (SvROK(ref))
+            ref = SvRV(ref);
+        ssv = Perl_sharedsv_find(aTHX_ ref);
+        if (! ssv)
+            Perl_croak(aTHX_ "cond_signal can only be used on shared values");
+        ul = S_get_userlock(aTHX_ ssv, 1);
+        if (ckWARN(WARN_THREADS) && ul->lock.owner != aTHX) {
+            Perl_warner(aTHX_ packWARN(WARN_THREADS),
+                            "cond_signal() called on unlocked variable");
+        }
+        COND_SIGNAL(&ul->user_cond);
+
+
+void
+cond_broadcast(SV *ref)
+    PROTOTYPE: \[$@%]
+    PREINIT:
+        SV *ssv;
+        user_lock *ul;
+    CODE:
+        if (! SvROK(ref))
+            Perl_croak(aTHX_ "Argument to cond_broadcast needs to be passed as ref");
+        ref = SvRV(ref);
+        if (SvROK(ref))
+            ref = SvRV(ref);
+        ssv = Perl_sharedsv_find(aTHX_ ref);
+        if (! ssv)
+            Perl_croak(aTHX_ "cond_broadcast can only be used on shared values");
+        ul = S_get_userlock(aTHX_ ssv, 1);
+        if (ckWARN(WARN_THREADS) && ul->lock.owner != aTHX) {
+            Perl_warner(aTHX_ packWARN(WARN_THREADS),
+                            "cond_broadcast() called on unlocked variable");
+        }
+        COND_BROADCAST(&ul->user_cond);
+
+
+void
+bless(SV* ref, ...);
+    PROTOTYPE: $;$
+    PREINIT:
+        HV* stash;
+        SV *ssv;
+    CODE:
+        if (items == 1) {
+            stash = CopSTASH(PL_curcop);
+        } else {
+            SV* classname = ST(1);
+            STRLEN len;
+            char *ptr;
+
+            if (classname &&
+                ! SvGMAGICAL(classname) &&
+                ! SvAMAGIC(classname) &&
+                SvROK(classname))
+            {
+                Perl_croak(aTHX_ "Attempt to bless into a reference");
+            }
+            ptr = SvPV(classname, len);
+            if (ckWARN(WARN_MISC) && len == 0) {
+                Perl_warner(aTHX_ packWARN(WARN_MISC),
+                        "Explicit blessing to '' (assuming package main)");
+            }
+            stash = gv_stashpvn(ptr, len, TRUE);
+        }
+        SvREFCNT_inc_void(ref);
+        (void)sv_bless(ref, stash);
+        ST(0) = sv_2mortal(ref);
+        ssv = Perl_sharedsv_find(aTHX_ ref);
+        if (ssv) {
+            dTHXc;
+            ENTER_LOCK;
+            SHARED_CONTEXT;
+            {
+                SV* fake_stash = newSVpv(HvNAME_get(stash), 0);
+                (void)sv_bless(ssv, (HV*)fake_stash);
+            }
+            CALLER_CONTEXT;
+            LEAVE_LOCK;
+        }
+        /* XSRETURN(1); - implied */
+
+#endif /* USE_ITHREADS */
+
 BOOT:
 {
+#ifdef USE_ITHREADS
      Perl_sharedsv_init(aTHX);
+#endif /* USE_ITHREADS */
 }