[前][次][番号順一覧][スレッド一覧]

ruby-changes:64817

From: Nobuyoshi <ko1@a...>
Date: Sun, 10 Jan 2021 20:00:11 +0900 (JST)
Subject: [ruby-changes:64817] 2adbf01ae1 (master): dtoa.c: make thread-safe by using atomic CAS

https://git.ruby-lang.org/ruby.git/commit/?id=2adbf01ae1

From 2adbf01ae14c0a4cf190b7c969b91726966a0e0f Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Sun, 10 Jan 2021 17:36:18 +0900
Subject: dtoa.c: make thread-safe by using atomic CAS


diff --git a/common.mk b/common.mk
index b89605e..f7c45b9 100644
--- a/common.mk
+++ b/common.mk
@@ -14808,6 +14808,7 @@ util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h https://github.com/ruby/ruby/blob/trunk/common.mk#L14808
 util.$(OBJEXT): $(top_srcdir)/internal/util.h
 util.$(OBJEXT): $(top_srcdir)/internal/warnings.h
 util.$(OBJEXT): {$(VPATH)}assert.h
+util.$(OBJEXT): {$(VPATH)}atomic.h
 util.$(OBJEXT): {$(VPATH)}backward/2/assume.h
 util.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
 util.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -14963,6 +14964,7 @@ util.$(OBJEXT): {$(VPATH)}internal/variable.h https://github.com/ruby/ruby/blob/trunk/common.mk#L14964
 util.$(OBJEXT): {$(VPATH)}internal/warning_push.h
 util.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
 util.$(OBJEXT): {$(VPATH)}missing.h
+util.$(OBJEXT): {$(VPATH)}ruby_atomic.h
 util.$(OBJEXT): {$(VPATH)}st.h
 util.$(OBJEXT): {$(VPATH)}subst.h
 util.$(OBJEXT): {$(VPATH)}util.c
diff --git a/missing/dtoa.c b/missing/dtoa.c
index 6c0d2b8..41b0a22 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -501,6 +501,19 @@ extern double rnd_prod(double, double), rnd_quot(double, double); https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L501
 #define FREE_DTOA_LOCK(n)	/*unused right now*/
 #endif
 
+#ifndef ATOMIC_PTR_CAS
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old))
+#endif
+#ifndef LIKELY
+#define LIKELY(x) (x)
+#endif
+#ifndef UNLIKELY
+#define UNLIKELY(x) (x)
+#endif
+#ifndef ASSUME
+#define ASSUME(x) (void)(x)
+#endif
+
 #define Kmax 15
 
 struct Bigint {
@@ -522,22 +535,39 @@ Balloc(int k) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L535
     size_t len;
 #endif
 
+    rv = 0;
     ACQUIRE_DTOA_LOCK(0);
-    if (k <= Kmax && (rv = freelist[k]) != 0) {
-        freelist[k] = rv->next;
+    if (k <= Kmax) {
+        rv = freelist[k];
+        while (rv) {
+            Bigint *rvn = rv;
+            rv = ATOMIC_PTR_CAS(freelist[k], rv, rv->next);
+            if (LIKELY(rvn == rv)) {
+                ASSUME(rv);
+                break;
+            }
+        }
     }
-    else {
+    if (!rv) {
         x = 1 << k;
 #ifdef Omit_Private_Memory
         rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
 #else
         len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
                 /sizeof(double);
-        if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
-            rv = (Bigint*)pmem_next;
-            pmem_next += len;
+        if (k <= Kmax) {
+            double *pnext = pmem_next;
+            while (pnext - private_mem + len <= PRIVATE_mem) {
+                double *p = pnext;
+                pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len);
+                if (LIKELY(p == pnext)) {
+                    rv = (Bigint*)pnext;
+                    ASSUME(rv);
+                    break;
+                }
+            }
         }
-        else
+        if (!rv)
             rv = (Bigint*)MALLOC(len*sizeof(double));
 #endif
         rv->k = k;
@@ -551,14 +581,16 @@ Balloc(int k) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L581
 static void
 Bfree(Bigint *v)
 {
+    Bigint *vn;
     if (v) {
         if (v->k > Kmax) {
             FREE(v);
             return;
         }
         ACQUIRE_DTOA_LOCK(0);
-        v->next = freelist[v->k];
-        freelist[v->k] = v;
+        do {
+            vn = v->next = freelist[v->k];
+        } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn));
         FREE_DTOA_LOCK(0);
     }
 }
@@ -841,6 +873,7 @@ static Bigint * https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L873
 pow5mult(Bigint *b, int k)
 {
     Bigint *b1, *p5, *p51;
+    Bigint *p5tmp;
     int i;
     static const int p05[3] = { 5, 25, 125 };
 
@@ -851,17 +884,17 @@ pow5mult(Bigint *b, int k) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L884
         return b;
     if (!(p5 = p5s)) {
         /* first time */
-#ifdef MULTIPLE_THREADS
         ACQUIRE_DTOA_LOCK(1);
         if (!(p5 = p5s)) {
-            p5 = p5s = i2b(625);
+            p5 = i2b(625);
             p5->next = 0;
+            p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5);
+            if (UNLIKELY(p5tmp)) {
+                Bfree(p5);
+                p5 = p5tmp;
+            }
         }
         FREE_DTOA_LOCK(1);
-#else
-        p5 = p5s = i2b(625);
-        p5->next = 0;
-#endif
     }
     for (;;) {
         if (k & 1) {
@@ -872,17 +905,17 @@ pow5mult(Bigint *b, int k) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L905
         if (!(k >>= 1))
             break;
         if (!(p51 = p5->next)) {
-#ifdef MULTIPLE_THREADS
             ACQUIRE_DTOA_LOCK(1);
             if (!(p51 = p5->next)) {
-                p51 = p5->next = mult(p5,p5);
+                p51 = mult(p5,p5);
                 p51->next = 0;
+                p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51);
+                if (UNLIKELY(p5tmp)) {
+                    Bfree(p51);
+                    p51 = p5tmp;
+                }
             }
             FREE_DTOA_LOCK(1);
-#else
-            p51 = p5->next = mult(p5,p5);
-            p51->next = 0;
-#endif
         }
         p5 = p51;
     }
diff --git a/util.c b/util.c
index 6db8ddb..8ec0cd6 100644
--- a/util.c
+++ b/util.c
@@ -29,6 +29,7 @@ https://github.com/ruby/ruby/blob/trunk/util.c#L29
 #include "internal/sanitizers.h"
 #include "internal/util.h"
 #include "ruby/util.h"
+#include "ruby_atomic.h"
 
 const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF";
 #define hexdigit ruby_hexdigits
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]