[*] 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
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user