rust-embedded / bare-metal Goto Github PK
View Code? Open in Web Editor NEWAbstractions common to microcontrollers
License: Apache License 2.0
Abstractions common to microcontrollers
License: Apache License 2.0
On a multi-core system, disabling interrupts does not prevent the other core from operating, and so values protected by a bare_metal::Mutex
will be incorrectly marked Sync.
Since the overwhelming majority of embedded use cases are single-core, I propose putting a prominent warning in the Mutex
docstring for now, and working to develop a safe multi-core extension to the Mutex which can be enabled with a feature gate. Probably something using an atomic to implement a spinlock on top of requiring a CriticalSection
.
This function can be compiled and leaks a reference to the stack:
fn bad(cs: &bare_metal::CriticalSection) -> &u32 {
let x = bare_metal::Mutex::new(42u32);
x.borrow(cs)
}
The solution is to change the type signature of borrow
to:
pub fn borrow<'cs>(&'cs self, _cs: &'cs CriticalSection) -> &'cs T
It seems inefficient to pass around a &'a CriticalSection
, since reference to zero-sized types are not themselves zero-sized in rust. In a lot of cases, this would be compiled out, but it is not guaranteed.
It would be better if CriticalSection
was defined like this:
struct CriticalSection<'a> {
_0: PhantomData<&'a ()>,
}
Instead of passing &'a CriticalSection
you would then pass a CriticalSection<'a>
around. This would have the same purpose
Is there a reason Mutex
does not have a borrow_mut()
?
Happy to open a PR if desired :)
Based on Matrix discussions, I think I understand why the current Mutex
API was chosen. However, using Mutex<RefCell<T>>
is a bit more painful than I think it could be. Would it be possible to add an inherent block for Mutex<RefCell<T>>
? It would basically combine .borrow(cs)
with some of RefCell
's methods, so that you don't end up with things like .borrow(cs).borrow_mut()
.
I can make a PR, but first I wanted to see if it would be a non-starter for some reason. It wouldn't be breaking, right?
We have Mutex. However, opening a critical section (disabling interrupts) to just read or write a Mutex<Cell<u8>>
seems a bit overkill: the read or write is a single instruction, which makes it impossible for an interrupt to hit in the middle.
How about this crate also provides some form of atomics with respect to what the Send
and Sync
markers mean in our context?
(I beleive they would be implemented this way, I'd be very willing to open a PR)
use core::cell::UnsafeCell;
pub struct SingleCoreAtomicUsize {
inner: UnsafeCell<usize>,
}
/// Safety:
/// We only provide `get` and `set`, which all take a single instruction, so no interrupt may hit in the middle
unsafe impl Sync for SingleCoreAtomicUsize {}
impl SingleCoreAtomicUsize {
pub const fn new(val: usize) -> Self {
Self {
inner: UnsafeCell::new(val),
}
}
pub fn get(&self) -> usize {
unsafe { *self.inner.get() }
}
pub fn set(&self, val: usize) {
unsafe { *self.inner.get() = val }
}
}
I personally think CriticalSection
should not be Clone
, because of two use case requiring that:
interrupt::enable_cs
: Safely enable interrupts, consuming a critical section. This can't work if there can be another copy lying around.Mutex::borrow_mut
: I'm quite sure this would allow to mutably borrow data in a mutex, by taking a &mut CriticalSection
. This would only allow to mutably borrow one mutex as once, but I think it is still better than Mutex<RefCell<_>>
.All actual use cases ought to work by passing a &CriticalSection
, although I don't think this needs to be used often. Should the size of &CriticalSection
be a problem, one could imagine a SharedCriticalSection
ZST borrowing a CriticalSection
.
I was just checking how well my crates would play with the 2018 edition and I was able to work around most quirks except for a few with the most major probably being that it seems to be impossible to share peripherals via the good old Mutex<RefCell<Option<_>>>
static mechanism due to the inavailability of const_fn
:
error[E0015]: calls in statics are limited to tuple structs and tuple variants
--> examples/i2c_haldriver_printmagserial.rs:31:62
|
31 | static MAG3110: Mutex<RefCell<Option<Mag3110<I2c<TWI1>>>>> = Mutex::new(RefCell::new(None));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: a limited form of compile-time function evaluation is available on a nightly compiler via `const fn`
--> examples/i2c_haldriver_printmagserial.rs:31:62
|
31 | static MAG3110: Mutex<RefCell<Option<Mag3110<I2c<TWI1>>>>> = Mutex::new(RefCell::new(None));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Is there any good workaround we can use here? Not being able to pass around peripherals and data safely into/out of interrupt handlers would be pretty bad, IMHO.
Part of rust-embedded/wg#383
Blockers:
Peripheral
be removed?Nr
trait? (it's gone)As per rust-embedded/r0#8
Per #22, we should audit the library against the API Guidelines prior to 1.0 to avoid making breaking changes after the fact.
The checklist is below.
As items are reviewed, we can mark them as completed.
New issues should be opened for items that fail the review.
https://rust-lang.github.io/api-guidelines/checklist.html
as_
, to_
, into_
conventions (C-CONV)iter
, iter_mut
, into_iter
(C-ITER)Copy
, Clone
, Eq
, PartialEq
, Ord
, PartialOrd
, Hash
, Debug
,Display
, Default
From
, AsRef
, AsMut
(C-CONV-TRAITS)FromIterator
and Extend
(C-COLLECT)Serialize
, Deserialize
(C-SERDE)Send
and Sync
where possible (C-SEND-SYNC)Hex
, Octal
, Binary
formatting (C-NUM-FMT)R: Read
and W: Write
by value (C-RW-VALUE)?
, not try!
, not unwrap
(C-QUESTION-MARK)Deref
and DerefMut
(C-DEREF)bool
or Option
(C-CUSTOM-TYPE)bitflags
, not enums (C-BITFLAG)Debug
(C-DEBUG)Debug
representation is never empty (C-DEBUG-NONEMPTY)A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.