diff options
author | Brian Cully <bjc@kublai.com> | 2019-08-06 16:31:34 -0400 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2019-08-06 16:31:34 -0400 |
commit | 392239c7f522acb7ca5847a48dd9ab2480242924 (patch) | |
tree | b02f1f568085ae1dcb3c33c780d49a8d1a77a2eb /src | |
parent | b0c6c4f9a45cf2b965acd3d10499e9df54929b36 (diff) | |
download | clint-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.rs | 23 | ||||
-rw-r--r-- | src/handler.rs | 64 |
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() |