kmc-solid: Synchronize the first update of ThreadInner::lifecycle with the second one on detach

The first update (swap RMW operation) must happen-before the second
update so that the latter can release `ThreadInner` safely.
This commit is contained in:
Tomoaki Kawada
2022-12-01 16:41:16 +09:00
parent ae7633f434
commit 304c6dcaed
+8 -8
View File
@@ -119,7 +119,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let old_lifecycle = inner
.lifecycle
.swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
.swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::AcqRel);
match old_lifecycle {
LIFECYCLE_DETACHED => {
@@ -129,9 +129,9 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
// In this case, `*p_inner`'s ownership has been moved to
// us, and we are responsible for dropping it. The acquire
// ordering is not necessary because the parent thread made
// no memory access needing synchronization since the call
// to `acre_tsk`.
// ordering ensures that the swap operation that wrote
// `LIFECYCLE_DETACHED` happens-before `Box::from_raw(
// p_inner)`.
// Safety: See above.
let _ = unsafe { Box::from_raw(p_inner) };
@@ -267,15 +267,15 @@ fn drop(&mut self) {
let inner = unsafe { self.p_inner.as_ref() };
// Detach the thread.
match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::AcqRel) {
LIFECYCLE_INIT => {
// [INIT → DETACHED]
// When the time comes, the child will figure out that no
// one will ever join it.
// The ownership of `*p_inner` is moved to the child thread.
// However, the release ordering is not necessary because we
// made no memory access needing synchronization since the call
// to `acre_tsk`.
// The release ordering ensures that the above swap operation on
// `lifecycle` happens-before the child thread's
// `Box::from_raw(p_inner)`.
}
LIFECYCLE_FINISHED => {
// [FINISHED → JOINED]