/*** Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ConditionVariable.Win32.hpp Date: 2021-6-12 Author: Reece ***/ #pragma once #include "AuConditionVariable.Generic.hpp" #if !defined(_AURUNTIME_GENERICCV) #include "AuConditionMutex.NT.hpp" namespace Aurora::Threading::Primitives { struct ConditionVariableNT final { ConditionVariableNT(); bool WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 timeout, bool bSpin = true); void Signal(); void Broadcast(); void BroadcastN(AuUInt32 nBroadcast); auline void AddWaiter(); auline bool CheckOut(); auline bool CheckOutNoSpin(); private: #if defined(AURORA_FORCE_SRW_LOCKS) CONDITION_VARIABLE winCond_; #else AuAUInt32 wlist {}; AuAUInt32 signalCount {}; #endif }; using ConditionVariableInternal = ConditionVariableNT; struct ConditionVariableImpl final : IConditionVariable { inline ConditionVariableImpl(const AuSPtr &mutex) : mutex(mutex) { } auline AuSPtr GetMutex() override { return mutex; } auline bool WaitForSignal(AuUInt32 timeout) override { return cond.WaitForSignalNsEx(&std::static_pointer_cast(this->mutex)->mutex, AuMSToNS(timeout)); } auline bool WaitForSignalNS(AuUInt64 qwTimeout) override { return cond.WaitForSignalNsEx(&std::static_pointer_cast(this->mutex)->mutex, qwTimeout); } inline bool WaitForSignalNsEx(const std::shared_ptr &pMutex, AuUInt64 timeout) { return cond.WaitForSignalNsEx(pMutex.get(), timeout); } auline void Signal() override { cond.Signal(); } auline void Broadcast() override { cond.Broadcast(); } ConditionVariableNT cond; std::shared_ptr mutex; }; static const auto kSizeOfDummyCondVar = sizeof(ConditionVariableInternal); static const auto kBoolRequiredLateSet = true; static const auto kShiftCountByBits = 8u; // ...otherwise // assume undefined behaviour past: // * bit zero is used for atomic bit test and yield loops // ( keyed events are an optimization mechanism for Windows XPs spinloop i had accidentally recreated in xenus. ) // ( originally, nt yielding sucked with the most barebones spinlock being dumb a hypervisor-unaware, smt-aware, spinner. ) // ( keyed events would then go in these spinners to serve as an early futex as early back as the year 2001-3 (?). ) // * bit one might be used under some niche versions of windows // (hearsay paranoia) // i actually have no reason to believe windows ever implemented lock-awareness into the kernel // i think it might be fine to skip the whole bit zero thing, but still, im going to say keep the min=2 // worst case scenario, we end up using these bits (we did). } #endif