1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-10 06:17:35 +00:00

Kernel: Move Blocker setup out from constructors into setup_blocker()

Instead of registering with blocker sets and whatnot in the various
Blocker subclass constructors, this patch moves such initialization
to a separate setup_blocker() virtual.

setup_blocker() returns false if there's no need to actually block
the thread. This allows us to bail earlier in Thread::block().
This commit is contained in:
Andreas Kling 2021-08-24 12:14:14 +02:00
parent c108c8ff24
commit 82c3cc4640
5 changed files with 92 additions and 39 deletions

View file

@ -425,6 +425,11 @@ bool Plan9FS::Blocker::unblock(u16 tag)
return unblock(); return unblock();
} }
bool Plan9FS::Blocker::setup_blocker()
{
return add_to_blocker_set(m_fs.m_completion_blocker);
}
void Plan9FS::Blocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason) void Plan9FS::Blocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason)
{ {
{ {

View file

@ -87,8 +87,8 @@ private:
, m_message(message) , m_message(message)
, m_completion(move(completion)) , m_completion(move(completion))
{ {
add_to_blocker_set(fs.m_completion_blocker);
} }
virtual bool setup_blocker() override;
virtual StringView state_string() const override { return "Waiting"sv; } virtual StringView state_string() const override { return "Waiting"sv; }
virtual Type blocker_type() const override { return Type::Plan9FS; } virtual Type blocker_type() const override { return Type::Plan9FS; }
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;

View file

@ -25,6 +25,7 @@ public:
virtual StringView state_string() const override { return "Routing (ARP)"sv; } virtual StringView state_string() const override { return "Routing (ARP)"sv; }
virtual Type blocker_type() const override { return Type::Routing; } virtual Type blocker_type() const override { return Type::Routing; }
virtual bool should_block() override { return m_should_block; } virtual bool should_block() override { return m_should_block; }
virtual bool setup_blocker() override;
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;
@ -85,9 +86,14 @@ static Singleton<ARPTableBlockerSet> s_arp_table_blocker_set;
ARPTableBlocker::ARPTableBlocker(IPv4Address ip_addr, Optional<MACAddress>& addr) ARPTableBlocker::ARPTableBlocker(IPv4Address ip_addr, Optional<MACAddress>& addr)
: m_ip_addr(ip_addr) : m_ip_addr(ip_addr)
, m_addr(addr) , m_addr(addr)
{
}
bool ARPTableBlocker::setup_blocker()
{ {
if (!add_to_blocker_set(*s_arp_table_blocker_set)) if (!add_to_blocker_set(*s_arp_table_blocker_set))
m_should_block = false; m_should_block = false;
return m_should_block;
} }
void ARPTableBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason) void ARPTableBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)

View file

@ -300,6 +300,7 @@ public:
virtual Type blocker_type() const = 0; virtual Type blocker_type() const = 0;
virtual const BlockTimeout& override_timeout(const BlockTimeout& timeout) { return timeout; } virtual const BlockTimeout& override_timeout(const BlockTimeout& timeout) { return timeout; }
virtual bool can_be_interrupted() const { return true; } virtual bool can_be_interrupted() const { return true; }
virtual bool setup_blocker();
Thread& thread() { return m_thread; } Thread& thread() { return m_thread; }
@ -523,11 +524,14 @@ public:
virtual bool should_block() override { return !m_join_error && m_should_block; } virtual bool should_block() override { return !m_join_error && m_should_block; }
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;
virtual bool setup_blocker() override;
bool unblock(void*, bool); bool unblock(void*, bool);
private: private:
NonnullRefPtr<Thread> m_joinee; NonnullRefPtr<Thread> m_joinee;
void*& m_joinee_exit_value; void*& m_joinee_exit_value;
KResult& m_try_join_result;
bool m_join_error { false }; bool m_join_error { false };
bool m_did_unblock { false }; bool m_did_unblock { false };
bool m_should_block { true }; bool m_should_block { true };
@ -541,15 +545,13 @@ public:
virtual Type blocker_type() const override { return Type::Queue; } virtual Type blocker_type() const override { return Type::Queue; }
virtual StringView state_string() const override { return m_block_reason.is_null() ? m_block_reason : "Queue"sv; } virtual StringView state_string() const override { return m_block_reason.is_null() ? m_block_reason : "Queue"sv; }
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override { } virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override { }
virtual bool should_block() override { return m_should_block; }
virtual bool should_block() override virtual bool setup_blocker() override;
{
return m_should_block;
}
bool unblock(); bool unblock();
protected: protected:
WaitQueue& m_wait_queue;
StringView m_block_reason; StringView m_block_reason;
bool m_should_block { true }; bool m_should_block { true };
bool m_did_unblock { false }; bool m_did_unblock { false };
@ -563,11 +565,8 @@ public:
virtual Type blocker_type() const override { return Type::Futex; } virtual Type blocker_type() const override { return Type::Futex; }
virtual StringView state_string() const override { return "Futex"sv; } virtual StringView state_string() const override { return "Futex"sv; }
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override { } virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override { }
virtual bool should_block() override { return m_should_block; }
virtual bool should_block() override virtual bool setup_blocker() override;
{
return m_should_block;
}
u32 bitset() const { return m_bitset; } u32 bitset() const { return m_bitset; }
@ -582,7 +581,8 @@ public:
bool unblock(bool force = false); bool unblock(bool force = false);
protected: protected:
u32 m_bitset; FutexQueue& m_futex_queue;
u32 m_bitset { 0 };
u32 m_relock_flags { 0 }; u32 m_relock_flags { 0 };
bool m_should_block { true }; bool m_should_block { true };
bool m_did_unblock { false }; bool m_did_unblock { false };
@ -627,6 +627,7 @@ public:
virtual bool unblock(bool, void*) override; virtual bool unblock(bool, void*) override;
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;
virtual bool setup_blocker() override;
protected: protected:
explicit FileDescriptionBlocker(FileDescription&, BlockFlags, BlockFlags&); explicit FileDescriptionBlocker(FileDescription&, BlockFlags, BlockFlags&);
@ -696,13 +697,14 @@ public:
}; };
typedef Vector<FDInfo, FD_SETSIZE> FDVector; typedef Vector<FDInfo, FD_SETSIZE> FDVector;
explicit SelectBlocker(FDVector& fds); explicit SelectBlocker(FDVector&);
virtual ~SelectBlocker(); virtual ~SelectBlocker();
virtual bool unblock(bool, void*) override; virtual bool unblock(bool, void*) override;
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;
virtual void was_unblocked(bool) override; virtual void was_unblocked(bool) override;
virtual StringView state_string() const override { return "Selecting"sv; } virtual StringView state_string() const override { return "Selecting"sv; }
virtual bool setup_blocker() override;
private: private:
size_t collect_unblocked_flags(); size_t collect_unblocked_flags();
@ -726,6 +728,7 @@ public:
virtual bool should_block() override { return m_should_block; } virtual bool should_block() override { return m_should_block; }
virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override; virtual void will_unblock_immediately_without_blocking(UnblockImmediatelyReason) override;
virtual void was_unblocked(bool) override; virtual void was_unblocked(bool) override;
virtual bool setup_blocker() override;
bool unblock(Process& process, UnblockFlags flags, u8 signal, bool from_add_blocker); bool unblock(Process& process, UnblockFlags flags, u8 signal, bool from_add_blocker);
bool is_wait() const { return !(m_wait_options & WNOWAIT); } bool is_wait() const { return !(m_wait_options & WNOWAIT); }
@ -867,6 +870,12 @@ public:
m_in_block = true; m_in_block = true;
BlockerType blocker(forward<Args>(args)...); BlockerType blocker(forward<Args>(args)...);
if (!blocker.setup_blocker()) {
blocker.will_unblock_immediately_without_blocking(Blocker::UnblockImmediatelyReason::UnblockConditionAlreadyMet);
m_in_block = false;
return BlockResult::NotBlocked;
}
SpinlockLocker scheduler_lock(g_scheduler_lock); SpinlockLocker scheduler_lock(g_scheduler_lock);
// Relaxed semantics are fine for timeout_unblocked because we // Relaxed semantics are fine for timeout_unblocked because we
// synchronize on the spin locks already. // synchronize on the spin locks already.
@ -885,13 +894,6 @@ public:
} }
m_blocker = &blocker; m_blocker = &blocker;
if (!blocker.should_block()) {
// Don't block if the wake condition is already met
blocker.will_unblock_immediately_without_blocking(Blocker::UnblockImmediatelyReason::UnblockConditionAlreadyMet);
m_blocker = nullptr;
m_in_block = false;
return BlockResult::NotBlocked;
}
auto& block_timeout = blocker.override_timeout(timeout); auto& block_timeout = blocker.override_timeout(timeout);
if (!block_timeout.is_infinite()) { if (!block_timeout.is_infinite()) {

View file

@ -45,6 +45,11 @@ Thread::Blocker::~Blocker()
m_blocker_set->remove_blocker(*this); m_blocker_set->remove_blocker(*this);
} }
bool Thread::Blocker::setup_blocker()
{
return true;
}
void Thread::Blocker::begin_blocking(Badge<Thread>) void Thread::Blocker::begin_blocking(Badge<Thread>)
{ {
SpinlockLocker lock(m_lock); SpinlockLocker lock(m_lock);
@ -68,19 +73,23 @@ auto Thread::Blocker::end_blocking(Badge<Thread>, bool did_timeout) -> BlockResu
Thread::JoinBlocker::JoinBlocker(Thread& joinee, KResult& try_join_result, void*& joinee_exit_value) Thread::JoinBlocker::JoinBlocker(Thread& joinee, KResult& try_join_result, void*& joinee_exit_value)
: m_joinee(joinee) : m_joinee(joinee)
, m_joinee_exit_value(joinee_exit_value) , m_joinee_exit_value(joinee_exit_value)
, m_try_join_result(try_join_result)
{ {
{ }
// We need to hold our lock to avoid a race where try_join succeeds
// but the joinee is joining immediately bool Thread::JoinBlocker::setup_blocker()
SpinlockLocker lock(m_lock); {
try_join_result = joinee.try_join([&]() { // We need to hold our lock to avoid a race where try_join succeeds
if (!add_to_blocker_set(joinee.m_join_blocker_set)) // but the joinee is joining immediately
m_should_block = false; SpinlockLocker lock(m_lock);
}); m_try_join_result = m_joinee->try_join([&]() {
m_join_error = try_join_result.is_error(); if (!add_to_blocker_set(m_joinee->m_join_blocker_set))
if (m_join_error)
m_should_block = false; m_should_block = false;
} });
m_join_error = m_try_join_result.is_error();
if (m_join_error)
m_should_block = false;
return m_should_block;
} }
void Thread::JoinBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason) void Thread::JoinBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
@ -114,10 +123,16 @@ bool Thread::JoinBlocker::unblock(void* value, bool from_add_blocker)
} }
Thread::WaitQueueBlocker::WaitQueueBlocker(WaitQueue& wait_queue, StringView block_reason) Thread::WaitQueueBlocker::WaitQueueBlocker(WaitQueue& wait_queue, StringView block_reason)
: m_block_reason(block_reason) : m_wait_queue(wait_queue)
, m_block_reason(block_reason)
{ {
if (!add_to_blocker_set(wait_queue)) }
bool Thread::WaitQueueBlocker::setup_blocker()
{
if (!add_to_blocker_set(m_wait_queue))
m_should_block = false; m_should_block = false;
return m_should_block;
} }
Thread::WaitQueueBlocker::~WaitQueueBlocker() Thread::WaitQueueBlocker::~WaitQueueBlocker()
@ -138,10 +153,16 @@ bool Thread::WaitQueueBlocker::unblock()
} }
Thread::FutexBlocker::FutexBlocker(FutexQueue& futex_queue, u32 bitset) Thread::FutexBlocker::FutexBlocker(FutexQueue& futex_queue, u32 bitset)
: m_bitset(bitset) : m_futex_queue(futex_queue)
, m_bitset(bitset)
{ {
if (!add_to_blocker_set(futex_queue)) }
bool Thread::FutexBlocker::setup_blocker()
{
if (!add_to_blocker_set(m_futex_queue))
m_should_block = false; m_should_block = false;
return m_should_block;
} }
Thread::FutexBlocker::~FutexBlocker() Thread::FutexBlocker::~FutexBlocker()
@ -187,10 +208,15 @@ Thread::FileDescriptionBlocker::FileDescriptionBlocker(FileDescription& descript
: m_blocked_description(description) : m_blocked_description(description)
, m_flags(flags) , m_flags(flags)
, m_unblocked_flags(unblocked_flags) , m_unblocked_flags(unblocked_flags)
{
}
bool Thread::FileDescriptionBlocker::setup_blocker()
{ {
m_unblocked_flags = BlockFlags::None; m_unblocked_flags = BlockFlags::None;
if (!add_to_blocker_set(description.blocker_set())) if (!add_to_blocker_set(m_blocked_description->blocker_set()))
m_should_block = false; m_should_block = false;
return m_should_block;
} }
bool Thread::FileDescriptionBlocker::unblock(bool from_add_blocker, void*) bool Thread::FileDescriptionBlocker::unblock(bool from_add_blocker, void*)
@ -337,6 +363,10 @@ Thread::BlockResult Thread::SleepBlocker::block_result()
Thread::SelectBlocker::SelectBlocker(FDVector& fds) Thread::SelectBlocker::SelectBlocker(FDVector& fds)
: m_fds(fds) : m_fds(fds)
{
}
bool Thread::SelectBlocker::setup_blocker()
{ {
for (auto& fd_entry : m_fds) { for (auto& fd_entry : m_fds) {
fd_entry.unblocked_flags = FileBlocker::BlockFlags::None; fd_entry.unblocked_flags = FileBlocker::BlockFlags::None;
@ -346,6 +376,7 @@ Thread::SelectBlocker::SelectBlocker(FDVector& fds)
if (!fd_entry.description->blocker_set().add_blocker(*this, &fd_entry)) if (!fd_entry.description->blocker_set().add_blocker(*this, &fd_entry))
m_should_block = false; m_should_block = false;
} }
return m_should_block;
} }
Thread::SelectBlocker::~SelectBlocker() Thread::SelectBlocker::~SelectBlocker()
@ -590,7 +621,11 @@ Thread::WaitBlocker::WaitBlocker(int wait_options, idtype_t id_type, pid_t id, K
, m_result(result) , m_result(result)
, m_should_block(!(m_wait_options & WNOHANG)) , m_should_block(!(m_wait_options & WNOHANG))
{ {
switch (id_type) { }
bool Thread::WaitBlocker::setup_blocker()
{
switch (m_id_type) {
case P_PID: { case P_PID: {
m_waitee = Process::from_pid(m_waitee_id); m_waitee = Process::from_pid(m_waitee_id);
if (!m_waitee || m_waitee->ppid() != Process::current().pid()) { if (!m_waitee || m_waitee->ppid() != Process::current().pid()) {
@ -613,11 +648,16 @@ Thread::WaitBlocker::WaitBlocker(int wait_options, idtype_t id_type, pid_t id, K
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
if (m_error)
return false;
if (m_wait_options & WNOHANG)
return false;
// NOTE: unblock may be called within add_to_blocker_set, in which // NOTE: unblock may be called within add_to_blocker_set, in which
// case it means that we already have a match without having to block. // case it means that we already have a match without having to block.
// In that case add_to_blocker_set will return false. // In that case add_to_blocker_set will return false.
if (m_error || !add_to_blocker_set(Process::current().wait_blocker_set())) return add_to_blocker_set(Process::current().wait_blocker_set());
m_should_block = false;
} }
void Thread::WaitBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason) void Thread::WaitBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)