WaitQueue.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Debug.h>
  7. #include <Kernel/Thread.h>
  8. #include <Kernel/WaitQueue.h>
  9. namespace Kernel {
  10. bool WaitQueue::should_add_blocker(Thread::Blocker& b, void*)
  11. {
  12. VERIFY(m_lock.is_locked());
  13. VERIFY(b.blocker_type() == Thread::Blocker::Type::Queue);
  14. if (m_wake_requested) {
  15. m_wake_requested = false;
  16. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: do not block thread {}", this, b.thread());
  17. return false;
  18. }
  19. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: should block thread {}", this, b.thread());
  20. return true;
  21. }
  22. u32 WaitQueue::wake_one()
  23. {
  24. u32 did_wake = 0;
  25. SpinlockLocker lock(m_lock);
  26. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_one", this);
  27. bool did_unblock_one = unblock_all_blockers_whose_conditions_are_met_locked([&](Thread::Blocker& b, void*, bool& stop_iterating) {
  28. VERIFY(b.blocker_type() == Thread::Blocker::Type::Queue);
  29. auto& blocker = static_cast<Thread::WaitQueueBlocker&>(b);
  30. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_one unblocking {}", this, blocker.thread());
  31. if (blocker.unblock()) {
  32. stop_iterating = true;
  33. did_wake = 1;
  34. return true;
  35. }
  36. return false;
  37. });
  38. m_wake_requested = !did_unblock_one;
  39. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_one woke {} threads", this, did_wake);
  40. return did_wake;
  41. }
  42. u32 WaitQueue::wake_n(u32 wake_count)
  43. {
  44. if (wake_count == 0)
  45. return 0; // should we assert instead?
  46. SpinlockLocker lock(m_lock);
  47. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_n({})", this, wake_count);
  48. u32 did_wake = 0;
  49. bool did_unblock_some = unblock_all_blockers_whose_conditions_are_met_locked([&](Thread::Blocker& b, void*, bool& stop_iterating) {
  50. VERIFY(b.blocker_type() == Thread::Blocker::Type::Queue);
  51. auto& blocker = static_cast<Thread::WaitQueueBlocker&>(b);
  52. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_n unblocking {}", this, blocker.thread());
  53. VERIFY(did_wake < wake_count);
  54. if (blocker.unblock()) {
  55. if (++did_wake >= wake_count)
  56. stop_iterating = true;
  57. return true;
  58. }
  59. return false;
  60. });
  61. m_wake_requested = !did_unblock_some;
  62. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_n({}) woke {} threads", this, wake_count, did_wake);
  63. return did_wake;
  64. }
  65. u32 WaitQueue::wake_all()
  66. {
  67. SpinlockLocker lock(m_lock);
  68. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_all", this);
  69. u32 did_wake = 0;
  70. bool did_unblock_any = unblock_all_blockers_whose_conditions_are_met_locked([&](Thread::Blocker& b, void*, bool&) {
  71. VERIFY(b.blocker_type() == Thread::Blocker::Type::Queue);
  72. auto& blocker = static_cast<Thread::WaitQueueBlocker&>(b);
  73. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_all unblocking {}", this, blocker.thread());
  74. if (blocker.unblock()) {
  75. did_wake++;
  76. return true;
  77. }
  78. return false;
  79. });
  80. m_wake_requested = !did_unblock_any;
  81. dbgln_if(WAITQUEUE_DEBUG, "WaitQueue @ {}: wake_all woke {} threads", this, did_wake);
  82. return did_wake;
  83. }
  84. }