condvar.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. use crate::{
  2. kernel::{
  3. console::println_trace,
  4. task::{Scheduler, Thread, ThreadState},
  5. },
  6. prelude::*,
  7. sync::preempt,
  8. };
  9. use super::{lock::Guard, strategy::LockStrategy};
  10. use alloc::{collections::vec_deque::VecDeque, sync::Arc};
  11. pub struct CondVar<const INTERRUPTIBLE: bool> {
  12. waiters: Spin<VecDeque<Arc<Thread>>>,
  13. }
  14. impl<const I: bool> core::fmt::Debug for CondVar<I> {
  15. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  16. if I {
  17. f.debug_struct("CondVar").finish()
  18. } else {
  19. f.debug_struct("CondVarUnintrruptible").finish()
  20. }
  21. }
  22. }
  23. impl<const I: bool> CondVar<I> {
  24. pub fn new() -> Self {
  25. Self {
  26. waiters: Spin::new(VecDeque::new()),
  27. }
  28. }
  29. fn wake(thread: &Arc<Thread>) {
  30. println_trace!("trace_condvar", "tid({}) is trying to wake", thread.tid);
  31. if I {
  32. thread.iwake();
  33. } else {
  34. thread.uwake();
  35. }
  36. println_trace!("trace_condvar", "tid({}) is awake", thread.tid);
  37. }
  38. fn sleep() {
  39. let thread = Thread::current();
  40. println_trace!("trace_condvar", "tid({}) is trying to sleep", thread.tid);
  41. if I {
  42. thread.isleep();
  43. } else {
  44. thread.usleep();
  45. }
  46. println_trace!("trace_condvar", "tid({}) is sleeping", thread.tid);
  47. }
  48. pub fn notify_one(&self) {
  49. if let Some(waiter) = self.waiters.lock().pop_front() {
  50. Self::wake(&waiter);
  51. }
  52. }
  53. pub fn notify_all(&self) {
  54. self.waiters.lock().retain(|waiter| {
  55. Self::wake(&waiter);
  56. false
  57. });
  58. }
  59. /// Unlock the `guard`. Then wait until being waken up. Relock the `guard` before returning.
  60. ///
  61. /// # Might Sleep
  62. /// This function **might sleep**, so call it in a preemptible context.
  63. pub fn wait<'a, T, S: LockStrategy, const W: bool>(&self, guard: &mut Guard<'a, T, S, W>) {
  64. preempt::disable();
  65. self.waiters.lock().push_back(Thread::current().clone());
  66. Self::sleep();
  67. // TODO!!!: Another way to do this:
  68. //
  69. // Store a flag in our entry in the waiting list.
  70. // Check the flag before doing `schedule()` but after we've unlocked the `guard`.
  71. // If the flag is already set, we don't need to sleep.
  72. unsafe { guard.force_unlock() };
  73. Scheduler::schedule();
  74. unsafe { guard.force_relock() };
  75. Thread::current().state.assert(ThreadState::RUNNING);
  76. self.waiters
  77. .lock()
  78. .retain(|waiter| waiter.tid != Thread::current().tid);
  79. }
  80. }