diff options
-rw-r--r-- | bootstraptest/test_ractor.rb | 11 | ||||
-rw-r--r-- | common.mk | 2 | ||||
-rw-r--r-- | missing/dtoa.c | 108 | ||||
-rw-r--r-- | util.c | 1 | ||||
-rw-r--r-- | version.h | 2 |
5 files changed, 95 insertions, 29 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 878b846487..fd698fa4d7 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -176,6 +176,17 @@ assert_equal '[[:e1, 1], [:e2, 2]]', %q{ a # } +# dtoa race condition +assert_equal '[:ok, :ok, :ok]', %q{ + n = 3 + n.times.map{ + Ractor.new{ + 10_000.times{ rand.to_s } + :ok + } + }.map(&:take) +} + ### ### # Ractor still has several memory corruption so skip huge number of tests @@ -14800,6 +14800,7 @@ util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h 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 @@ -14955,6 +14956,7 @@ util.$(OBJEXT): {$(VPATH)}internal/variable.h 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 cbee13ee81..a940eabd91 100644 --- a/missing/dtoa.c +++ b/missing/dtoa.c @@ -183,12 +183,16 @@ #undef Long #undef ULong -#if SIZEOF_INT == 4 +#include <limits.h> + +#if (INT_MAX >> 30) && !(INT_MAX >> 31) #define Long int #define ULong unsigned int -#elif SIZEOF_LONG == 4 +#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31) #define Long long int #define ULong unsigned long int +#else +#error No 32bit integer #endif #if HAVE_LONG_LONG @@ -202,6 +206,11 @@ #define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);} #endif +#ifndef ISDIGIT +#include <ctype.h> +#define ISDIGIT(c) isdigit(c) +#endif +#include <errno.h> #include <stdlib.h> #include <string.h> @@ -219,6 +228,9 @@ extern void FREE(void*); #else #define FREE xfree #endif +#ifndef NO_SANITIZE +#define NO_SANITIZE(x, y) y +#endif #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM @@ -280,7 +292,7 @@ extern "C" { #endif #ifndef hexdigit -static const char hexdigits[] = "0123456789abcdef0123456789ABCDEF"; +static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; #endif #if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 @@ -489,6 +501,19 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #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 { @@ -501,6 +526,8 @@ typedef struct Bigint Bigint; static Bigint *freelist[Kmax+1]; +#define BLOCKING_BIGINT ((Bigint *)(-1)) + static Bigint * Balloc(int k) { @@ -510,22 +537,41 @@ Balloc(int k) 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, BLOCKING_BIGINT); + if (LIKELY(rv != BLOCKING_BIGINT && rvn == rv)) { + rvn = ATOMIC_PTR_CAS(freelist[k], BLOCKING_BIGINT, rv->next); + assert(rvn == BLOCKING_BIGINT); + 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; @@ -539,14 +585,19 @@ Balloc(int k) 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 { + do { + vn = ATOMIC_PTR_CAS(freelist[v->k], 0, 0); + } while (UNLIKELY(vn == BLOCKING_BIGINT)); + v->next = vn; + } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn)); FREE_DTOA_LOCK(0); } } @@ -829,8 +880,9 @@ static Bigint * pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; + Bigint *p5tmp; int i; - static int p05[3] = { 5, 25, 125 }; + static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3) != 0) b = multadd(b, p05[i-1], 0); @@ -839,17 +891,17 @@ pow5mult(Bigint *b, int k) 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) { @@ -860,17 +912,17 @@ pow5mult(Bigint *b, int k) 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; } @@ -2520,10 +2572,10 @@ static char *dtoa_result; static char * rv_alloc(int i) { - return dtoa_result = xmalloc(i); + return dtoa_result = MALLOC(i); } #else -#define rv_alloc(i) xmalloc(i) +#define rv_alloc(i) MALLOC(i) #endif static char * @@ -2550,7 +2602,7 @@ nrv_alloc(const char *s, char **rve, size_t n) static void freedtoa(char *s) { - xfree(s); + FREE(s); } #endif @@ -29,6 +29,7 @@ #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 @@ -12,7 +12,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 53 +#define RUBY_PATCHLEVEL 54 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 3 |