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