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.
ck_pring 0.2.13
Samy Al Bahra 12 years ago
parent 0631e396e0
commit b54ae5c4ac

@ -317,7 +317,15 @@ ck_ring_dequeue_spmc(struct ck_ring *ring, void *data)
return false; return false;
ck_pr_fence_load(); 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. */ /* Serialize load with respect to head update. */
ck_pr_fence_memory(); ck_pr_fence_memory();
@ -326,6 +334,10 @@ ck_ring_dequeue_spmc(struct ck_ring *ring, void *data)
consumer + 1, consumer + 1,
&consumer) == false); &consumer) == false);
/*
* Force spillage while avoiding aliasing issues that aren't
* a problem on POSIX.
*/
ck_pr_store_ptr(data, r); ck_pr_store_ptr(data, r);
return true; return true;
} }

Loading…
Cancel
Save