timer.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. use alloc::{collections::BinaryHeap, vec, vec::Vec};
  2. use core::{
  3. cell::RefCell,
  4. cmp::Reverse,
  5. ops::Add,
  6. sync::atomic::{AtomicUsize, Ordering},
  7. task::{Poll, Waker},
  8. time::Duration,
  9. };
  10. use eonix_hal::processor::CPU;
  11. use eonix_sync::{Spin, SpinIrq as _};
  12. static TICKS: AtomicUsize = AtomicUsize::new(0);
  13. static WAKEUP_TICK: AtomicUsize = AtomicUsize::new(usize::MAX);
  14. static SLEEPERS_LIST: Spin<BinaryHeap<Reverse<Sleepers>>> = Spin::new(BinaryHeap::new());
  15. #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
  16. pub struct Ticks(usize);
  17. pub struct Instant(Ticks);
  18. struct Sleepers {
  19. wakeup_tick: Ticks,
  20. wakers: RefCell<Vec<Waker>>,
  21. }
  22. impl Ord for Sleepers {
  23. fn cmp(&self, other: &Self) -> core::cmp::Ordering {
  24. self.wakeup_tick.cmp(&other.wakeup_tick)
  25. }
  26. }
  27. impl PartialOrd for Sleepers {
  28. fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
  29. Some(self.cmp(other))
  30. }
  31. }
  32. impl Eq for Sleepers {}
  33. impl PartialEq for Sleepers {
  34. fn eq(&self, other: &Self) -> bool {
  35. self.wakeup_tick == other.wakeup_tick
  36. }
  37. }
  38. impl Ticks {
  39. pub const fn in_secs(&self) -> u64 {
  40. self.0 as u64 / 1_000
  41. }
  42. pub const fn in_msecs(&self) -> u128 {
  43. self.0 as u128
  44. }
  45. pub const fn in_usecs(&self) -> u128 {
  46. self.0 as u128 * 1_000
  47. }
  48. pub const fn in_nsecs(&self) -> u128 {
  49. self.0 as u128 * 1_000_000
  50. }
  51. pub fn now() -> Self {
  52. Ticks(TICKS.load(Ordering::Acquire))
  53. }
  54. pub fn since_boot() -> Duration {
  55. Duration::from_nanos(Self::now().in_nsecs() as u64)
  56. }
  57. }
  58. impl Instant {
  59. pub fn now() -> Self {
  60. Instant(Ticks::now())
  61. }
  62. pub fn elapsed(&self) -> Duration {
  63. Duration::from_nanos((Ticks::now().in_nsecs() - self.0.in_nsecs()) as u64)
  64. }
  65. }
  66. impl From<Ticks> for Instant {
  67. fn from(ticks: Ticks) -> Self {
  68. Instant(ticks)
  69. }
  70. }
  71. impl From<Instant> for Ticks {
  72. fn from(instant: Instant) -> Self {
  73. instant.0
  74. }
  75. }
  76. impl Add for Ticks {
  77. type Output = Ticks;
  78. fn add(self, other: Self) -> Self::Output {
  79. Ticks(self.0 + other.0)
  80. }
  81. }
  82. impl Add<Duration> for Instant {
  83. type Output = Instant;
  84. fn add(self, duration: Duration) -> Self::Output {
  85. Instant(self.0 + Ticks(duration.as_millis() as usize))
  86. }
  87. }
  88. pub fn timer_interrupt() {
  89. if CPU::local().cpuid() != 0 {
  90. // Only the BSP should handle the timer interrupt.
  91. return;
  92. }
  93. let current_tick = TICKS.fetch_add(1, Ordering::Relaxed) + 1;
  94. let wakeup_tick = WAKEUP_TICK.load(Ordering::Acquire);
  95. if wakeup_tick <= current_tick {
  96. let mut sleepers = SLEEPERS_LIST.lock_irq();
  97. let Some(Reverse(sleepers_to_wakeup)) = sleepers.pop() else {
  98. return;
  99. };
  100. for waker in sleepers_to_wakeup.wakers.into_inner() {
  101. waker.wake();
  102. }
  103. if WAKEUP_TICK.load(Ordering::Acquire) == wakeup_tick {
  104. // The wakeup tick is not changed.
  105. // Set the next wakeup tick to the next sleeper's wakeup time.
  106. let wakeup_tick = sleepers
  107. .peek()
  108. .map(|sleepers| sleepers.0.wakeup_tick.0)
  109. .unwrap_or(usize::MAX);
  110. WAKEUP_TICK.store(wakeup_tick, Ordering::Release);
  111. }
  112. }
  113. }
  114. /// Returns true if the timeslice of the current task has expired and it should be rescheduled.
  115. pub fn should_reschedule() -> bool {
  116. #[eonix_percpu::define_percpu]
  117. static PREV_SCHED_TICK: usize = 0;
  118. let prev_tick = PREV_SCHED_TICK.get();
  119. let current_tick = Ticks::now().0;
  120. if Ticks(current_tick - prev_tick).in_msecs() >= 10 {
  121. PREV_SCHED_TICK.set(current_tick);
  122. true
  123. } else {
  124. false
  125. }
  126. }
  127. pub fn ticks() -> Ticks {
  128. Ticks::now()
  129. }
  130. pub async fn sleep(duration: Duration) {
  131. let wakeup_time = Instant::now() + duration;
  132. let wakeup_tick = Ticks::from(wakeup_time);
  133. core::future::poll_fn(|ctx| {
  134. if Ticks::now() >= wakeup_tick {
  135. return Poll::Ready(());
  136. }
  137. let mut sleepers_list = SLEEPERS_LIST.lock_irq();
  138. let sleepers: Option<&Reverse<Sleepers>> = sleepers_list
  139. .iter()
  140. .find(|s| s.0.wakeup_tick == wakeup_tick);
  141. match sleepers {
  142. Some(Reverse(sleepers)) => {
  143. sleepers.wakers.borrow_mut().push(ctx.waker().clone());
  144. }
  145. None => {
  146. sleepers_list.push(Reverse(Sleepers {
  147. wakeup_tick,
  148. wakers: RefCell::new(vec![ctx.waker().clone()]),
  149. }));
  150. }
  151. }
  152. if wakeup_tick < Ticks(WAKEUP_TICK.load(Ordering::Acquire)) {
  153. WAKEUP_TICK.store(wakeup_tick.0, Ordering::Release);
  154. }
  155. Poll::Pending
  156. })
  157. .await;
  158. }