1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:18:12 +00:00

Kernel: Fix Lock race causing infinite spinning between two threads

We need to account for how many shared lock instances the current
thread owns, so that we can properly release such references when
yielding execution.

We also need to release the process lock when donating.
This commit is contained in:
Tom 2020-12-14 16:36:22 -07:00 committed by Andreas Kling
parent 56701f91f9
commit c4176b0da1
10 changed files with 359 additions and 96 deletions

View file

@ -28,44 +28,60 @@
#include <AK/Assertions.h>
#include <AK/Atomic.h>
#include <AK/HashMap.h>
#include <AK/Types.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Forward.h>
#include <Kernel/Thread.h>
#include <Kernel/LockMode.h>
#include <Kernel/WaitQueue.h>
namespace Kernel {
class Lock {
AK_MAKE_NONCOPYABLE(Lock);
AK_MAKE_NONMOVABLE(Lock);
public:
using Mode = LockMode;
Lock(const char* name = nullptr)
: m_name(name)
{
}
~Lock() { }
enum class Mode {
Unlocked,
Shared,
Exclusive
};
void lock(Mode = Mode::Exclusive);
#ifdef LOCK_DEBUG
void lock(const char* file, int line, Mode mode = Mode::Exclusive);
void restore_lock(const char* file, int line, Mode, u32);
#endif
void unlock();
bool force_unlock_if_locked();
bool is_locked() const { return m_holder; }
[[nodiscard]] Mode force_unlock_if_locked(u32&);
void restore_lock(Mode, u32);
bool is_locked() const { return m_mode.load(AK::MemoryOrder::memory_order_relaxed) != Mode::Unlocked; }
void clear_waiters();
const char* name() const { return m_name; }
static const char* mode_to_string(Mode mode)
{
switch (mode) {
case Mode::Unlocked:
return "unlocked";
case Mode::Exclusive:
return "exclusive";
case Mode::Shared:
return "shared";
default:
return "invalid";
}
}
private:
Atomic<bool> m_lock { false };
const char* m_name { nullptr };
WaitQueue m_queue;
Mode m_mode { Mode::Unlocked };
Atomic<Mode> m_mode { Mode::Unlocked };
// When locked exclusively, only the thread already holding the lock can
// lock it again. When locked in shared mode, any thread can do that.
@ -77,6 +93,7 @@ private:
// When locked exclusively, this is always the one thread that holds the
// lock.
RefPtr<Thread> m_holder;
HashMap<Thread*, u32> m_shared_holders;
};
class Locker {
@ -103,8 +120,10 @@ private:
#ifdef LOCK_DEBUG
# define LOCKER(...) Locker locker(__FILE__, __LINE__, __VA_ARGS__)
# define RESTORE_LOCK(lock, ...) (lock).restore_lock(__FILE__, __LINE__, __VA_ARGS__)
#else
# define LOCKER(...) Locker locker(__VA_ARGS__)
# define RESTORE_LOCK(lock, ...) (lock).restore_lock(__VA_ARGS__)
#endif
template<typename T>