[*] simplify wake on address emulation

Windows 7 reporting improved time to wake, but it is still averaging about the same... everything.
This commit is contained in:
Reece Wilson 2023-06-11 19:13:37 +01:00
parent 5b495f7fd9
commit 1bda1f469f
2 changed files with 66 additions and 56 deletions

View File

@ -14,6 +14,8 @@
namespace Aurora::Threading
{
static thread_local WaitEntry tlsWaitEntry;
#if defined(AURORA_IS_LINUX_DERIVED)
static int futex_wait(uint32_t *addr, uint32_t expected, const struct timespec *timeout)
{
@ -34,16 +36,50 @@ namespace Aurora::Threading
#endif
static ProcessWaitContainer gProcessWaitables;
static int gShouldSpinOnlyInCPU = 1; // TODO: havent decided
template<typename T>
static void DoSpinLockOnVar(T *uPointer)
{
if (gShouldSpinOnlyInCPU == 0)
{
while (!Primitives::DoTryIf([&]()
{
return AuAtomicTestAndSet(uPointer, 0) == 0;
}))
{
}
}
else if (gShouldSpinOnlyInCPU == 1)
{
while (!Primitives::DoTryIf([&]()
{
return AuAtomicTestAndSet(uPointer, 0) == 0;
}))
{
ContextYield();
}
}
else if (gShouldSpinOnlyInCPU == 2)
{
while (AuAtomicTestAndSet(uPointer, 0))
{
while (*uPointer)
{
ContextYield();
}
}
}
else
{
SysUnreachable();
}
}
bool WaitEntry::TryAcquire(const void *pAddress, AuUInt8 uSize)
{
while (AuAtomicTestAndSet(&this->uAtomic, 0))
{
while (this->uAtomic)
{
AuThreading::ContextYield();
}
}
DoSpinLockOnVar(&this->uAtomic);
//AU_LOCK_GUARD(this->mutex);
@ -167,13 +203,7 @@ namespace Aurora::Threading
bool WaitEntry::TryWake(const void *pAddress)
{
while (AuAtomicTestAndSet(&this->uAtomic, 0))
{
while (this->uAtomic)
{
AuThreading::ContextYield();
}
}
DoSpinLockOnVar(&this->uAtomic);
auto bRet = TryWakeNoLock(pAddress);
if (!bRet)
@ -241,30 +271,26 @@ namespace Aurora::Threading
}
}
AuSPtr<WaitEntry> ProcessWaitContainer::WaitBufferFrom(void *pAddress, AuUInt8 uSize)
WaitEntry *ProcessWaitContainer::WaitBufferFrom(void *pAddress, AuUInt8 uSize)
{
for (AU_ITERATE_N(i, kDefaultWaitPerProcess))
{
if (this->entries[i].TryAcquire(pAddress, uSize))
{
return AuUnsafeRaiiToShared(&this->entries[i]);
return &this->entries[i];
}
}
AuSPtr<WaitEntry> pNew;
{
AuDebug::AddMemoryCrunch();
pNew = AuMakeSharedPanic<WaitEntry>();
AuDebug::DecMemoryCrunch();
}
auto pReturn = &tlsWaitEntry;
{
Lock();
this->overflow.push_back(pNew);
this->overflow.push_back(pReturn);
pReturn->bOverflow = true;
Unlock();
}
return pNew;
return pReturn;
}
template <typename T>
@ -274,27 +300,23 @@ namespace Aurora::Threading
{
auto &entry = this->entries[i];
{
while (AuAtomicTestAndSet(&entry.uAtomic, 0))
{
while (entry.uAtomic)
{
AuThreading::ContextYield();
}
}
DoSpinLockOnVar(&entry.uAtomic);
if (!entry.pAddress)
{
entry.uAtomic = 0;
}
else
if (entry.pAddress)
{
// Intentional lock/unlock order:
AU_LOCK_GUARD(entry.mutex);
entry.uAtomic = 0;
if (!callback(entry))
{
return false;
}
}
else
{
entry.uAtomic = 0;
}
}
}
@ -321,13 +343,7 @@ namespace Aurora::Threading
{
auto &entry = this->entries[i];
{
while (AuAtomicTestAndSet(&entry.uAtomic, 0))
{
while (entry.uAtomic)
{
AuThreading::ContextYield();
}
}
DoSpinLockOnVar(&entry.uAtomic);
if (entry.pAddress)
{
@ -350,7 +366,7 @@ namespace Aurora::Threading
for (auto &overflow : this->overflow)
{
AU_LOCK_GUARD(overflow->mutex);
if (!callback(*overflow.get()))
if (!callback(*overflow))
{
bRetStatus = false;
break;
@ -372,13 +388,7 @@ namespace Aurora::Threading
void ProcessWaitContainer::Lock()
{
while (AuAtomicTestAndSet(&this->uAtomic, 0))
{
while (this->uAtomic)
{
AuThreading::ContextYield();
}
}
DoSpinLockOnVar(&this->uAtomic);
}
void ProcessWaitContainer::Unlock()
@ -393,7 +403,7 @@ namespace Aurora::Threading
itr != this->overflow.end();
)
{
if ((*itr).get() == pParent)
if ((*itr) == pParent)
{
itr = this->overflow.erase(itr);
}

View File

@ -12,7 +12,7 @@
namespace Aurora::Threading
{
static const auto kDefaultWaitPerProcess = 32;
static const auto kDefaultWaitPerProcess = 12;
struct WaitState;
@ -64,9 +64,9 @@ namespace Aurora::Threading
{
AuUInt32 uAtomic {};
WaitEntry entries[kDefaultWaitPerProcess];
AuList<AuSPtr<WaitEntry>> overflow;
AuList<WaitEntry *> overflow;
AuSPtr<WaitEntry> WaitBufferFrom(void *pAddress, AuUInt8 uSize);
WaitEntry *WaitBufferFrom(void *pAddress, AuUInt8 uSize);
template <typename T>
bool IterateAll(T callback);