-
Notifications
You must be signed in to change notification settings - Fork 214
Description
I will use the code from the LL-SC implementation, but the same applies to the CAS one.
heapless/src/pool/treiber/llsc.rs
Lines 84 to 116 in fb62d12
pub fn try_pop<N>(stack: &Stack<N>) -> Option<NonNullPtr<N>> | |
where | |
N: Node, | |
{ | |
unsafe { | |
let top_addr = ptr::addr_of!(stack.top) as *mut usize; | |
loop { | |
let top = arch::load_link(top_addr); | |
if let Some(top) = NonNull::new(top as *mut N) { | |
let next = &top.as_ref().next(); | |
if arch::store_conditional( | |
next.inner | |
.get() | |
.read() | |
.map(|non_null| non_null.as_ptr() as usize) | |
.unwrap_or_default(), | |
top_addr, | |
) | |
.is_ok() | |
{ | |
break Some(NonNullPtr { inner: top }); | |
} | |
} else { | |
arch::clear_load_link(); | |
break None; | |
} | |
} | |
} | |
} |
Between the head load in line 89 and the read to get the next pointer in line 95, another thread could have started and successfully finished a try_pop
. Back to the first thread, now the top
points to an in-use node that can be written to, since the storage for the next pointer and the data are the same (i.e. it's an union) we now get a data race.
I will try to trigger it with loom and miri and then try to come up with a fix. The simplest solution seems to replace the UnionNode
with StructNode
. However, I hope I can find a solution that doesn't incur in more memory usage, specially since I was the one that came up with the union suggestion years ago...