condvar.rs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. use crate::kernel::task::Thread;
  2. use core::pin::pin;
  3. use eonix_sync::{UnlockableGuard, UnlockedGuard as _, WaitList};
  4. use intrusive_collections::UnsafeRef;
  5. pub struct CondVar<const INTERRUPTIBLE: bool> {
  6. wait_list: WaitList,
  7. }
  8. impl<const I: bool> core::fmt::Debug for CondVar<I> {
  9. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  10. if I {
  11. f.debug_struct("CondVar").finish()
  12. } else {
  13. f.debug_struct("CondVarUnintrruptible").finish()
  14. }
  15. }
  16. }
  17. impl<const I: bool> CondVar<I> {
  18. pub const fn new() -> Self {
  19. Self {
  20. wait_list: WaitList::new(),
  21. }
  22. }
  23. pub fn notify_all(&self) {
  24. self.wait_list.notify_all();
  25. }
  26. /// Unlock the `guard`. Then wait until being woken up.
  27. /// Return the relocked `guard`.
  28. pub async fn wait<G>(&self, guard: G) -> G
  29. where
  30. G: UnlockableGuard + Send,
  31. G::Unlocked: Send,
  32. {
  33. let mut wait_handle = pin!(self.wait_list.prepare_to_wait());
  34. wait_handle.as_mut().add_to_wait_list();
  35. let interrupt_waker = pin!(unsafe {
  36. // SAFETY: We won't use the waker after the wait_handle is dropped.
  37. wait_handle.as_ref().get_waker_function()
  38. });
  39. if I {
  40. // Prohibit the thread from being woken up by a signal.
  41. Thread::current().signal_list.set_signal_waker(Some(unsafe {
  42. UnsafeRef::from_raw(interrupt_waker.as_ref().get_ref())
  43. }));
  44. }
  45. let unlocked_guard = guard.unlock();
  46. wait_handle.await;
  47. if I {
  48. // Allow the thread to be woken up by a signal again.
  49. Thread::current().signal_list.set_signal_waker(None);
  50. }
  51. unlocked_guard.relock().await
  52. }
  53. }