/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Semaphore.Win32.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "Semaphore.Generic.hpp" #include "Semaphore.NT.hpp" #if !defined(_AURUNTIME_GENERIC_SEMAPHORE) namespace Aurora::Threading::Primitives { Semaphore::Semaphore(long intialValue) { value_ = intialValue; InitializeSRWLock(&lock_); InitializeConditionVariable(&winCond_); } Semaphore::~Semaphore() { } bool Semaphore::HasOSHandle(AuMach &mach) { return false; } bool Semaphore::HasLockImplementation() { return true; } bool Semaphore::TryLock() { auto old = value_; return (old != 0 && AuAtomicCompareExchange(&value_, old - 1, old) == old); } bool Semaphore::Lock(AuUInt64 timeout) { AuUInt64 start = AuTime::CurrentInternalClockMS(); AuUInt64 end = start + timeout; AcquireSRWLockShared(&lock_); // we use atomics. using shared is fine, let's not get congested early while (!TryLock()) { start = AuTime::CurrentInternalClockMS(); if (end <= start) { ReleaseSRWLockShared(&lock_); return false; } auto timeout = end - start; if (!::SleepConditionVariableSRW(&winCond_, &lock_, AuUInt32(timeout), CONDITION_VARIABLE_LOCKMODE_SHARED)) { ReleaseSRWLockShared(&lock_); return false; } } ReleaseSRWLockShared(&lock_); return true; } void Semaphore::Lock() { auto status = Lock(0); SysAssert(status, "Couldn't lock semaphore"); } void Semaphore::Unlock(long count) { AcquireSRWLockShared(&lock_); AuAtomicAdd(&value_, count); ::WakeAllConditionVariable(&winCond_); ReleaseSRWLockShared(&lock_); } void Semaphore::Unlock() { return Unlock(1); } AUKN_SYM ISemaphore *SemaphoreNew(int initialCount) { return _new Semaphore(initialCount); } AUKN_SYM void SemaphoreRelease(ISemaphore *waitable) { AuSafeDelete(waitable); } } #endif