Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 21267f6

Browse files
committedApr 23, 2024
bus: make AtomicDevice use a per-bus "busy" flag, not per-device.
Needed for soundness.
1 parent 15c265c commit 21267f6

File tree

1 file changed

+32
-16
lines changed

1 file changed

+32
-16
lines changed
 

‎embedded-hal-bus/src/spi/atomic.rs‎

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,28 @@ use embedded_hal::spi::{Error, ErrorKind, ErrorType, Operation, SpiBus, SpiDevic
66
use super::DeviceError;
77
use crate::spi::shared::transaction;
88

9+
/// Cell type used by [`AtomicDevice`].
10+
///
11+
/// To use [`AtomicDevice`], you must wrap the bus with this struct, and then
12+
/// construct multiple [`AtomicDevice`] instances with references to it.
13+
pub struct AtomicCell<BUS> {
14+
bus: UnsafeCell<BUS>,
15+
busy: portable_atomic::AtomicBool,
16+
}
17+
18+
unsafe impl<BUS: Send> Send for AtomicCell<BUS> {}
19+
unsafe impl<BUS: Send> Sync for AtomicCell<BUS> {}
20+
21+
impl<BUS> AtomicCell<BUS> {
22+
/// Create a new `AtomicCell`
23+
pub fn new(bus: BUS) -> Self {
24+
Self {
25+
bus: UnsafeCell::new(bus),
26+
busy: portable_atomic::AtomicBool::from(false),
27+
}
28+
}
29+
}
30+
931
/// `UnsafeCell`-based shared bus [`SpiDevice`] implementation.
1032
///
1133
/// This allows for sharing an [`SpiBus`], obtaining multiple [`SpiDevice`] instances,
@@ -19,10 +41,9 @@ use crate::spi::shared::transaction;
1941
/// rules, such as the RTIC framework.
2042
///
2143
pub struct AtomicDevice<'a, BUS, CS, D> {
22-
bus: &'a UnsafeCell<BUS>,
44+
bus: &'a AtomicCell<BUS>,
2345
cs: CS,
2446
delay: D,
25-
busy: portable_atomic::AtomicBool,
2647
}
2748

2849
#[derive(Debug, Copy, Clone)]
@@ -40,13 +61,8 @@ pub enum AtomicError<T: Error> {
4061
impl<'a, BUS, CS, D> AtomicDevice<'a, BUS, CS, D> {
4162
/// Create a new [`AtomicDevice`].
4263
#[inline]
43-
pub fn new(bus: &'a UnsafeCell<BUS>, cs: CS, delay: D) -> Self {
44-
Self {
45-
bus,
46-
cs,
47-
delay,
48-
busy: portable_atomic::AtomicBool::from(false),
49-
}
64+
pub fn new(bus: &'a AtomicCell<BUS>, cs: CS, delay: D) -> Self {
65+
Self { bus, cs, delay }
5066
}
5167
}
5268

@@ -72,18 +88,15 @@ where
7288
/// The returned device will panic if you try to execute a transaction
7389
/// that contains any operations of type [`Operation::DelayNs`].
7490
#[inline]
75-
pub fn new_no_delay(bus: &'a UnsafeCell<BUS>, cs: CS) -> Self {
91+
pub fn new_no_delay(bus: &'a AtomicCell<BUS>, cs: CS) -> Self {
7692
Self {
7793
bus,
7894
cs,
7995
delay: super::NoDelay,
80-
busy: portable_atomic::AtomicBool::from(false),
8196
}
8297
}
8398
}
8499

85-
unsafe impl<'a, BUS, CS, D> Send for AtomicDevice<'a, BUS, CS, D> {}
86-
87100
impl<T: Error> Error for AtomicError<T> {
88101
fn kind(&self) -> ErrorKind {
89102
match self {
@@ -109,7 +122,8 @@ where
109122
{
110123
#[inline]
111124
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
112-
self.busy
125+
self.bus
126+
.busy
113127
.compare_exchange(
114128
false,
115129
true,
@@ -118,11 +132,13 @@ where
118132
)
119133
.map_err(|_| AtomicError::Busy)?;
120134

121-
let bus = unsafe { &mut *self.bus.get() };
135+
let bus = unsafe { &mut *self.bus.bus.get() };
122136

123137
let result = transaction(operations, bus, &mut self.delay, &mut self.cs);
124138

125-
self.busy.store(false, core::sync::atomic::Ordering::SeqCst);
139+
self.bus
140+
.busy
141+
.store(false, core::sync::atomic::Ordering::SeqCst);
126142

127143
result.map_err(AtomicError::Other)
128144
}

0 commit comments

Comments
 (0)
Please sign in to comment.