Add Send/Sync bounds to PeripheralState

This commit is contained in:
Liam Murphy 2021-07-24 12:53:57 +10:00
parent ff9ff5e43a
commit 1b7ad7080e
6 changed files with 44 additions and 24 deletions

View file

@ -5,18 +5,26 @@ use core::ptr;
use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::interrupt::{Interrupt, InterruptExt};
/// A version of `PeripheralState` without the `'static` bound,
/// for cases where the compiler can't statically make sure
/// that `on_interrupt` doesn't reference anything which might be invalidated.
///
/// # Safety /// # Safety
/// When types implementing this trait are used with `PeripheralMutex`, /// When types implementing this trait are used with `PeripheralMutex`,
/// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `PeripheralMutex`. /// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `PeripheralMutex`.
pub unsafe trait PeripheralStateUnchecked { pub unsafe trait PeripheralStateUnchecked: Send {
type Interrupt: Interrupt; type Interrupt: Interrupt;
fn on_interrupt(&mut self); fn on_interrupt(&mut self);
} }
// `PeripheralMutex` is safe because `Pin` guarantees that the memory it references will not be invalidated or reused /// A type which can be used as state with `PeripheralMutex`.
// without calling `Drop`. However, it provides no guarantees about references contained within the state still being valid, ///
// so this `'static` bound is necessary. /// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
pub trait PeripheralState: 'static { /// and `&mut T` is `Send` where `T: Send`.
///
/// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated,
/// it doesn't guarantee that the lifetime will last.
pub trait PeripheralState: Send + 'static {
type Interrupt: Interrupt; type Interrupt: Interrupt;
fn on_interrupt(&mut self); fn on_interrupt(&mut self);
} }

View file

@ -4,18 +4,25 @@ use core::ptr;
use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::interrupt::{Interrupt, InterruptExt};
/// A version of `PeripheralState` without the `'static` bound,
/// for cases where the compiler can't statically make sure
/// that `on_interrupt` doesn't reference anything which might be invalidated.
///
/// # Safety /// # Safety
/// When types implementing this trait are used with `Peripheral`, /// When types implementing this trait are used with `Peripheral`,
/// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `Peripheral`. /// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `Peripheral`.
pub unsafe trait PeripheralStateUnchecked { pub unsafe trait PeripheralStateUnchecked: Sync {
type Interrupt: Interrupt; type Interrupt: Interrupt;
fn on_interrupt(&self); fn on_interrupt(&self);
} }
// `Peripheral` is safe because `Pin` guarantees that the memory it references will not be invalidated or reused /// A type which can be used as state with `Peripheral`.
// without calling `Drop`. However, it provides no guarantees about references contained within the state still being valid, ///
// so this `'static` bound is necessary. /// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt.
pub trait PeripheralState: 'static { ///
/// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated,
/// it doesn't guarantee that the lifetime will last.
pub trait PeripheralState: Sync + 'static {
type Interrupt: Interrupt; type Interrupt: Interrupt;
fn on_interrupt(&self); fn on_interrupt(&self);
} }

View file

@ -14,7 +14,7 @@ use embassy::interrupt::Interrupt;
use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; use usb_serial::{ReadInterface, UsbSerial, WriteInterface};
/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. /// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction.
pub unsafe trait USBInterrupt: Interrupt {} pub unsafe trait USBInterrupt: Interrupt + Send {}
pub(crate) struct State<'bus, B, T, I> pub(crate) struct State<'bus, B, T, I>
where where
@ -140,7 +140,7 @@ where
} }
} }
pub trait ClassSet<B: UsbBus> { pub trait ClassSet<B: UsbBus>: Send {
fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool; fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool;
} }
@ -176,8 +176,8 @@ pub struct Index1;
impl<B, C1> ClassSet<B> for ClassSet1<B, C1> impl<B, C1> ClassSet<B> for ClassSet1<B, C1>
where where
B: UsbBus, B: UsbBus + Send,
C1: UsbClass<B>, C1: UsbClass<B> + Send,
{ {
fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
device.poll(&mut [&mut self.class]) device.poll(&mut [&mut self.class])
@ -186,9 +186,9 @@ where
impl<B, C1, C2> ClassSet<B> for ClassSet2<B, C1, C2> impl<B, C1, C2> ClassSet<B> for ClassSet2<B, C1, C2>
where where
B: UsbBus, B: UsbBus + Send,
C1: UsbClass<B>, C1: UsbClass<B> + Send,
C2: UsbClass<B>, C2: UsbClass<B> + Send,
{ {
fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
device.poll(&mut [&mut self.class1, &mut self.class2]) device.poll(&mut [&mut self.class1, &mut self.class2])
@ -197,8 +197,8 @@ where
impl<B, C1> IntoClassSet<B, ClassSet1<B, C1>> for C1 impl<B, C1> IntoClassSet<B, ClassSet1<B, C1>> for C1
where where
B: UsbBus, B: UsbBus + Send,
C1: UsbClass<B>, C1: UsbClass<B> + Send,
{ {
fn into_class_set(self) -> ClassSet1<B, C1> { fn into_class_set(self) -> ClassSet1<B, C1> {
ClassSet1 { ClassSet1 {
@ -210,9 +210,9 @@ where
impl<B, C1, C2> IntoClassSet<B, ClassSet2<B, C1, C2>> for (C1, C2) impl<B, C1, C2> IntoClassSet<B, ClassSet2<B, C1, C2>> for (C1, C2)
where where
B: UsbBus, B: UsbBus + Send,
C1: UsbClass<B>, C1: UsbClass<B> + Send,
C2: UsbClass<B>, C2: UsbClass<B> + Send,
{ {
fn into_class_set(self) -> ClassSet2<B, C1, C2> { fn into_class_set(self) -> ClassSet2<B, C1, C2> {
ClassSet2 { ClassSet2 {

View file

@ -29,7 +29,7 @@ pub(crate) mod sealed {
pub trait ExtendedInstance {} pub trait ExtendedInstance {}
} }
pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send {
type Interrupt: Interrupt; type Interrupt: Interrupt;
} }
pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {}

View file

@ -461,7 +461,7 @@ pub(crate) mod sealed {
} }
} }
pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send {
type Interrupt: Interrupt; type Interrupt: Interrupt;
} }

View file

@ -48,6 +48,11 @@ impl WakerRegistration {
} }
} }
// SAFETY: `WakerRegistration` effectively contains an `Option<Waker>`,
// which is `Send` and `Sync`.
unsafe impl Send for WakerRegistration {}
unsafe impl Sync for WakerRegistration {}
pub struct AtomicWaker { pub struct AtomicWaker {
waker: AtomicPtr<TaskHeader>, waker: AtomicPtr<TaskHeader>,
} }