AuroraRuntime/Source/Threading/AuStopTheWorld.cpp
Jamie Reece Wilson f2ac93027c [*] Optimize WaitForMultipleAddressesAnd
[*] Harden bAlive: possible spurious bAlive = true
[*] WaitOnAddressSteady: dont let N of WakeNOnAdadress consume spurious threads that would fail, at a slight irrelevant cost to the waking thread, despite our guarantee (still true) that these wakes can be dropped
2024-12-03 20:28:46 +00:00

87 lines
3.2 KiB
C++

/***
Copyright (C) Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuStopTheWorld.cpp
Date: 2024-09-09
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuStopTheWorld.hpp"
#include "AuWakeOnAddress.hpp"
#include "Primitives/SMTYield.hpp"
namespace Aurora::Threading
{
static AuThreadPrimitives::RWLock gHolderRWLock;
AUKN_SYM IWaitable *GetShutdownReadLock()
{
return gHolderRWLock->AsReadable();
}
// See GetShutdownReadLock comment
void WakeOnAddressHoldContainersAndTheWorld(const AuVoidFunc &func)
{
// We * must * allow ::GetShutdownLock() to be recursive, no matter how the runtime is configured
Primitives::ThrdCfg::gEnableRWLockWriteBiasOnReadLock = false;
{
// First: no-one shall pass anymore
AU_LOCK_GUARD(gHolderRWLock->AsWritable());
// Second: wait for any sleep ops to finish
for (AU_ITERATE_N(i, kDefaultWaitPerProcess))
{
gProcessWaitables.list[i].Lock();
// Second - nested: unlink all wait multiple heads and send a spurious signal for WaitForMultipleAddressesOr to handle.
// Best case: WaitForMultipleAddressesOr notices it's spurious and goes back to sleep
// Worst case: a thread we intend to kill is now unlinked and gets stuck at the its' lock to reinsert its head
{
auto pCurrentHead = gProcessWaitables.list[i].waitList.pTail;
while (pCurrentHead)
{
if (auto pSpecial = pCurrentHead->pSpecial)
{
// pSpecial swill remain alive until it's removed by the caller (we own the container lock so gl with that)
AuAtomicStore(&pCurrentHead->bAlive, 0u);
#if defined(WOA_SEMAPHORE_MODE)
pCurrentHead->semaphore->Unlock(1);
#else
pCurrentHead->variable.Signal();
#endif
auto uCount = pSpecial->waitArray.Count<WaitMultipleEntry>();
auto pBase = pSpecial->waitArray.Begin<WaitMultipleEntry>();
for (AU_ITERATE_N(z, uCount))
{
gProcessWaitables.list[i].RemoveEntry<true>(pBase[z].pTargetAddress, pCurrentHead);
}
pCurrentHead = gProcessWaitables.list[i].waitList.pTail;
}
else
{
pCurrentHead = pCurrentHead->pBefore;
}
}
}
}
{
func();
}
// Finally: reset
for (AU_ITERATE_N(i, kDefaultWaitPerProcess))
{
gProcessWaitables.list[i].Unlock();
}
}
Primitives::ThrdCfg::gEnableRWLockWriteBiasOnReadLock = gRuntimeConfig.threadingConfig.bEnableRWLockWriteBiasOnReadLock;
}
}