This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #52000] add perldiag entries for the new warnings
[perl5.git] / dist / threads-shared / shared.xs
index e92d33d..d3e859d 100644 (file)
 #define UL_MAGIC_SIG 0x554C  /* UL = user lock */
 
 /*
- * The shared things need an intepreter to live in ...
+ * The shared things need an interpreter 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 */
@@ -304,6 +304,24 @@ MGVTBL sharedsv_userlock_vtbl = {
 #endif
 };
 
+
+/* Support for dual-valued variables */
+#ifdef SVf_IVisUV
+#  define DUALVAR_FLAGS(sv)                             \
+    ((SvPOK(sv))                                        \
+        ? ((SvNOK(sv) || SvNOKp(sv)) ? SVf_NOK          \
+        : ((SvIsUV(sv)) ? (SVf_IOK | SVf_IVisUV)        \
+        : ((SvIOK(sv) || SvIOKp(sv)) ? SVf_IOK : 0)))   \
+        : 0)
+#else
+#  define DUALVAR_FLAGS(sv)                             \
+    ((SvPOK(sv))                                        \
+        ? ((SvNOK(sv) || SvNOKp(sv)) ? SVf_NOK          \
+        : ((SvIOK(sv) || SvIOKp(sv)) ? SVf_IOK : 0))    \
+        : 0)
+#endif
+
+
 /*
  * Access to shared things is heavily based on MAGIC
  *      - in mg.h/mg.c/sv.c sense
@@ -326,11 +344,7 @@ extern MGVTBL sharedsv_elem_vtbl;      /* Elements of hashes and arrays have
 
 /* Get shared aggregate SV pointed to by threads::shared::tie magic object */
 
-STATIC SV *
-S_sharedsv_from_obj(pTHX_ SV *sv)
-{
-     return ((SvROK(sv)) ? INT2PTR(SV *, SvIV(SvRV(sv))) : NULL);
-}
+#define SHAREDSV_FROM_OBJ(sv) ((SvROK(sv)) ? INT2PTR(SV *, SvIV(SvRV(sv))) : NULL)
 
 
 /* Return the user_lock structure (if any) associated with a shared SV.
@@ -405,7 +419,7 @@ Perl_sharedsv_find(pTHX_ SV *sv)
     }
     /* 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 (SHAREDSV_FROM_OBJ(sv));
     }
     return (NULL);
 }
@@ -598,7 +612,7 @@ S_abs_2_rel_milli(double abs)
 bool
 Perl_sharedsv_cond_timedwait(perl_cond *cond, perl_mutex *mut, double abs)
 {
-#if defined(NETWARE) || defined(FAKE_THREADS) || defined(I_MACH_CTHREADS)
+#if defined(NETWARE) || defined(I_MACH_CTHREADS)
     Perl_croak_nocontext("cond_timedwait not supported on this platform");
 #else
 #  ifdef WIN32
@@ -657,18 +671,17 @@ Perl_sharedsv_cond_timedwait(perl_cond *cond, perl_mutex *mut, double abs)
     return (got_it);
 #    endif /* OS2 */
 #  endif /* WIN32 */
-#endif /* NETWARE || FAKE_THREADS || I_MACH_CTHREADS */
+#endif /* NETWARE || I_MACH_CTHREADS */
 }
 
 
-/* Given a shared RV, copy it's value to a private RV, also copying the
- * object status of the referent.
+/* Given a thingy referenced by 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);
+S_get_RV(pTHX_ SV *sv, SV *sobj) {
     SV *obj;
     if (! (SvROK(sv) &&
            ((obj = SvRV(sv))) &&
@@ -683,7 +696,7 @@ S_get_RV(pTHX_ SV *sv, SV *ssv) {
             sv_setsv_nomg(sv, &PL_sv_undef);
             SvROK_on(sv);
         }
-        obj = S_sharedsv_new_private(aTHX_ SvRV(ssv));
+        obj = S_sharedsv_new_private(aTHX_ sobj);
         SvRV_set(sv, obj);
     }
 
@@ -702,6 +715,16 @@ S_get_RV(pTHX_ SV *sv, SV *ssv) {
     }
 }
 
+/* Every caller of S_get_RV needs this incantation (which cannot go inside
+   S_get_RV itself, as we do not want recursion beyond one level): */
+#define get_RV(sv, sobj)                     \
+        S_get_RV(aTHX_ sv, sobj);             \
+        /* Look ahead for refs of refs */      \
+        if (SvROK(sobj)) {                      \
+            SvROK_on(SvRV(sv));                  \
+            S_get_RV(aTHX_ SvRV(sv), SvRV(sobj)); \
+        }
+
 
 /* ------------ PERL_MAGIC_shared_scalar(n) functions -------------- */
 
