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

View File

@ -12,7 +12,7 @@
namespace Aurora::Threading namespace Aurora::Threading
{ {
static const auto kDefaultWaitPerProcess = 32; static const auto kDefaultWaitPerProcess = 12;
struct WaitState; struct WaitState;
@ -64,9 +64,9 @@ namespace Aurora::Threading
{ {
AuUInt32 uAtomic {}; AuUInt32 uAtomic {};
WaitEntry entries[kDefaultWaitPerProcess]; 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> template <typename T>
bool IterateAll(T callback); bool IterateAll(T callback);