[kernel] Simplify event and wait_queue

Previously event tried to read its value in event::wake_observer, which
required jumping through some hoops in how wait_queue was designed, so
that a value wouldn't be wasted if the wait_queue was empty. Now, read
the event value in event::wait after returning from the thread::block
call instead, which simplifies the whole process and lets us simplify
the wait_queue API as well.
This commit is contained in:
Justin C. Miller
2023-02-19 14:34:03 -08:00
parent 94b2a79f79
commit 274891854f
3 changed files with 15 additions and 45 deletions

View File

@@ -28,22 +28,15 @@ event::wait()
// Wait for event::signal() to wake us with a value // Wait for event::signal() to wake us with a value
thread &current = thread::current(); thread &current = thread::current();
m_queue.add_thread(&current); m_queue.add_thread(&current);
return current.block(); current.block();
return read();
} }
void void
event::wake_observer() event::wake_observer()
{ {
util::scoped_lock lock {m_queue.get_lock()}; thread *t = m_queue.pop_next();
thread *t = m_queue.get_next_unlocked(); if (t) t->wake();
if (!t) return;
uint64_t value = read();
if (value) {
m_queue.pop_next_unlocked();
lock.release();
t->wake(value);
}
} }
} // namespace obj } // namespace obj

View File

@@ -38,31 +38,24 @@ wait_queue::pop_exited()
} }
obj::thread * obj::thread *
wait_queue::get_next_unlocked() wait_queue::pop_next()
{ {
pop_exited(); pop_exited();
if (m_threads.empty()) if (m_threads.empty())
return nullptr; return nullptr;
return m_threads.first();
}
obj::thread * obj::thread *t = m_threads.pop_front();
wait_queue::pop_next_unlocked() kassert(t, "Null thread in wait_queue");
{ t->handle_release();
pop_exited(); return t;
if (m_threads.empty())
return nullptr;
return m_threads.pop_front();
} }
void void
wait_queue::clear(uint64_t value) wait_queue::clear(uint64_t value)
{ {
util::scoped_lock lock {m_lock}; obj::thread *t = pop_next();
while (!m_threads.empty()) { while (t) {
obj::thread *t = pop_next_unlocked(); t->wake(value);
kassert(t, "Null thread in the wait queue"); t = pop_next();
if (!t->exited()) t->wake(value);
t->handle_release();
} }
} }

View File

@@ -15,30 +15,14 @@ public:
/// Wake all threads when destructing /// Wake all threads when destructing
~wait_queue(); ~wait_queue();
/// Add the given thread to the queue. Locks the /// Add the given thread to the queue.
/// queue lock.
void add_thread(obj::thread *t); void add_thread(obj::thread *t);
/// Block the current thread on the queue. /// Block the current thread on the queue.
void wait(); void wait();
/// Pops the next waiting thread off the queue. /// Pops the next waiting thread off the queue.
/// Locks the queue lock. obj::thread * pop_next();
inline obj::thread * pop_next() {
util::scoped_lock lock {m_lock};
return pop_next_unlocked();
}
/// Get the next waiting thread. Does not lock the
/// queue lock.
obj::thread * get_next_unlocked();
/// Pop the next thread off the queue. Does not
/// lock the queue lock.
obj::thread * pop_next_unlocked();
/// Get the spinlock to lock this queue
util::spinlock & get_lock() { return m_lock; }
/// Wake and clear out all threads. /// Wake and clear out all threads.
/// \arg value The value passed to thread::wake /// \arg value The value passed to thread::wake