[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:
@@ -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 ¤t = thread::current();
|
thread ¤t = thread::current();
|
||||||
m_queue.add_thread(¤t);
|
m_queue.add_thread(¤t);
|
||||||
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
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user