guard.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use super::{
  2. ContextUnlock, DisablePreemption, Relax, Spin, SpinContext, SpinRelax, UnlockedContext,
  3. };
  4. use core::{
  5. marker::PhantomData,
  6. mem::ManuallyDrop,
  7. ops::{Deref, DerefMut},
  8. };
  9. use eonix_sync_base::{NotSend, UnlockableGuard, UnlockedGuard};
  10. pub struct SpinGuard<'a, T, C = DisablePreemption, R = SpinRelax>
  11. where
  12. T: ?Sized,
  13. C: SpinContext,
  14. {
  15. lock: &'a Spin<T, R>,
  16. value: &'a mut T,
  17. context: Option<C>,
  18. /// We don't want this to be `Send` because we don't want to allow the guard to be
  19. /// transferred to another thread since we have disabled the preemption on the local cpu.
  20. _not_send: PhantomData<NotSend>,
  21. }
  22. pub struct UnlockedSpinGuard<'a, T, C, R>(&'a Spin<T, R>, C::Unlocked)
  23. where
  24. T: ?Sized,
  25. C: ContextUnlock;
  26. // SAFETY: As long as the value protected by the lock is able to be shared between threads,
  27. // we can access the guard from multiple threads.
  28. unsafe impl<T, C, R> Sync for SpinGuard<'_, T, C, R>
  29. where
  30. T: ?Sized + Sync,
  31. C: SpinContext,
  32. {
  33. }
  34. impl<'a, T, C, R> SpinGuard<'a, T, C, R>
  35. where
  36. T: ?Sized,
  37. C: SpinContext,
  38. {
  39. pub(super) fn new(lock: &'a Spin<T, R>, value: &'a mut T, context: C) -> Self {
  40. Self {
  41. lock,
  42. value,
  43. context: Some(context),
  44. _not_send: PhantomData,
  45. }
  46. }
  47. }
  48. impl<T, C, R> Drop for SpinGuard<'_, T, C, R>
  49. where
  50. T: ?Sized,
  51. C: SpinContext,
  52. {
  53. fn drop(&mut self) {
  54. unsafe {
  55. // SAFETY: We are dropping the guard, so we are not holding the lock anymore.
  56. self.lock.do_unlock();
  57. self.context
  58. .take()
  59. .expect("We should have a context here")
  60. .restore();
  61. }
  62. }
  63. }
  64. impl<T, C, R> Deref for SpinGuard<'_, T, C, R>
  65. where
  66. T: ?Sized,
  67. C: SpinContext,
  68. {
  69. type Target = T;
  70. fn deref(&self) -> &Self::Target {
  71. // SAFETY: We are holding the lock, so we can safely access the value.
  72. self.value
  73. }
  74. }
  75. impl<T, C, R> DerefMut for SpinGuard<'_, T, C, R>
  76. where
  77. T: ?Sized,
  78. C: SpinContext,
  79. {
  80. fn deref_mut(&mut self) -> &mut Self::Target {
  81. // SAFETY: We are holding the lock, so we can safely access the value.
  82. self.value
  83. }
  84. }
  85. impl<T, U, C, R> AsRef<U> for SpinGuard<'_, T, C, R>
  86. where
  87. T: ?Sized,
  88. C: SpinContext,
  89. U: ?Sized,
  90. <Self as Deref>::Target: AsRef<U>,
  91. {
  92. fn as_ref(&self) -> &U {
  93. self.deref().as_ref()
  94. }
  95. }
  96. impl<T, U, C, R> AsMut<U> for SpinGuard<'_, T, C, R>
  97. where
  98. T: ?Sized,
  99. C: SpinContext,
  100. U: ?Sized,
  101. <Self as Deref>::Target: AsMut<U>,
  102. {
  103. fn as_mut(&mut self) -> &mut U {
  104. self.deref_mut().as_mut()
  105. }
  106. }
  107. impl<'a, T, C, R> UnlockableGuard for SpinGuard<'a, T, C, R>
  108. where
  109. T: ?Sized + Send,
  110. C: ContextUnlock,
  111. C::Unlocked: Send,
  112. R: Relax,
  113. {
  114. type Unlocked = UnlockedSpinGuard<'a, T, C, R>;
  115. fn unlock(self) -> Self::Unlocked {
  116. let mut me = ManuallyDrop::new(self);
  117. unsafe {
  118. // SAFETY: No access is possible after unlocking.
  119. me.lock.do_unlock();
  120. }
  121. let unlocked_context = me
  122. .context
  123. .take()
  124. .expect("We should have a context here")
  125. .unlock();
  126. UnlockedSpinGuard(me.lock, unlocked_context)
  127. }
  128. }
  129. // SAFETY: The guard is stateless so no more process needed.
  130. unsafe impl<'a, T, C, R> UnlockedGuard for UnlockedSpinGuard<'a, T, C, R>
  131. where
  132. T: ?Sized + Send,
  133. C: ContextUnlock,
  134. C::Unlocked: Send,
  135. R: Relax,
  136. {
  137. type Guard = SpinGuard<'a, T, C, R>;
  138. async fn relock(self) -> Self::Guard {
  139. let Self(lock, context) = self;
  140. let context = context.relock();
  141. lock.do_lock();
  142. SpinGuard::new(lock, unsafe { &mut *lock.value.get() }, context)
  143. }
  144. }