Skip to content

Instantly share code, notes, and snippets.

@cr1901
Last active December 25, 2019 07:46
Show Gist options
  • Save cr1901/6e4761ab9e3debb9e9220093d25eb8c4 to your computer and use it in GitHub Desktop.
Save cr1901/6e4761ab9e3debb9e9220093d25eb8c4 to your computer and use it in GitHub Desktop.
RefCell Misoptimization
[package]
name = "take-api"
version = "0.1.0"
authors = ["William D. Jones <[email protected]>"]
edition = "2018"
[dependencies]
bare-metal = {version = "0.2.5", optional = true }
[dependencies.msp430-rt]
git = "https://github.com/rust-embedded/msp430-rt"
branch = "rt-up"
version = "0.2.0"
[dependencies.panic-msp430]
version = "0.1.0"
[features]
bare_metal = ["bare-metal"]
# xargo build --manifest-path=take-api/Cargo.toml --release --target=msp430-none-elf [--features bare_metal]
#![no_std]
#![no_main]
#![feature(lang_items, start)]
#![feature(abi_msp430_interrupt)]
extern crate panic_msp430;
use core::cell::UnsafeCell;
use core::cell::RefCell;
use msp430_rt::entry;
#[cfg(feature = "bare_metal")]
use bare_metal;
/// Critical section token
///
/// Indicates that you are executing code within a critical section
pub struct CriticalSection {
_0: (),
}
impl CriticalSection {
/// Creates a critical section token
///
/// This method is meant to be used to create safe abstractions rather than
/// meant to be directly used in applications.
pub unsafe fn new() -> Self {
CriticalSection { _0: () }
}
}
/// A "mutex" based on critical sections
///
/// # Safety
///
/// **This Mutex is only safe on single-core systems.**
///
/// On multi-core systems, a `CriticalSection` **is not sufficient** to ensure exclusive access.
pub struct Mutex<T> {
inner: UnsafeCell<T>,
}
impl<T> Mutex<T> {
/// Creates a new mutex
pub const fn new(value: T) -> Self {
Mutex {
inner: UnsafeCell::new(value),
}
}
}
impl<T> Mutex<T> {
/// Borrows the data for the duration of the critical section
pub fn borrow<'cs>(&'cs self, _cs: &'cs CriticalSection) -> &'cs T {
unsafe { &*self.inner.get() }
}
}
// NOTE A `Mutex` can be used as a channel so the protected data must be `Send`
// to prevent sending non-Sendable stuff (e.g. access tokens) across different
// execution contexts (e.g. interrupts)
unsafe impl<T> Sync for Mutex<T> where T: Send {}
#[cfg(not(feature = "bare_metal"))]
static PERIPHERALS : Mutex<RefCell<Option<u8>>> =
Mutex::new(RefCell::new(None));
#[cfg(feature = "bare_metal")]
static PERIPHERALS : bare_metal::Mutex<RefCell<Option<u8>>> =
bare_metal::Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
#[cfg(not(feature = "bare_metal"))]
let _ = PERIPHERALS.borrow(unsafe { &CriticalSection::new() }).borrow_mut();
#[cfg(not(feature = "bare_metal"))]
let _ = PERIPHERALS.borrow(unsafe { &CriticalSection::new() }).borrow();
#[cfg(feature = "bare_metal")]
let _ = PERIPHERALS.borrow(unsafe { &bare_metal::CriticalSection::new() }).borrow_mut();
#[cfg(feature = "bare_metal")]
let _ = PERIPHERALS.borrow(unsafe { &bare_metal::CriticalSection::new() }).borrow();
loop { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment