summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2018-09-27 01:00:11 -0400
committerAndy Wingo <wingo@pobox.com>2019-05-23 15:52:32 +0200
commitf65ccc6afeda2d4e14878928123d8d3660712dca (patch)
treee3c8b251c21dd1dd9e93beaa49e7c1cf7f51c906
parent827e88b4b798b11013e8a9ef4e0f6ad111966321 (diff)
downloadguile-f65ccc6afeda2d4e14878928123d8d3660712dca.tar.gz
Fix 'atomic-box-compare-and-swap!'.
Fixes <https://bugs.gnu.org/32786>. 'scm_atomic_compare_and_swap_scm' is a thin wrapper around 'atomic_compare_exchange_weak' (where available), and therefore it may spuriously fail on some platforms, leaving the atomic object unchanged even when the observed value is equal to the expected value. Since 'scm_atomic_compare_and_swap_scm' returns both a boolean result and the observed value, the caller is able to detect spurious failures when using that API. 'atomic-box-compare-and-swap!' presents a simpler API, returning only the observed value. The documentation advises callers to assume that the exchange succeeded if the observed value is 'eq?' to the expected value. It's therefore not possible to report spurious failures with this API. 'atomic-box-compare-and-swap!' uses 'scm_atomic_compare_and_swap_scm', and prior to this commit would simply ignore the boolean result and return the observed value. In case of spurious failures, the caller would legitimately conclude that the exchange had succeeded. With this commit, 'atomic-box-compare-and-swap!' now retries in case of spurious failures. * libguile/atomic.c (scm_atomic_box_compare_and_swap_x): If 'scm_atomic_compare_and_swap_scm' returns false and the observed value is equal to 'expected', then try again. * libguile/intrinsics.c (atomic_compare_and_swap_scm): Ditto.
-rw-r--r--libguile/atomic.c19
-rw-r--r--libguile/intrinsics.c18
2 files changed, 30 insertions, 7 deletions
diff --git a/libguile/atomic.c b/libguile/atomic.c
index 604a21e5a..174d26b76 100644
--- a/libguile/atomic.c
+++ b/libguile/atomic.c
@@ -1,4 +1,4 @@
-/* Copyright 2016,2018
+/* Copyright 2016,2018-2019
Free Software Foundation, Inc.
This file is part of Guile.
@@ -102,10 +102,21 @@ SCM_DEFINE (scm_atomic_box_compare_and_swap_x,
"if the return value is @code{eq?} to @var{expected}.")
#define FUNC_NAME s_scm_atomic_box_compare_and_swap_x
{
+ SCM result = expected;
+
SCM_VALIDATE_ATOMIC_BOX (1, box);
- scm_atomic_compare_and_swap_scm (scm_atomic_box_loc (box),
- &expected, desired);
- return expected;
+ while (!scm_atomic_compare_and_swap_scm (scm_atomic_box_loc (box),
+ &result, desired)
+ && scm_is_eq (result, expected))
+ {
+ /* 'scm_atomic_compare_and_swap_scm' has spuriously failed,
+ i.e. it has returned 0 to indicate failure, although the
+ observed value is 'eq?' to EXPECTED. In this case, we *must*
+ try again, because the API of 'atomic-box-compare-and-swap!'
+ provides no way to indicate to the caller that the exchange
+ failed when the observed value is 'eq?' to EXPECTED. */
+ }
+ return result;
}
#undef FUNC_NAME
diff --git a/libguile/intrinsics.c b/libguile/intrinsics.c
index a619fda90..437441032 100644
--- a/libguile/intrinsics.c
+++ b/libguile/intrinsics.c
@@ -1,4 +1,4 @@
-/* Copyright 2018
+/* Copyright 2018-2019
Free Software Foundation, Inc.
This file is part of Guile.
@@ -459,8 +459,20 @@ atomic_swap_scm (SCM *loc, SCM val)
static SCM
atomic_compare_and_swap_scm (SCM *loc, SCM expected, SCM desired)
{
- scm_atomic_compare_and_swap_scm (loc, &expected, desired);
- return expected;
+ SCM result = expected;
+
+ while (!scm_atomic_compare_and_swap_scm (loc, &result, desired)
+ && scm_is_eq (result, expected))
+ {
+ /* 'scm_atomic_compare_and_swap_scm' has spuriously failed,
+ i.e. it has returned 0 to indicate failure, although the
+ observed value is 'eq?' to EXPECTED. In this case, we *must*
+ try again, because the API of 'atomic-box-compare-and-swap!'
+ provides no way to indicate to the caller that the exchange
+ failed when the observed value is 'eq?' to EXPECTED. */
+ }
+
+ return result;
}
void