From 392239c7f522acb7ca5847a48dd9ab2480242924 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 6 Aug 2019 16:31:34 -0400 Subject: 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. --- Cargo.lock | 45 ++++++++++++++++++++++++++++++ Cargo.toml | 3 +- examples/dummy.rs | 11 ++++++-- examples/scope.rs | 7 ++++- src/array.rs | 23 +++++++++++++++- src/handler.rs | 64 +++++++++++++++++++++++-------------------- tests/compile-fail/handler.rs | 19 ++++++++----- tests/tests.rs | 2 +- 8 files changed, 131 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfcfe67..0b5518f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,7 @@ dependencies = [ "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "cortex-m 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "cortex-m-rt 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -95,6 +96,7 @@ dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,6 +186,15 @@ name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.3.0" @@ -388,6 +399,25 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tester" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -434,6 +464,11 @@ dependencies = [ "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.7" @@ -443,6 +478,11 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -474,6 +514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" @@ -501,6 +542,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" +"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" @@ -509,6 +552,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 6d6f192..81c783b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,13 @@ readme = "README.md" cortex-m = "~0.6" cortex-m-rt = "~0.6" compiletest_rs = "~0.3" +lazy_static = "~1.3" [target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies] cortex-m = "~0.6" [features] -default = ["isr-32"] +default = ["isr-32", "compiletest_rs/stable"] const-fn = [] # Number of ISR closures to hold in a HandlerTable. This is pretty diff --git a/examples/dummy.rs b/examples/dummy.rs index 7e7c237..cfcd717 100644 --- a/examples/dummy.rs +++ b/examples/dummy.rs @@ -1,24 +1,29 @@ use clint::Handler; +#[macro_use] +extern crate lazy_static; + // Wrapper used to call through to `example_handler` via `closure` in // `main`. `Handler::new()` places a do-nothing handler in this at // compile-time, in case the interrupt using this handler is fired // before being `replace`d in `main`. -static mut HANDLER: Handler = Handler::new(); +lazy_static! { + static ref HANDLER: Handler<'static> = Handler::new(); +} fn main() { let mut x: u32 = 0; // Create a closure to take a mutable reference to `x` for use in // `example_handler`. - let closure = move || example_handler(&mut x); + let mut closure = move || example_handler(&mut x); // Swap out the do-nothing handler with our closure that calls // through to `example_handler`. Ideally, the interrupt which uses // this handler would be disabled while this happens, but as this // is a demo, and there aren't any actual interrupts firing, this // is left as an exercise to the reader. - unsafe { HANDLER.replace(&closure) }; + unsafe { HANDLER.replace(&mut closure) }; // Simulate firing the interrupt. dummy_interrupt(); diff --git a/examples/scope.rs b/examples/scope.rs index cd17570..8df0702 100644 --- a/examples/scope.rs +++ b/examples/scope.rs @@ -1,6 +1,11 @@ use clint::HandlerArray; -static HANDLERS: HandlerArray = HandlerArray::new(); +#[macro_use] +extern crate lazy_static; + +lazy_static! { + static ref HANDLERS: HandlerArray<'static> = HandlerArray::new(); +} fn main() { let mut cl = || println!("whoa!"); 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; 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(&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>, + h: UnsafeCell>>, } 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> = *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() diff --git a/tests/compile-fail/handler.rs b/tests/compile-fail/handler.rs index fdc464a..64ab961 100644 --- a/tests/compile-fail/handler.rs +++ b/tests/compile-fail/handler.rs @@ -1,8 +1,13 @@ extern crate clint; +#[macro_use] +extern crate lazy_static; + use clint::Handler; -static mut HANDLER: Handler = Handler::new(); +lazy_static! { + static ref HANDLER: Handler<'static> = Handler::new(); +} fn main() { need_move(); @@ -12,11 +17,11 @@ fn main() { fn need_move() { let x = vec![1, 2, 3]; - let c = || { + let mut c = || { println!("x(h-c): {:?}", x); //~ ERROR does not live long enough }; unsafe { - HANDLER.replace(&c); + HANDLER.replace(&mut c); HANDLER.call(); HANDLER.call(); } @@ -25,11 +30,11 @@ fn need_move() { fn borrow_error() { let x = vec![1, 2, 3]; - let c = move || { + let mut c = move || { println!("x(h-c): {:?}", x); }; unsafe { - HANDLER.replace(&c); + HANDLER.replace(&mut c); HANDLER.call(); HANDLER.call(); } @@ -38,11 +43,11 @@ fn borrow_error() { fn no_borrow_needed() { let x = vec![1, 2, 3]; - let c = || { + let mut c = || { println!("x(h-c): hi!"); }; unsafe { - HANDLER.replace(&c); + HANDLER.replace(&mut c); HANDLER.call(); HANDLER.call(); } diff --git a/tests/tests.rs b/tests/tests.rs index c295c5a..eedb4b0 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -5,7 +5,7 @@ fn run_mode(mode: &'static str) { config.mode = mode.parse().expect("invalid mode"); config.src_base = PathBuf::from(format!("tests/{}", mode)); - config.target_rustcflags = Some("-L target/debug".to_string()); + config.target_rustcflags = Some("-L target/debug/deps".to_string()); config.clean_rmeta(); compiletest_rs::run_tests(&config); -- cgit v1.2.3