From b54ae5c4ace9b94442bbb46858449069f566d269 Mon Sep 17 00:00:00 2001 From: Samy Al Bahra Date: Tue, 18 Dec 2012 21:34:48 -0500 Subject: [PATCH] ck_ring: Add a work-around for compiler bug(s) in ck_ring_dequeue_spmc. Both LLVM-backed compilers and GCC incorrectly treat a barrier-sandwiched load as a loop invariant in dequeue_spmc. Forcing volatile atomic load semantics generates the right thing. Thanks to Devon O'Dell and Abel Mathew for help in catching this issue. --- include/ck_ring.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/ck_ring.h b/include/ck_ring.h index cab155f..ac37a66 100644 --- a/include/ck_ring.h +++ b/include/ck_ring.h @@ -317,7 +317,15 @@ ck_ring_dequeue_spmc(struct ck_ring *ring, void *data) return false; ck_pr_fence_load(); - r = ring->ring[consumer & ring->mask]; + + /* + * Both LLVM and GCC have generated code which completely + * ignores the semantics of the r load, despite it being + * sandwiched between compiler barriers. We use an atomic + * volatile load to force volatile semantics while allowing + * for r itself to remain aliased across the loop. + */ + r = ck_pr_load_ptr(&ring->ring[consumer & ring->mask]); /* Serialize load with respect to head update. */ ck_pr_fence_memory(); @@ -326,6 +334,10 @@ ck_ring_dequeue_spmc(struct ck_ring *ring, void *data) consumer + 1, &consumer) == false); + /* + * Force spillage while avoiding aliasing issues that aren't + * a problem on POSIX. + */ ck_pr_store_ptr(data, r); return true; }