summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_ractor.rb11
-rw-r--r--common.mk2
-rw-r--r--missing/dtoa.c108
-rw-r--r--util.c1
-rw-r--r--version.h2
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
diff --git a/common.mk b/common.mk
index 763305082d..594c165ffd 100644
--- a/common.mk
+++ b/common.mk
@@ -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
diff --git a/util.c b/util.c
index 6db8ddbfbe..8ec0cd60e5 100644
--- a/util.c
+++ b/util.c
@@ -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
diff --git a/version.h b/version.h
index 17c6406292..1ca6c45f81 100644
--- a/version.h
+++ b/version.h
@@ -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