-
Notifications
You must be signed in to change notification settings - Fork 12
Panic if SpinLock locked in interrupt context #528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7efb2ec
Count nested interrupts.
kitlith 96e294a
Panic if SpinLock locked in interrupt context.
kitlith 69374bf
Add verbose message.
kitlith 4e1ea51
Syscall context != IRQ context
kitlith 6e0a6da
FIXUP!
kitlith d30731f
Fix boot (and panic in interrupt).
kitlith File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| //! Lock that panics when used in a IRQ context | ||
| //! | ||
| //! See the [sync] module documentation. | ||
| //! | ||
| //! [sync]: crate::sync | ||
|
|
||
| use core::fmt; | ||
|
|
||
| pub use spin::MutexGuard as SpinLockGuard; | ||
|
|
||
| /// This type provides mutual exclusion based on spinning. | ||
| /// It will panic if used in the context of an interrupt. | ||
| /// | ||
| /// # Description | ||
| /// | ||
| /// The behaviour of these locks is similar to `std::sync::Mutex`. they | ||
| /// differ on the following: | ||
| /// | ||
| /// - The lock will not be poisoned in case of failure; | ||
| /// | ||
| /// # Simple examples | ||
| /// | ||
| /// ``` | ||
| /// use crate::sync::SpinLock; | ||
| /// let spin_lock = SpinLock::new(0); | ||
| /// | ||
| /// // Modify the data | ||
| /// { | ||
| /// let mut data = spin_lock.lock(); | ||
| /// *data = 2; | ||
| /// } | ||
| /// | ||
| /// // Read the data | ||
| /// let answer = | ||
| /// { | ||
| /// let data = spin_lock.lock(); | ||
| /// *data | ||
| /// }; | ||
| /// | ||
| /// assert_eq!(answer, 2); | ||
| /// ``` | ||
| /// | ||
| /// # Thread-safety example | ||
| /// | ||
| /// ``` | ||
| /// use crate::sync::SpinLock; | ||
| /// use std::sync::{Arc, Barrier}; | ||
| /// | ||
| /// let numthreads = 1000; | ||
| /// let spin_lock = Arc::new(SpinLock::new(0)); | ||
| /// | ||
| /// // We use a barrier to ensure the readout happens after all writing | ||
| /// let barrier = Arc::new(Barrier::new(numthreads + 1)); | ||
| /// | ||
| /// for _ in (0..numthreads) | ||
| /// { | ||
| /// let my_barrier = barrier.clone(); | ||
| /// let my_lock = spin_lock.clone(); | ||
| /// std::thread::spawn(move|| | ||
| /// { | ||
| /// let mut guard = my_lock.lock(); | ||
| /// *guard += 1; | ||
| /// | ||
| /// // Release the lock to prevent a deadlock | ||
| /// drop(guard); | ||
| /// my_barrier.wait(); | ||
| /// }); | ||
| /// } | ||
| /// | ||
| /// barrier.wait(); | ||
| /// | ||
| /// let answer = { *spin_lock.lock() }; | ||
| /// assert_eq!(answer, numthreads); | ||
| /// ``` | ||
| #[repr(transparent)] | ||
| pub struct SpinLock<T: ?Sized>(spin::Mutex<T>); | ||
|
|
||
| impl<T> SpinLock<T> { | ||
| /// Creates a new spinlock wrapping the supplied data. | ||
| /// | ||
| /// May be used statically: | ||
| /// | ||
| /// ``` | ||
| /// use crate::sync::SpinLock; | ||
| /// | ||
| /// static SPINLOCK: SpinLock<()> = SpinLock::new(()); | ||
| /// | ||
| /// fn demo() { | ||
| /// let lock = SPINLOCK.lock(); | ||
| /// // do something with lock | ||
| /// drop(lock); | ||
| /// } | ||
| /// ``` | ||
| pub const fn new(data: T) -> SpinLock<T> { | ||
| SpinLock(spin::Mutex::new(data)) | ||
| } | ||
|
|
||
| /// Consumes this spinlock, returning the underlying data. | ||
| pub fn into_inner(self) -> T { | ||
| self.0.into_inner() | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized> SpinLock<T> { | ||
| /// Locks the spinlock and returns a guard. | ||
| /// | ||
| /// The returned value may be dereferenced for data access | ||
| /// and the lock will be dropped when the guard falls out of scope. | ||
| /// | ||
| /// Panics if called in an interrupt context. | ||
| /// | ||
| /// ``` | ||
| /// let mylock = crate::sync::SpinLock::new(0); | ||
| /// { | ||
| /// let mut data = mylock.lock(); | ||
| /// // The lock is now locked and the data can be accessed | ||
| /// *data += 1; | ||
| /// // The lock is implicitly dropped | ||
| /// } | ||
| /// | ||
| /// ``` | ||
| pub fn lock(&self) -> SpinLockGuard<T> { | ||
| use core::sync::atomic::Ordering; | ||
| use crate::cpu_locals::ARE_CPU_LOCALS_INITIALIZED_YET; | ||
| use crate::i386::interrupt_service_routines::INSIDE_INTERRUPT_COUNT; | ||
| use super::INTERRUPT_DISARM; | ||
| if !INTERRUPT_DISARM.load(Ordering::SeqCst) && ARE_CPU_LOCALS_INITIALIZED_YET.load(Ordering::SeqCst) && INSIDE_INTERRUPT_COUNT.load(Ordering::SeqCst) != 0 { | ||
| panic!("\ | ||
| You have attempted to lock a spinlock in interrupt context. \ | ||
| This is most likely a design flaw. \ | ||
| See documentation of the sync module."); | ||
| } | ||
| self.0.lock() | ||
| } | ||
|
|
||
| /// Force unlock the spinlock. | ||
| /// | ||
| /// This is *extremely* unsafe if the lock is not held by the current | ||
| /// thread. However, this can be useful in some instances for exposing the | ||
| /// lock to FFI that doesn't know how to deal with RAII. | ||
| /// | ||
| /// If the lock isn't held, this is a no-op. | ||
| pub unsafe fn force_unlock(&self) { | ||
| self.0.force_unlock() | ||
| } | ||
|
|
||
| /// Tries to lock the spinlock. If it is already locked, it will return None. Otherwise it returns | ||
| /// a guard within Some. | ||
| pub fn try_lock(&self) -> Option<SpinLockGuard<T>> { | ||
| use core::sync::atomic::Ordering; | ||
| if crate::i386::interrupt_service_routines::INSIDE_INTERRUPT_COUNT.load(Ordering::SeqCst) != 0 { | ||
| panic!("\ | ||
| You have attempted to lock a spinlock in interrupt context. \ | ||
| This is most likely a design flaw. \ | ||
| See documentation of the sync module."); | ||
| } | ||
| self.0.try_lock() | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + fmt::Debug> fmt::Debug for SpinLock<T> { | ||
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| self.0.fmt(f) | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + Default> Default for SpinLock<T> { | ||
| fn default() -> SpinLock<T> { | ||
| Self::new(Default::default()) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.