[*] 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:
parent
5b495f7fd9
commit
1bda1f469f
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user