aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-08-06 16:31:34 -0400
committerBrian Cully <bjc@kublai.com>2019-08-06 16:31:34 -0400
commit392239c7f522acb7ca5847a48dd9ab2480242924 (patch)
treeb02f1f568085ae1dcb3c33c780d49a8d1a77a2eb /src
parentb0c6c4f9a45cf2b965acd3d10499e9df54929b36 (diff)
downloadclint-392239c7f522acb7ca5847a48dd9ab2480242924.tar.gz
clint-392239c7f522acb7ca5847a48dd9ab2480242924.zip
Add compatibilty with rust-stable.
* Add feature flag for const-fn functionality, which simplifies some things and lets this crate run on architectures where atomic CAS isn't available (e.g., thumbv6). * Remove `const fn` where necessary to compile under rust-stable. * BREAKING CHANGE - Change signature of `Handler::replace` to take a mutable borrow. This is required because the underlying type is now a NonNull, which needs `mut`. The old behavior was never desired, but a consequence of trying to avoid `Option` by using a default handler. * Use lazy_static crate for initialization of Handler/HandlerArray. * Specify Sync for Handler. This is not amazing, since it isn't, but it's necessary for initialization in static contexts inside `lazy_static`. This should be fine, because any actual manipulation of the handler is done in unsafe functions.
Diffstat (limited to 'src')
-rw-r--r--src/array.rs23
-rw-r--r--src/handler.rs64
2 files changed, 57 insertions, 30 deletions
diff --git a/src/array.rs b/src/array.rs
index e01fe74..d460824 100644
--- a/src/array.rs
+++ b/src/array.rs
@@ -18,7 +18,12 @@
//! use clint::HandlerArray;
//! use cortex_m_rt::exception;
//!
-//! static HANDLERS: HandlerArray = HandlerArray::new();
+//! #[macro_use]
+//! extern crate lazy_static;
+//!
+//! lazy_static! {
+//! static ref HANDLERS: HandlerArray<'static> = HandlerArray::new();
+//! }
//!
//! fn main() {
//! // NB: This closure has to be created outside of `with_overrides` to
@@ -75,12 +80,28 @@ pub struct HandlerArray<'a> {
impl<'a> HandlerArray<'a> {
/// Create a new `HandlerArray` filled with no-op handlers.
+ #[cfg(feature = "const-fn")]
pub const fn new() -> Self {
Self {
h: UnsafeCell::new([Handler::new(); NR_ISR]),
}
}
+ #[cfg(not(feature = "const-fn"))]
+ pub fn new() -> Self {
+ let h = {
+ let mut ui_h: [core::mem::MaybeUninit<Handler>; NR_ISR] =
+ unsafe { core::mem::MaybeUninit::uninit().assume_init() };
+ for h in &mut ui_h[..] {
+ unsafe { core::ptr::write(h.as_mut_ptr(), Handler::new()) }
+ }
+ unsafe { core::mem::transmute(ui_h) }
+ };
+ Self {
+ h: UnsafeCell::new(h),
+ }
+ }
+
/// Register `f` for entry `nr` in this array using the default
/// critical section locker.
pub fn register<F>(&self, nr: usize, f: &'a mut F)
diff --git a/src/handler.rs b/src/handler.rs
index 545e622..1087b21 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -56,18 +56,23 @@
//! use clint::Handler;
//! use cortex_m_rt::exception;
//!
-//! static mut SYSTICK_HANDLER: Handler = Handler::new();
+//! #[macro_use]
+//! extern crate lazy_static;
+//!
+//! lazy_static! {
+//! static ref SYSTICK_HANDLER: Handler<'static> = Handler::new();
+//! }
//!
//! fn main() {
//! // NB: `closure` is in the lexical scope of `main`, and thus
//! // cannot go out of scope.
-//! let closure = || {
+//! let mut closure = || {
//! // Your interrupt handling code.
//! };
//! // Replace the handler for SysTick with closure while interrupts are
//! // disabled.
//! cortex_m::interrupt::free(|_| {
-//! unsafe { SYSTICK_HANDLER.replace(&closure) };
+//! unsafe { SYSTICK_HANDLER.replace(&mut closure) };
//! });
//!
//! loop {
@@ -81,34 +86,37 @@
//! }
//! ```
#[cfg(not(feature = "const-fn"))]
+use core::cell::UnsafeCell;
+#[cfg(not(feature = "const-fn"))]
use core::ptr::NonNull;
#[cfg(feature = "const-fn")]
pub struct Handler<'a> {
// Handler that will be executed on `call`.
- h: *const dyn FnMut(),
+ h: *mut dyn FnMut(),
lifetime: core::marker::PhantomData<&'a dyn FnMut()>,
}
#[cfg(not(feature = "const-fn"))]
pub struct Handler<'a> {
// Handler that will be executed on `call`.
- h: Option<NonNull<dyn FnMut() + 'a>>,
+ h: UnsafeCell<Option<NonNull<dyn FnMut() + 'a>>>,
}
impl<'a> Handler<'a> {
/// Returns a new Handler that initially does nothing when
/// called. Override its behavior by using `replace`.
+ #[cfg(feature = "const-fn")]
pub const fn new() -> Self {
- #[cfg(feature = "const-fn")]
- {
- Self {
- h: &Self::default_handler,
- lifetime: core::marker::PhantomData,
- }
+ Self {
+ h: &Self::default_handler,
+ lifetime: core::marker::PhantomData,
}
- #[cfg(not(feature = "const-fn"))]
- {
- Self { h: None }
+ }
+
+ #[cfg(not(feature = "const-fn"))]
+ pub fn new() -> Self {
+ Self {
+ h: UnsafeCell::new(None),
}
}
@@ -119,7 +127,7 @@ impl<'a> Handler<'a> {
/// There is no exclusion on replacing the handler's behavior
/// while it is being executed. It is your responsibility to make
/// sure that it's not being executed when you call `replace`.
- pub unsafe fn replace(&mut self, f: &(dyn FnMut() + Send + 'a)) {
+ pub unsafe fn replace(&self, f: &mut (dyn FnMut() + Send + 'a)) {
#[cfg(feature = "const-fn")]
{
self.h = core::mem::transmute::<_, &'a _>(f);
@@ -128,7 +136,7 @@ impl<'a> Handler<'a> {
{
// let ptr: *mut dyn FnMut() = core::mem::transmute::<_, &'a _>(f);
// self.h = Some(NonNull::new(ptr));
- self.h = Some(NonNull::new_unchecked(f));
+ *self.h.get() = Some(NonNull::new_unchecked(f));
}
}
@@ -147,7 +155,8 @@ impl<'a> Handler<'a> {
}
#[cfg(not(feature = "const-fn"))]
{
- self.h.map(|mut f| (f.as_mut())());
+ let h: Option<NonNull<dyn FnMut()>> = *self.h.get();
+ h.map(|mut f| (f.as_mut())());
}
}
@@ -159,29 +168,24 @@ impl<'a> Handler<'a> {
impl<'a> core::fmt::Debug for Handler<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- let (f0, f1) = unsafe { core::mem::transmute::<_, (usize, usize)>(self.h) };
+ let (f0, f1) = unsafe { core::mem::transmute::<_, (usize, usize)>(*self.h.get()) };
write!(f, "Handler{{ h: (0x{:x}, 0x{:x}) }}", f0, f1)
}
}
-// FIXME: This probably shouldn't be Copy/Clone, but it needs to be in
-// order for array initialization to work with [Handler::new(); 32].
-impl<'a> core::marker::Copy for Handler<'a> {}
-impl<'a> core::clone::Clone for Handler<'a> {
- fn clone(&self) -> Self {
- *self
- }
-}
+unsafe impl Sync for Handler<'_> {}
#[cfg(test)]
mod test {
use super::*;
+ use lazy_static::*;
+
#[test]
fn replace() {
static mut X: usize = 0;
- let mut handler = Handler::new();
+ let handler = Handler::new();
unsafe {
handler.replace(&mut || X += 1);
assert_eq!(X, 0);
@@ -193,7 +197,9 @@ mod test {
#[test]
fn replace_static() {
- static mut HANDLER: Handler = Handler::new();
+ lazy_static! {
+ static ref HANDLER: Handler<'static> = Handler::new();
+ }
static mut X: usize = 0;
unsafe {
@@ -207,7 +213,7 @@ mod test {
#[test]
fn replace_with_default() {
- let mut handler = Handler::new();
+ let handler = Handler::new();
unsafe {
handler.replace(&mut Handler::default_handler);
handler.call()