@@ -715,12 +738,7 @@ sharedsv_scalar_mg_get(pTHX_ SV *sv, MAGIC *mg)
 
     ENTER_LOCK;
     if (SvROK(ssv)) {
-        S_get_RV(aTHX_ sv, ssv);
-        /* Look ahead for refs of refs */
-        if (SvROK(SvRV(ssv))) {
-            SvROK_on(SvRV(sv));
-            S_get_RV(aTHX_ SvRV(sv), SvRV(ssv));
-        }
+        get_RV(sv, SvRV(ssv));
     } else {
         sv_setsv_nomg(sv, ssv);
     }
@@ -739,6 +757,11 @@ sharedsv_scalar_store(pTHX_ SV *sv, SV *ssv)
     bool allowed = TRUE;
 
     assert(PL_sharedsv_lock.owner == aTHX);
+    if (!PL_dirty && SvROK(ssv) && SvREFCNT(SvRV(ssv)) == 1) {
+        SV *sv = sv_newmortal();
+        sv_upgrade(sv, SVt_RV);
+        get_RV(sv, SvRV(ssv));
+    }
     if (SvROK(sv)) {
         SV *obj = SvRV(sv);
         SV *sobj = Perl_sharedsv_find(aTHX_ obj);
@@ -809,7 +832,15 @@ int
 sharedsv_scalar_mg_free(pTHX_ SV *sv, MAGIC *mg)
 {
     PERL_UNUSED_ARG(sv);
+    ENTER_LOCK;
+    if (!PL_dirty
+     && SvROK((SV *)mg->mg_ptr) && SvREFCNT(SvRV((SV *)mg->mg_ptr)) == 1) {
+        SV *sv = sv_newmortal();
+        sv_upgrade(sv, SVt_RV);
+        get_RV(sv, SvRV((SV *)mg->mg_ptr));
+    }
     S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
+    LEAVE_LOCK;
     return (0);
 }
 
@@ -868,7 +899,7 @@ int
 sharedsv_elem_mg_FETCH(pTHX_ SV *sv, MAGIC *mg)
 {
     dTHXc;
-    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    SV *saggregate = SHAREDSV_FROM_OBJ(mg->mg_obj);
     SV** svp = NULL;
 
     ENTER_LOCK;
@@ -898,12 +929,7 @@ sharedsv_elem_mg_FETCH(pTHX_ SV *sv, MAGIC *mg)
     if (svp) {
         /* Exists in the array */
         if (SvROK(*svp)) {
-            S_get_RV(aTHX_ sv, *svp);
-            /* Look ahead for refs of refs */
-            if (SvROK(SvRV(*svp))) {
-                SvROK_on(SvRV(sv));
-                S_get_RV(aTHX_ SvRV(sv), SvRV(*svp));
-            }
+            get_RV(sv, SvRV(*svp));
         } else {
             /* $ary->[elem] or $ary->{elem} is a scalar */
             Perl_sharedsv_associate(aTHX_ sv, *svp);
@@ -923,8 +949,10 @@ int
 sharedsv_elem_mg_STORE(pTHX_ SV *sv, MAGIC *mg)
 {
     dTHXc;
-    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    SV *saggregate = SHAREDSV_FROM_OBJ(mg->mg_obj);
     SV **svp;
+    U32 dualvar_flags = DUALVAR_FLAGS(sv);
+
     /* 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
@@ -953,6 +981,7 @@ sharedsv_elem_mg_STORE(pTHX_ SV *sv, MAGIC *mg)
     CALLER_CONTEXT;
     Perl_sharedsv_associate(aTHX_ sv, *svp);
     sharedsv_scalar_store(aTHX_ sv, *svp);
+    SvFLAGS(*svp) |= dualvar_flags;
     LEAVE_LOCK;
     return (0);
 }
@@ -964,7 +993,7 @@ sharedsv_elem_mg_DELETE(pTHX_ SV *sv, MAGIC *mg)
 {
     dTHXc;
     MAGIC *shmg;
-    SV *saggregate = S_sharedsv_from_obj(aTHX_ mg->mg_obj);
+    SV *saggregate = SHAREDSV_FROM_OBJ(mg->mg_obj);
 
     /* Object may not exist during global destruction */
     if (! saggregate) {
@@ -1005,7 +1034,7 @@ int
 sharedsv_elem_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
 {
     PERL_UNUSED_ARG(param);
-    SvREFCNT_inc_void(S_sharedsv_from_obj(aTHX_ mg->mg_obj));
+    SvREFCNT_inc_void(SHAREDSV_FROM_OBJ(mg->mg_obj));
     assert(mg->mg_flags & MGf_DUP);
     return (0);
 }
@@ -1039,7 +1068,7 @@ sharedsv_array_mg_FETCHSIZE(pTHX_ SV *sv, MAGIC *mg)
         val = av_len((AV*) ssv);
     } else {
         /* Not actually defined by tie API but ... */
-        val = HvKEYS((HV*) ssv);
+        val = HvUSEDKEYS((HV*) ssv);
     }
     SHARED_RELEASE;
     return (val);
@@ -1052,13 +1081,29 @@ sharedsv_array_mg_CLEAR(pTHX_ SV *sv, MAGIC *mg)
 {
     dTHXc;
     SV *ssv = (SV *) mg->mg_ptr;
+    const bool isav = SvTYPE(ssv) == SVt_PVAV;
     PERL_UNUSED_ARG(sv);
     SHARED_EDIT;
-    if (SvTYPE(ssv) == SVt_PVAV) {
-        av_clear((AV*) ssv);
-    } else {
-        hv_clear((HV*) ssv);
+    if (!PL_dirty) {
+            SV **svp = isav ? AvARRAY((AV *)ssv) : NULL;
+            I32 items = isav ? AvFILLp((AV *)ssv) + 1 : 0;
+            HE *iter;
+            if (!isav) hv_iterinit((HV *)ssv);
+            while (isav ? items-- : !!(iter = hv_iternext((HV *)ssv))) {
+                SV *sv = isav ? *svp++ : HeVAL(iter);
+                if (!sv) continue;
+                if ( (SvOBJECT(sv) || (SvROK(sv) && (sv = SvRV(sv))))
+                  && SvREFCNT(sv) == 1 ) {
+                    SV *tmp = Perl_sv_newmortal(caller_perl);
+                    PERL_SET_CONTEXT((aTHX = caller_perl));
+                    sv_upgrade(tmp, SVt_RV);
+                    get_RV(tmp, sv);
+                    PERL_SET_CONTEXT((aTHX = PL_sharedsv_space));
+                }
+            }
     }
+    if (isav) av_clear((AV*) ssv);
+    else      hv_clear((HV*) ssv);
     SHARED_RELEASE;
     return (0);
 }
@@ -1156,14 +1201,14 @@ Perl_sharedsv_locksv(pTHX_ SV *sv)
         sv = SvRV(sv);
     ssv = Perl_sharedsv_find(aTHX_ sv);
     if (!ssv)
-       croak("lock can only be used on shared values");
+        croak("lock can only be used on shared values");
     Perl_sharedsv_lock(aTHX_ ssv);
 }
 
 
 /* Can a shared object be destroyed?
  * True if not a shared,
- * or if detroying last proxy on a shared object
+ * or if destroying last proxy on a shared object
  */
 #ifdef PL_destroyhook
 bool
@@ -1178,7 +1223,7 @@ Perl_shared_object_destroy(pTHX_ SV *sv)
 }
 #endif
 
-/* veto signal despatch if we have the lock */
+/* veto signal dispatch if we have the lock */
 
 #ifdef PL_signalhook
 
@@ -1191,7 +1236,7 @@ S_shared_signal_hook(pTHX) {
     us = (PL_sharedsv_lock.owner == aTHX);
     MUTEX_UNLOCK(&PL_sharedsv_lock.mutex);
     if (us)
-       return; /* try again later */
+        return; /* try again later */
     prev_signal_hook(aTHX);
 }
 #endif
@@ -1215,8 +1260,8 @@ Perl_sharedsv_init(pTHX)
 #endif
 #ifdef PL_signalhook
     if (!prev_signal_hook) {
-       prev_signal_hook = PL_signalhook;
-       PL_signalhook = &S_shared_signal_hook;
+        prev_signal_hook = PL_signalhook;
+        PL_signalhook = &S_shared_signal_hook;
     }
 #endif
 }
@@ -1233,14 +1278,16 @@ void
 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 *sobj = SHAREDSV_FROM_OBJ(obj);
+        int ii;
+        for (ii = 1; ii < items; ii++) {
+            SV* tmp = newSVsv(ST(ii));
             SV *stmp;
+            U32 dualvar_flags = DUALVAR_FLAGS(tmp);
             ENTER_LOCK;
             stmp = S_sharedsv_new_shared(aTHX_ tmp);
             sharedsv_scalar_store(aTHX_ tmp, stmp);
+            SvFLAGS(stmp) |= dualvar_flags;
             SHARED_CONTEXT;
             av_push((AV*) sobj, stmp);
             SvREFCNT_inc_void(stmp);
@@ -1253,18 +1300,20 @@ void
 UNSHIFT(SV *obj, ...)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
-        int i;
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
+        int ii;
         ENTER_LOCK;
         SHARED_CONTEXT;
         av_unshift((AV*)sobj, items - 1);
         CALLER_CONTEXT;
-        for (i = 1; i < items; i++) {
-            SV *tmp = newSVsv(ST(i));
+        for (ii = 1; ii < items; ii++) {
+            SV *tmp = newSVsv(ST(ii));
+            U32 dualvar_flags = DUALVAR_FLAGS(tmp);
             SV *stmp = S_sharedsv_new_shared(aTHX_ tmp);
             sharedsv_scalar_store(aTHX_ tmp, stmp);
             SHARED_CONTEXT;
-            av_store((AV*) sobj, i - 1, stmp);
+            SvFLAGS(stmp) |= dualvar_flags;
+            av_store((AV*) sobj, ii - 1, stmp);
             SvREFCNT_inc_void(stmp);
             CALLER_CONTEXT;
             SvREFCNT_dec(tmp);
@@ -1276,7 +1325,7 @@ void
 POP(SV *obj)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         SV* ssv;
         ENTER_LOCK;
         SHARED_CONTEXT;
@@ -1293,7 +1342,7 @@ void
 SHIFT(SV *obj)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         SV* ssv;
         ENTER_LOCK;
         SHARED_CONTEXT;
@@ -1310,7 +1359,7 @@ void
 EXTEND(SV *obj, IV count)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         SHARED_EDIT;
         av_extend((AV*)sobj, count);
         SHARED_RELEASE;
@@ -1320,7 +1369,7 @@ void
 STORESIZE(SV *obj,IV count)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         SHARED_EDIT;
         av_fill((AV*) sobj, count);
         SHARED_RELEASE;
@@ -1330,7 +1379,7 @@ void
 EXISTS(SV *obj, SV *index)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         bool exists;
         if (SvTYPE(sobj) == SVt_PVAV) {
             SHARED_EDIT;
@@ -1355,7 +1404,7 @@ void
 FIRSTKEY(SV *obj)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         char* key = NULL;
         I32 len = 0;
         HE* entry;
@@ -1380,7 +1429,7 @@ void
 NEXTKEY(SV *obj, SV *oldkey)
     CODE:
         dTHXc;
-        SV *sobj = S_sharedsv_from_obj(aTHX_ obj);
+        SV *sobj = SHAREDSV_FROM_OBJ(obj);
         char* key = NULL;
         I32 len = 0;
         HE* entry;
@@ -1614,7 +1663,7 @@ cond_broadcast(SV *myref)
 
 
 void
-bless(SV* myref, ...);
+bless(SV* myref, ...)
     PROTOTYPE: $;$
     PREINIT:
         HV* stash;