зеркало из https://github.com/github/ruby.git
Fixed race in dtoa [Bug #17612]
Fixed the race condition when replacing `freelist` entry with its chained next element. At acquiring an entry, hold the entry once with the special value, then release by replacing it with the next element again after acquired. If another thread is holding the same entry at that time, spinning until the entry gets released. Co-Authored-By: Koichi Sasada <ko1@atdot.net>
This commit is contained in:
Родитель
ad2c7f8a1e
Коммит
3acc81d9e4
|
@ -158,6 +158,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
|
||||
|
|
|
@ -526,6 +526,8 @@ typedef struct Bigint Bigint;
|
|||
|
||||
static Bigint *freelist[Kmax+1];
|
||||
|
||||
#define BLOCKING_BIGINT ((Bigint *)(-1))
|
||||
|
||||
static Bigint *
|
||||
Balloc(int k)
|
||||
{
|
||||
|
@ -541,8 +543,10 @@ Balloc(int k)
|
|||
rv = freelist[k];
|
||||
while (rv) {
|
||||
Bigint *rvn = rv;
|
||||
rv = ATOMIC_PTR_CAS(freelist[k], rv, rv->next);
|
||||
if (LIKELY(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;
|
||||
}
|
||||
|
@ -589,7 +593,10 @@ Bfree(Bigint *v)
|
|||
}
|
||||
ACQUIRE_DTOA_LOCK(0);
|
||||
do {
|
||||
vn = v->next = freelist[v->k];
|
||||
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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче