Jamie Reece Wilson
f2ac93027c
[*] 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
87 lines
3.2 KiB
C++
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;
|
|
}
|
|
} |