Kernel: Fix most of mutex + block race conditions
All block functions now take an optional mutex parameter that is atomically unlocked instead of having the user unlock it before hand. This prevents a ton of race conditions everywhere in the code!
This commit is contained in:
@@ -29,30 +29,4 @@ namespace Kernel
|
||||
Lock& m_lock;
|
||||
};
|
||||
|
||||
template<typename Lock>
|
||||
class LockFreeGuard
|
||||
{
|
||||
BAN_NON_COPYABLE(LockFreeGuard);
|
||||
BAN_NON_MOVABLE(LockFreeGuard);
|
||||
|
||||
public:
|
||||
LockFreeGuard(Lock& lock)
|
||||
: m_lock(lock)
|
||||
, m_depth(lock.lock_depth())
|
||||
{
|
||||
for (uint32_t i = 0; i < m_depth; i++)
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
~LockFreeGuard()
|
||||
{
|
||||
for (uint32_t i = 0; i < m_depth; i++)
|
||||
m_lock.lock();
|
||||
}
|
||||
|
||||
private:
|
||||
Lock& m_lock;
|
||||
const uint32_t m_depth;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,19 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Mutex
|
||||
class BaseMutex
|
||||
{
|
||||
public:
|
||||
virtual void lock() = 0;
|
||||
virtual bool try_lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
|
||||
virtual pid_t locker() const = 0;
|
||||
virtual bool is_locked() const = 0;
|
||||
virtual uint32_t lock_depth() const = 0;
|
||||
};
|
||||
|
||||
class Mutex : public BaseMutex
|
||||
{
|
||||
BAN_NON_COPYABLE(Mutex);
|
||||
BAN_NON_MOVABLE(Mutex);
|
||||
@@ -17,9 +29,10 @@ namespace Kernel
|
||||
public:
|
||||
Mutex() = default;
|
||||
|
||||
void lock()
|
||||
void lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
@@ -37,9 +50,10 @@ namespace Kernel
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
bool try_lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
@@ -55,7 +69,7 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
void unlock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
@@ -68,16 +82,16 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
pid_t locker() const { return m_locker; }
|
||||
bool is_locked() const { return m_locker != -1; }
|
||||
uint32_t lock_depth() const { return m_lock_depth; }
|
||||
pid_t locker() const override { return m_locker; }
|
||||
bool is_locked() const override { return m_locker != -1; }
|
||||
uint32_t lock_depth() const override { return m_lock_depth; }
|
||||
|
||||
private:
|
||||
BAN::Atomic<pid_t> m_locker { -1 };
|
||||
uint32_t m_lock_depth { 0 };
|
||||
};
|
||||
|
||||
class PriorityMutex
|
||||
class PriorityMutex : public BaseMutex
|
||||
{
|
||||
BAN_NON_COPYABLE(PriorityMutex);
|
||||
BAN_NON_MOVABLE(PriorityMutex);
|
||||
@@ -85,7 +99,7 @@ namespace Kernel
|
||||
public:
|
||||
PriorityMutex() = default;
|
||||
|
||||
void lock()
|
||||
void lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
@@ -110,7 +124,7 @@ namespace Kernel
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
bool try_lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
@@ -133,7 +147,7 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
void unlock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
@@ -149,9 +163,9 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
pid_t locker() const { return m_locker; }
|
||||
bool is_locked() const { return m_locker != -1; }
|
||||
uint32_t lock_depth() const { return m_lock_depth; }
|
||||
pid_t locker() const override { return m_locker; }
|
||||
bool is_locked() const override { return m_locker != -1; }
|
||||
uint32_t lock_depth() const override { return m_lock_depth; }
|
||||
|
||||
private:
|
||||
BAN::Atomic<pid_t> m_locker { -1 };
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Kernel
|
||||
|
||||
void unlock(InterruptState state);
|
||||
|
||||
uint32_t lock_depth() const { return current_processor_has_lock(); }
|
||||
|
||||
bool current_processor_has_lock() const
|
||||
{
|
||||
return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32();
|
||||
@@ -72,6 +74,8 @@ namespace Kernel
|
||||
Processor::set_interrupt_state(state);
|
||||
}
|
||||
|
||||
uint32_t lock_depth() const { return m_lock_depth; }
|
||||
|
||||
bool current_processor_has_lock() const
|
||||
{
|
||||
return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32();
|
||||
@@ -82,6 +86,9 @@ namespace Kernel
|
||||
uint32_t m_lock_depth { 0 };
|
||||
};
|
||||
|
||||
template<typename Lock>
|
||||
class SpinLockGuardAsMutex;
|
||||
|
||||
template<typename Lock>
|
||||
class SpinLockGuard
|
||||
{
|
||||
@@ -103,6 +110,7 @@ namespace Kernel
|
||||
private:
|
||||
Lock& m_lock;
|
||||
InterruptState m_state;
|
||||
friend class SpinLockGuardAsMutex<Lock>;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user