diff --git a/core/lock.cpp b/core/lock.cpp index 247afd88..647c1e20 100644 --- a/core/lock.cpp +++ b/core/lock.cpp @@ -96,8 +96,7 @@ size_t GetLocksCount() { return LocksCount.load(); } void LockClass::Yield() { - if (CPU::Interrupts(CPU::Check) && - TaskManager && + if (CPU::Interrupts(CPU::Check) && TaskManager && !TaskManager->IsPanic()) { TaskManager->Yield(); @@ -123,10 +122,8 @@ void LockClass::DeadLock(SpinLockData &Lock) CCore = CoreData->ID; warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. (%ld times happened)", - Lock.AttemptingToGet, Lock.CurrentHolder, - Lock.Count, Lock.Count > 1 ? "locks" : "lock", - CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", - CCore, Lock.Core, this->DeadLocks); + Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock", + CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", CCore, Lock.Core, this->DeadLocks); #ifdef PRINT_BACKTRACE PrintStacktrace(&Lock); @@ -201,10 +198,8 @@ void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout) uint64_t Counter = TimeManager->GetCounter(); warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).", - Lock.AttemptingToGet, Lock.CurrentHolder, - Lock.Count, Lock.Count > 1 ? "locks" : "lock", - CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", - CCore, Lock.Core, Timeout, Timeout - Counter); + Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock", + CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", CCore, Lock.Core, Timeout, Timeout - Counter); #ifdef PRINT_BACKTRACE PrintStacktrace(&Lock); diff --git a/include/lock.hpp b/include/lock.hpp index 6170669d..a60be962 100644 --- a/include/lock.hpp +++ b/include/lock.hpp @@ -68,6 +68,32 @@ public: int TimeoutLock(const char *FunctionName, uint64_t Timeout); }; +class spin_lock +{ +private: + LockClass lc; + +public: + bool locked() + { + return this->lc.Locked(); + } + + bool lock(const char *FunctionName) + { + return this->lc.Lock(FunctionName) == 0; + } + + bool unlock() + { + return this->lc.Unlock() == 0; + } + + spin_lock() = default; + spin_lock(const spin_lock &) = delete; + ~spin_lock() = default; +}; + /** @brief Please use this macro to create a new smart lock. */ class SmartLockClass { @@ -106,6 +132,7 @@ public: this->LockPointer = &Lock; this->LockPointer->TimeoutLock(FunctionName, Timeout); } + ~SmartTimeoutLockClass() { this->LockPointer->Unlock(); @@ -128,6 +155,7 @@ public: this->LockPointer = &Lock; this->LockPointer->Lock(FunctionName); } + ~SmartLockCriticalSectionClass() { this->LockPointer->Unlock(); @@ -153,6 +181,7 @@ public: InterruptsEnabled = true; CPU::Interrupts(CPU::Disable); } + ~SmartCriticalSectionClass() { if (InterruptsEnabled) diff --git a/include_std/mutex b/include_std/mutex index 675412b2..ee977f1e 100644 --- a/include_std/mutex +++ b/include_std/mutex @@ -25,6 +25,21 @@ namespace std { + + struct defer_lock_t + { + explicit defer_lock_t() = default; + }; + + struct try_to_lock_t + { + explicit try_to_lock_t() = default; + }; + struct adopt_lock_t + { + explicit adopt_lock_t() = default; + }; + /** * A mutex implementation. * @@ -35,7 +50,7 @@ namespace std { private: atomic_bool Locked = false; - vector Waiting; + list Waiting; Tasking::TCB *Holder = nullptr; public: @@ -43,24 +58,37 @@ namespace std bool try_lock(); void unlock(); - mutex() = default; + mutex(); mutex(const mutex &) = delete; - ~mutex() = default; + ~mutex(); }; template class lock_guard { private: - Mutex &m; + Mutex &mutexRef; public: - explicit lock_guard(Mutex &mutex) - : m(mutex) { m.lock(); } + explicit lock_guard(Mutex &m) + : mutexRef(m) + { + mutexRef.lock(); + } - ~lock_guard() { m.unlock(); } + lock_guard(Mutex &m, adopt_lock_t t) + : mutexRef(m) + { + /* Do nothing */ + } lock_guard(const lock_guard &) = delete; + + ~lock_guard() + { + mutexRef.unlock(); + } + lock_guard &operator=(const lock_guard &) = delete; }; } diff --git a/library/std/mutex.cpp b/library/std/mutex.cpp index 1baff3b8..7b2f6a8f 100644 --- a/library/std/mutex.cpp +++ b/library/std/mutex.cpp @@ -29,53 +29,80 @@ namespace std { void mutex::lock() { + RetryLock: bool Result = this->Locked.exchange(true, std::memory_order_acquire); - __sync; - if (Result) + TCB *tcb = thisThread; + if (Result == true) { - this->Waiting.push_back(thisThread); - thisThread->Block(); + debug("%#lx: Mutex is locked, blocking task %d (\"%s\" : %d)", this, + tcb->ID, tcb->Parent->Name, tcb->Parent->ID); + + this->Waiting.push_back(tcb); + tcb->Block(); TaskManager->Yield(); - return; + goto RetryLock; } - this->Holder = thisThread; - this->Waiting.erase(std::find(this->Waiting.begin(), - this->Waiting.end(), - thisThread)); + this->Holder = tcb; + this->Waiting.remove(tcb); + + debug("%#lx: Mutex locked by task %d (\"%s\" : %d)", this, + tcb->ID, tcb->Parent->Name, tcb->Parent->ID); } bool mutex::try_lock() { bool Result = this->Locked.exchange(true, std::memory_order_acquire); - __sync; - if (!Result) + TCB *tcb = thisThread; + if (Result == true) { - this->Holder = thisThread; - this->Waiting.erase(std::find(this->Waiting.begin(), - this->Waiting.end(), - thisThread)); + debug("%#lx: Mutex is locked, task %d (\"%s\" : %d) failed to lock", this, + tcb->ID, tcb->Parent->Name, tcb->Parent->ID); + return false; } - return !Result; + + this->Holder = tcb; + this->Waiting.remove(tcb); + + debug("%#lx: Mutex locked by task %d (\"%s\" : %d)", this, + tcb->ID, tcb->Parent->Name, tcb->Parent->ID); + return true; } void mutex::unlock() { - __sync; + TCB *tcb = thisThread; + assert(this->Holder == tcb); + + this->Holder = nullptr; this->Locked.store(false, std::memory_order_release); - if (!this->Waiting.empty()) + if (this->Waiting.empty()) { - this->Holder = this->Waiting[0]; - - this->Holder = this->Waiting.front(); - this->Waiting.erase(this->Waiting.begin()); - this->Holder->Unblock(); - TaskManager->Yield(); + debug("%#lx: Mutex unlocked, no tasks to unblock", this); + return; } - else - this->Holder = nullptr; + + TCB *Next = this->Waiting.front(); + this->Waiting.pop_front(); + + debug("%#lx: Mutex unlocked, task %d (\"%s\" : %d) unblocked", this, + Next->ID, Next->Parent->Name, Next->Parent->ID); + + Next->Unblock(); + } + + mutex::mutex() + { + debug("%#lx: Creating mutex", this); + } + + mutex::~mutex() + { + debug("%#lx: Destroying mutex", this); + assert(this->Holder == nullptr); + assert(this->Waiting.empty()); } }