spin.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. mod guard;
  2. mod relax;
  3. mod spin_irq;
  4. use core::{
  5. cell::UnsafeCell,
  6. marker::PhantomData,
  7. sync::atomic::{AtomicBool, Ordering},
  8. };
  9. pub use guard::{SpinGuard, UnlockedSpinGuard};
  10. pub use relax::{LoopRelax, Relax, SpinRelax};
  11. pub use spin_irq::SpinIrq;
  12. pub trait SpinContext {
  13. fn save() -> Self;
  14. fn restore(self);
  15. }
  16. pub trait ContextUnlock: SpinContext {
  17. type Unlocked: UnlockedContext<Relocked = Self>;
  18. fn unlock(self) -> Self::Unlocked;
  19. }
  20. pub trait UnlockedContext {
  21. type Relocked: ContextUnlock<Unlocked = Self>;
  22. fn relock(self) -> Self::Relocked;
  23. }
  24. pub struct NoContext;
  25. pub struct DisablePreemption();
  26. //// A spinlock is a lock that uses busy-waiting to acquire the lock.
  27. /// It is useful for short critical sections where the overhead of a context switch
  28. /// is too high.
  29. #[derive(Debug, Default)]
  30. pub struct Spin<T, R = SpinRelax>
  31. where
  32. T: ?Sized,
  33. {
  34. _phantom: PhantomData<R>,
  35. locked: AtomicBool,
  36. value: UnsafeCell<T>,
  37. }
  38. impl<T, R> Spin<T, R>
  39. where
  40. R: Relax,
  41. {
  42. pub const fn new(value: T) -> Self {
  43. Self {
  44. locked: AtomicBool::new(false),
  45. value: UnsafeCell::new(value),
  46. _phantom: PhantomData,
  47. }
  48. }
  49. }
  50. impl<T, R> Spin<T, R>
  51. where
  52. T: ?Sized,
  53. {
  54. /// # Safety
  55. /// This function is unsafe because the caller MUST ensure that the protected
  56. /// value is no longer accessed after calling this function.
  57. unsafe fn do_unlock(&self) {
  58. let locked = self.locked.swap(false, Ordering::Release);
  59. debug_assert!(locked, "Spin::unlock(): Unlocking an unlocked lock");
  60. }
  61. }
  62. impl<T, R> Spin<T, R>
  63. where
  64. T: ?Sized,
  65. R: Relax,
  66. {
  67. pub fn lock_with_context<C>(&self, context: C) -> SpinGuard<T, C, R>
  68. where
  69. C: SpinContext,
  70. {
  71. self.do_lock();
  72. SpinGuard::new(
  73. self,
  74. unsafe {
  75. // SAFETY: We are holding the lock, so we can safely access the value.
  76. &mut *self.value.get()
  77. },
  78. context,
  79. )
  80. }
  81. pub fn lock(&self) -> SpinGuard<T, DisablePreemption, R> {
  82. self.lock_with_context(DisablePreemption::save())
  83. }
  84. pub fn get_mut(&mut self) -> &mut T {
  85. // SAFETY: The exclusive access to the lock is guaranteed by the borrow checker.
  86. unsafe { &mut *self.value.get() }
  87. }
  88. fn do_lock(&self) {
  89. while let Err(_) =
  90. self.locked
  91. .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
  92. {
  93. R::relax();
  94. }
  95. }
  96. }
  97. // SAFETY: As long as the value protected by the lock is able to be shared between threads,
  98. // we can send the lock between threads.
  99. unsafe impl<T, R> Send for Spin<T, R> where T: ?Sized + Send {}
  100. // SAFETY: As long as the value protected by the lock is able to be shared between threads,
  101. // we can provide exclusive access guarantees to the lock.
  102. unsafe impl<T, R> Sync for Spin<T, R> where T: ?Sized + Send {}
  103. impl SpinContext for NoContext {
  104. fn save() -> Self {
  105. Self
  106. }
  107. fn restore(self) {}
  108. }
  109. impl ContextUnlock for NoContext {
  110. type Unlocked = NoContext;
  111. fn unlock(self) -> Self::Unlocked {
  112. self
  113. }
  114. }
  115. impl UnlockedContext for NoContext {
  116. type Relocked = NoContext;
  117. fn relock(self) -> Self::Relocked {
  118. self
  119. }
  120. }
  121. impl SpinContext for DisablePreemption {
  122. fn save() -> Self {
  123. eonix_preempt::disable();
  124. Self()
  125. }
  126. fn restore(self) {
  127. eonix_preempt::enable();
  128. }
  129. }
  130. impl ContextUnlock for DisablePreemption {
  131. type Unlocked = DisablePreemption;
  132. fn unlock(self) -> Self::Unlocked {
  133. eonix_preempt::enable();
  134. self
  135. }
  136. }
  137. impl UnlockedContext for DisablePreemption {
  138. type Relocked = DisablePreemption;
  139. fn relock(self) -> Self::Relocked {
  140. eonix_preempt::disable();
  141. self
  142. }
  143. }