spin.rs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. use core::{
  2. arch::asm,
  3. sync::atomic::{AtomicBool, Ordering},
  4. };
  5. use crate::sync::preempt_disable;
  6. use super::{preempt_enable, strategy::LockStrategy};
  7. pub struct SpinStrategy;
  8. impl SpinStrategy {
  9. #[inline(always)]
  10. fn is_locked(data: &<Self as LockStrategy>::StrategyData) -> bool {
  11. data.load(Ordering::Relaxed)
  12. }
  13. }
  14. unsafe impl LockStrategy for SpinStrategy {
  15. type StrategyData = AtomicBool;
  16. type GuardContext = ();
  17. #[inline(always)]
  18. fn data() -> Self::StrategyData {
  19. AtomicBool::new(false)
  20. }
  21. #[inline(always)]
  22. unsafe fn do_lock(data: &Self::StrategyData) -> Self::GuardContext {
  23. use Ordering::{Acquire, Relaxed};
  24. preempt_disable();
  25. while data
  26. .compare_exchange_weak(false, true, Acquire, Relaxed)
  27. .is_err()
  28. {
  29. while Self::is_locked(data) {
  30. core::hint::spin_loop();
  31. }
  32. }
  33. }
  34. #[inline(always)]
  35. unsafe fn do_unlock(data: &Self::StrategyData, _: &mut Self::GuardContext) {
  36. data.store(false, Ordering::Release);
  37. preempt_enable();
  38. }
  39. }
  40. pub struct IrqStrategy<Strategy: LockStrategy> {
  41. _phantom: core::marker::PhantomData<Strategy>,
  42. }
  43. unsafe impl<Strategy: LockStrategy> LockStrategy for IrqStrategy<Strategy> {
  44. type StrategyData = Strategy::StrategyData;
  45. type GuardContext = (Strategy::GuardContext, usize);
  46. #[inline(always)]
  47. fn data() -> Self::StrategyData {
  48. Strategy::data()
  49. }
  50. #[inline(always)]
  51. unsafe fn do_lock(data: &Self::StrategyData) -> Self::GuardContext {
  52. let mut context: usize;
  53. asm!(
  54. "pushf",
  55. "pop {context}",
  56. "cli",
  57. context = out(reg) context,
  58. );
  59. (Strategy::do_lock(data), context)
  60. }
  61. #[inline(always)]
  62. unsafe fn do_unlock(
  63. data: &Self::StrategyData,
  64. context: &mut Self::GuardContext,
  65. ) {
  66. Strategy::do_unlock(data, &mut context.0);
  67. asm!(
  68. "push {context}",
  69. "popf",
  70. context = in(reg) context.1,
  71. )
  72. }
  73. #[inline(always)]
  74. unsafe fn do_temporary_unlock(
  75. data: &Self::StrategyData,
  76. context: &mut Self::GuardContext,
  77. ) {
  78. Strategy::do_unlock(data, &mut context.0)
  79. }
  80. #[inline(always)]
  81. unsafe fn do_relock(
  82. data: &Self::StrategyData,
  83. context: &mut Self::GuardContext,
  84. ) {
  85. Strategy::do_relock(data, &mut context.0);
  86. }
  87. }