From 5abb33765144c95bce0c297e8a8d343f194cf774 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 5 Nov 2018 00:29:16 +0100 Subject: [PATCH 1/3] concurrency: AtomicUsize doesn't need be in a static mut variable --- src/concurrency/concurrency.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/concurrency/concurrency.md b/src/concurrency/concurrency.md index a4d4671..a6f888a 100644 --- a/src/concurrency/concurrency.md +++ b/src/concurrency/concurrency.md @@ -161,9 +161,9 @@ increment operation. These atomic operations are safe even across multiple cores. ```rust -// New type for COUNTER -use core::sync::atomic; -static mut COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT; +use core::sync::atomic::{AtomicUsize, Ordering}; + +static COUNTER: AtomicUsize = AtomicUsize::new(0); #[entry] fn main() -> ! { @@ -174,7 +174,7 @@ fn main() -> ! { if state && !last_state { last_state = state; // Use `fetch_add` to atomically add 1 to COUNTER - unsafe { COUNTER.fetch_add(1, atomic::Ordering::Relaxed) }; + COUNTER.fetch_add(1, atomic::Ordering::Relaxed); } } } @@ -182,13 +182,14 @@ fn main() -> ! { #[interrupt] fn timer() { // Use `store` to write 0 directly to COUNTER - unsafe { COUNTER.store(0, atomic::Ordering::Relaxed) } + COUNTER.store(0, atomic::Ordering::Relaxed) } ``` -We still require `unsafe` blocks since `COUNTER` is a `static mut`, but we no -longer have the overhead of disabling all interrupts. When possible, this is a -better solution — but it may not be supported on your platform. +This time `COUNTER` is a safe `static` variable. Thanks to the `AtomicUsize` +type `COUNTER` can be safely modified from both the interrupt handler and the +main thread without disabling interrupts. When possible, this is a better +solution — but it may not be supported on your platform. A note on [`Ordering`]: this affects how the compiler and hardware may reorder instructions, and also has consequences on cache visibility. For simple atomic From 691206d7633e1e5d43546bf6316ab5f8ee90e3ac Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 5 Nov 2018 00:50:19 +0100 Subject: [PATCH 2/3] Relaxed is OK if the target is a single-core device for a multi-core device AcqRel ordering for the fetch-add operation and Release ordering for the store operation would have been required for correctness --- src/concurrency/concurrency.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/concurrency/concurrency.md b/src/concurrency/concurrency.md index a6f888a..d4fb352 100644 --- a/src/concurrency/concurrency.md +++ b/src/concurrency/concurrency.md @@ -192,13 +192,12 @@ main thread without disabling interrupts. When possible, this is a better solution — but it may not be supported on your platform. A note on [`Ordering`]: this affects how the compiler and hardware may reorder -instructions, and also has consequences on cache visibility. For simple atomic -operations like incrementing a counter, where we are not synchronising any -other tasks on the counter, `Relaxed` is sufficient, and will have the best -performance on typical embedded platforms. Stricter ordering will cause the -compiler to emit memory barriers around the atomic operations; depending on -what you're using atomics for you may or may not need this! The precise -details of the atomic model are complicated and best described elsewhere. +instructions, and also has consequences on cache visibility. Assuming that the +target is a single core platform `Relaxed` is sufficient and the most efficient +choice in this particular case. Stricter ordering will cause the compiler to +emit memory barriers around the atomic operations; depending on what you're +using atomics for you may or may not need this! The precise details of the +atomic model are complicated and best described elsewhere. For more details on atomics and ordering, see the [nomicon]. From e8e8862dec07128907ba84e225bfbfae8d63f623 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 5 Nov 2018 01:41:06 +0100 Subject: [PATCH 3/3] fix paths --- src/concurrency/concurrency.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concurrency/concurrency.md b/src/concurrency/concurrency.md index d4fb352..45b28ff 100644 --- a/src/concurrency/concurrency.md +++ b/src/concurrency/concurrency.md @@ -174,7 +174,7 @@ fn main() -> ! { if state && !last_state { last_state = state; // Use `fetch_add` to atomically add 1 to COUNTER - COUNTER.fetch_add(1, atomic::Ordering::Relaxed); + COUNTER.fetch_add(1, Ordering::Relaxed); } } } @@ -182,7 +182,7 @@ fn main() -> ! { #[interrupt] fn timer() { // Use `store` to write 0 directly to COUNTER - COUNTER.store(0, atomic::Ordering::Relaxed) + COUNTER.store(0, Ordering::Relaxed) } ```