>From 99b7e15342fda1591838efc068d2624457afd5b0 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa <akiyks@xxxxxxxxx> Date: Mon, 19 Nov 2018 23:02:09 +0900 Subject: [PATCH 2/3] locking: Get rid of ACCESS_ONCE() Also add READ_ONCE() and WRITE_ONCE() to racy accesses in xchglock.c. Signed-off-by: Akira Yokosawa <akiyks@xxxxxxxxx> --- CodeSamples/locking/xchglock.c | 10 +++++----- locking/locking.tex | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CodeSamples/locking/xchglock.c b/CodeSamples/locking/xchglock.c index 5877920..a5e3403 100644 --- a/CodeSamples/locking/xchglock.c +++ b/CodeSamples/locking/xchglock.c @@ -28,7 +28,7 @@ typedef int xchglock_t; //\lnlbl{typedef} void xchg_lock(xchglock_t *xp) //\lnlbl{lock:b} { while (xchg(xp, 1) == 1) { //\lnlbl{lock:atmxchg} - while (*xp == 1) //\lnlbl{lock:inner:b} + while (READ_ONCE(*xp) == 1) //\lnlbl{lock:inner:b} continue; //\lnlbl{lock:inner:e} } } //\lnlbl{lock:e} @@ -59,9 +59,9 @@ void *test_xchg_lock(void *arg) run_on(me); atomic_inc(&nthreadsrunning); - while (ACCESS_ONCE(goflag) == GOFLAG_INIT) + while (READ_ONCE(goflag) == GOFLAG_INIT) poll(NULL, 0, 1); - while (ACCESS_ONCE(goflag) == GOFLAG_RUN) { + while (READ_ONCE(goflag) == GOFLAG_RUN) { xchg_lock(&testlock); if (owner != -1) lockerr++; @@ -86,11 +86,11 @@ int main(int argc, char *argv[]) smp_mb(); while (atomic_read(&nthreadsrunning) < nthreads) poll(NULL, 0, 1); - goflag = GOFLAG_RUN; + WRITE_ONCE(goflag, GOFLAG_RUN); smp_mb(); poll(NULL, 0, 10000); smp_mb(); - goflag = GOFLAG_STOP; + WRITE_ONCE(goflag, GOFLAG_STOP); smp_mb(); wait_all_threads(); printf("lockacqs = %lu, lockerr = %lu\n", lockacqs, lockerr); diff --git a/locking/locking.tex b/locking/locking.tex index 92ed2f2..874fb3b 100644 --- a/locking/locking.tex +++ b/locking/locking.tex @@ -1463,7 +1463,7 @@ void force_quiescent_state(struct rcu_node *rnp_leaf) struct rcu_node *rnp_old = NULL; for (; rnp != NULL; rnp = rnp->parent) { \lnlbl[loop:b] - ret = (ACCESS_ONCE(gp_flags)) || \lnlbl[flag_set] + ret = (READ_ONCE(gp_flags)) || \lnlbl[flag_set] !raw_spin_trylock(&rnp->fqslock);\lnlbl[trylock] if (rnp_old != NULL) \lnlbl[non_NULL] raw_spin_unlock(&rnp_old->fqslock);\lnlbl[rel1] @@ -1471,11 +1471,11 @@ void force_quiescent_state(struct rcu_node *rnp_leaf) return; \lnlbl[return] rnp_old = rnp; \lnlbl[save] } \lnlbl[loop:e] - if (!ACCESS_ONCE(gp_flags)) { \lnlbl[flag_not_set] - ACCESS_ONCE(gp_flags) = 1; \lnlbl[set_flag] + if (!READ_ONCE(gp_flags)) { \lnlbl[flag_not_set] + WRITE_ONCE(gp_flags, 1); \lnlbl[set_flag] do_force_quiescent_state(); \lnlbl[invoke] schedule_timeout_interruptible(HZ / 10);\lnlbl[wait] - ACCESS_ONCE(gp_flags) = 0; \lnlbl[clr_flag] + WRITE_ONCE(gp_flags, 0); \lnlbl[clr_flag] } raw_spin_unlock(&rnp_old->fqslock); \lnlbl[rel2] } @@ -1649,7 +1649,7 @@ the lock, thus marking it as having been released. \QuickQuizAnswer{ This can be a legitimate implementation, but only if this store is preceded by a memory barrier and makes use - of \co{ACCESS_ONCE()}. + of \co{WRITE_ONCE()}. The memory barrier is not required when the \co{xchg()} operation is used because this operation implies a full memory barrier due to the fact that it returns -- 2.7.4