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};
/// 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
/// 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`.
pub unsafe trait PeripheralStateUnchecked {
pub unsafe trait PeripheralStateUnchecked: Send {
type Interrupt: Interrupt;
fn on_interrupt(&mut self);
}
// `PeripheralMutex` is safe because `Pin` guarantees that the memory it references will not be invalidated or reused
// without calling `Drop`. However, it provides no guarantees about references contained within the state still being valid,
// so this `'static` bound is necessary.
pub trait PeripheralState: 'static {
/// A type which can be used as state with `PeripheralMutex`.
///
/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
/// 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;
fn on_interrupt(&mut self);
}

View file

@ -4,18 +4,25 @@ use core::ptr;
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
/// 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`.
pub unsafe trait PeripheralStateUnchecked {
pub unsafe trait PeripheralStateUnchecked: Sync {
type Interrupt: Interrupt;
fn on_interrupt(&self);
}
// `Peripheral` is safe because `Pin` guarantees that the memory it references will not be invalidated or reused
// without calling `Drop`. However, it provides no guarantees about references contained within the state still being valid,
// so this `'static` bound is necessary.
pub trait PeripheralState: 'static {
/// A type which can be used as state with `Peripheral`.
///
/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt.
///
/// 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;
fn on_interrupt(&self);
}

View file

@ -14,7 +14,7 @@ use embassy::interrupt::Interrupt;
use usb_serial::{ReadInterface, UsbSerial, WriteInterface};
/// 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>
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;
}
@ -176,8 +176,8 @@ pub struct Index1;
impl<B, C1> ClassSet<B> for ClassSet1<B, C1>
where
B: UsbBus,
C1: UsbClass<B>,
B: UsbBus + Send,
C1: UsbClass<B> + Send,
{
fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
device.poll(&mut [&mut self.class])
@ -186,9 +186,9 @@ where
impl<B, C1, C2> ClassSet<B> for ClassSet2<B, C1, C2>
where
B: UsbBus,
C1: UsbClass<B>,
C2: UsbClass<B>,
B: UsbBus + Send,
C1: UsbClass<B> + Send,
C2: UsbClass<B> + Send,
{
fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
device.poll(&mut [&mut self.class1, &mut self.class2])
@ -197,8 +197,8 @@ where
impl<B, C1> IntoClassSet<B, ClassSet1<B, C1>> for C1
where
B: UsbBus,
C1: UsbClass<B>,
B: UsbBus + Send,
C1: UsbClass<B> + Send,
{
fn into_class_set(self) -> ClassSet1<B, C1> {
ClassSet1 {
@ -210,9 +210,9 @@ where
impl<B, C1, C2> IntoClassSet<B, ClassSet2<B, C1, C2>> for (C1, C2)
where
B: UsbBus,
C1: UsbClass<B>,
C2: UsbClass<B>,
B: UsbBus + Send,
C1: UsbClass<B> + Send,
C2: UsbClass<B> + Send,
{
fn into_class_set(self) -> ClassSet2<B, C1, C2> {
ClassSet2 {

View file

@ -29,7 +29,7 @@ pub(crate) mod sealed {
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;
}
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;
}

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 {
waker: AtomicPtr<TaskHeader>,
}