From 42dc78626a63fc1faf3589313dc80cc219bfcd2c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 27 Oct 2022 02:44:09 +0300 Subject: [PATCH] Changed how lock works (now it's assembly spinlock) --- Architecture/amd64/LockAssembly.S | 70 +++++++++++++++++++++++++++++++ Core/Lock.cpp | 11 +++++ include/lock.hpp | 62 +++++++++++++++++++-------- 3 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 Architecture/amd64/LockAssembly.S create mode 100644 Core/Lock.cpp diff --git a/Architecture/amd64/LockAssembly.S b/Architecture/amd64/LockAssembly.S new file mode 100644 index 0000000..c0bddb7 --- /dev/null +++ b/Architecture/amd64/LockAssembly.S @@ -0,0 +1,70 @@ +# https://en.wikipedia.org/wiki/Spinlock + +.text + +# void SpinLock_Lock(volatile uint64_t *LockData) +.global SpinLock_Lock + +# void SpinLock_Unlock(volatile uint64_t *LockData) +.global SpinLock_Unlock + +# uint64_t SpinLock_CheckAndLock(volatile uint64_t *LockData) +.global SpinLock_CheckAndLock + +# uint64_t SpinLock_WithTimeout(volatile uint64_t *LockData, volatile uint64_t Iterations) +.global SpinLock_WithTimeout + +# DeadLockHandler(volatile *LockStructure) +.extern DeadLockHandler + +SpinLock_Lock: + xorq %rax,%rax + lock btsl $0,(%rdi) + jc Spin + ret +Spin: + incq %rax + cmpq $0x10000000,%rax + je Deadlock + pause + testl $1,(%rdi) + jnz Spin + jmp SpinLock_Lock + +SpinLock_Unlock: + lock btrl $0,(%rdi) + ret + +Deadlock: + pushq %rdi + pushq %rdi + xorq %rax,%rax + call DeadLockHandler + popq %rdi + popq %rdi + jmp Spin + +SpinLock_CheckAndLock: + xorl %eax,%eax + lock btsl $0,(%rdi) + setcb %al + ret + +SpinLock_WithTimeout: + xorq %rax,%rax +SpinTimeout: + incq %rax + lock btsl $0,(%rdi) + setcb %bl + cmpb $0,%bl + je LockAquired + cmpq %rsi,%rax + je LockTimedOut + pause + jmp SpinTimeout +LockAquired: + movq $1,%rax + ret +LockTimedOut: + xorq %rax,%rax + ret diff --git a/Core/Lock.cpp b/Core/Lock.cpp new file mode 100644 index 0000000..461c0f4 --- /dev/null +++ b/Core/Lock.cpp @@ -0,0 +1,11 @@ +#include + +#include + +extern "C" void DeadLockHandler(LockClass *Lock) +{ + warn("Potential deadlock in lock '%s' held by '%s'", + Lock->GetLockData()->AttemptingToGet, + Lock->GetLockData()->CurrentHolder); + // TODO: Print on screen too. +} \ No newline at end of file diff --git a/include/lock.hpp b/include/lock.hpp index d76c6bf..c891eaa 100644 --- a/include/lock.hpp +++ b/include/lock.hpp @@ -1,34 +1,60 @@ #ifndef __FENNIX_KERNEL_LOCK_H__ #define __FENNIX_KERNEL_LOCK_H__ -/* -TODO: Add deadlock detection. -*/ - #include + +#include #include +#pragma GCC diagnostic ignored "-Wvolatile" + +EXTERNC void SpinLock_Lock(volatile uint64_t *LockData); +EXTERNC void SpinLock_Unlock(volatile uint64_t *LockData); +EXTERNC uint64_t SpinLock_CheckAndLock(volatile uint64_t *LockData); +EXTERNC uint64_t SpinLock_WithTimeout(volatile uint64_t *LockData, volatile uint64_t Iterations); + #ifdef __cplusplus /** @brief Please use this macro to create a new lock. */ class LockClass { + struct SpinLockData + { + uint64_t LockData; + const char *CurrentHolder; + const char *AttemptingToGet; + uint64_t Count; + }; + private: - bool IsLocked = false; + SpinLockData LockData; + // bool IsLocked = false; public: - int Lock() + SpinLockData *GetLockData() { return &LockData; } + + int Lock(const char *FunctionName = "Unknown") { - while (!__sync_bool_compare_and_swap(&IsLocked, false, true)) - CPU::Pause(); - __sync_synchronize(); + LockData.AttemptingToGet = FunctionName; + SpinLock_Lock(&LockData.LockData); + LockData.CurrentHolder = FunctionName; + LockData.Count++; + CPU::MemBar::Barrier(); + + // while (!__sync_bool_compare_and_swap(&IsLocked, false, true)) + // CPU::Pause(); + // __sync_synchronize(); return 0; } int Unlock() { - __sync_synchronize(); - __atomic_store_n(&IsLocked, false, __ATOMIC_SEQ_CST); - IsLocked = false; + SpinLock_Unlock(&LockData.LockData); + LockData.Count--; + CPU::MemBar::Barrier(); + + // __sync_synchronize(); + // __atomic_store_n(&IsLocked, false, __ATOMIC_SEQ_CST); + // IsLocked = false; return 0; } }; @@ -39,10 +65,10 @@ private: LockClass *LockPointer = nullptr; public: - SmartLockClass(LockClass &Lock) + SmartLockClass(LockClass &Lock, const char *FunctionName) { this->LockPointer = &Lock; - this->LockPointer->Lock(); + this->LockPointer->Lock(FunctionName); } ~SmartLockClass() { this->LockPointer->Unlock(); } }; @@ -54,13 +80,13 @@ private: bool InterruptsEnabled = false; public: - SmartCriticalSectionClass(LockClass &Lock) + SmartCriticalSectionClass(LockClass &Lock, const char *FunctionName) { if (CPU::Interrupts(CPU::Check)) InterruptsEnabled = true; CPU::Interrupts(CPU::Disable); this->LockPointer = &Lock; - this->LockPointer->Lock(); + this->LockPointer->Lock(FunctionName); } ~SmartCriticalSectionClass() { @@ -73,9 +99,9 @@ public: /** @brief Create a new lock (can be used with SmartCriticalSection). */ #define NewLock(Name) LockClass Name /** @brief Simple lock that is automatically released when the scope ends. */ -#define SmartLock(LockClassName) SmartLockClass CONCAT(lock##_, __COUNTER__)(LockClassName) +#define SmartLock(LockClassName) SmartLockClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__) /** @brief Simple critical section that is automatically released when the scope ends and interrupts are restored if they were enabled. */ -#define SmartCriticalSection(LockClassName) SmartCriticalSectionClass CONCAT(lock##_, __COUNTER__)(LockClassName) +#define SmartCriticalSection(LockClassName) SmartCriticalSectionClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__) #endif // __cplusplus #endif // !__FENNIX_KERNEL_LOCK_H__