101 lines
1.9 KiB
C++
101 lines
1.9 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Zenaphore.h"
|
|
#include "HAL/Event.h"
|
|
#include "HAL/PlatformProcess.h"
|
|
#include "Misc/ScopeLock.h"
|
|
|
|
FZenaphore::FZenaphore()
|
|
{
|
|
Event = FPlatformProcess::GetSynchEventFromPool(true);
|
|
}
|
|
|
|
FZenaphore::~FZenaphore()
|
|
{
|
|
FPlatformProcess::ReturnSynchEventToPool(Event);
|
|
}
|
|
|
|
void FZenaphore::NotifyInternal(FZenaphoreWaiterNode* Waiter)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ZenaphoreTrigger);
|
|
check(Waiter);
|
|
FScopeLock Lock(&Mutex);
|
|
Waiter->bTriggered = true;
|
|
Event->Trigger();
|
|
}
|
|
|
|
void FZenaphore::NotifyOne()
|
|
{
|
|
for (;;)
|
|
{
|
|
FZenaphoreWaiterNode* Waiter = HeadWaiter.Load();
|
|
if (!Waiter)
|
|
{
|
|
return;
|
|
}
|
|
if (HeadWaiter.CompareExchange(Waiter, Waiter->Next))
|
|
{
|
|
NotifyInternal(Waiter);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FZenaphore::NotifyAll()
|
|
{
|
|
for (;;)
|
|
{
|
|
FZenaphoreWaiterNode* Waiter = HeadWaiter.Load();
|
|
if (!Waiter)
|
|
{
|
|
return;
|
|
}
|
|
if (HeadWaiter.CompareExchange(Waiter, Waiter->Next))
|
|
{
|
|
NotifyInternal(Waiter);
|
|
}
|
|
}
|
|
}
|
|
|
|
FZenaphoreWaiter::~FZenaphoreWaiter()
|
|
{
|
|
if (SpinCount)
|
|
{
|
|
WaitInternal();
|
|
}
|
|
}
|
|
|
|
void FZenaphoreWaiter::WaitInternal()
|
|
{
|
|
for (;;)
|
|
{
|
|
Outer.Event->Wait(INT32_MAX, true);
|
|
FScopeLock Lock(&Outer.Mutex);
|
|
if (WaiterNode.bTriggered)
|
|
{
|
|
Outer.Event->Reset();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FZenaphoreWaiter::Wait()
|
|
{
|
|
if (SpinCount == 0)
|
|
{
|
|
FZenaphoreWaiterNode* OldHeadWaiter = nullptr;
|
|
WaiterNode.bTriggered = false;
|
|
WaiterNode.Next = nullptr;
|
|
while (!Outer.HeadWaiter.CompareExchange(OldHeadWaiter, &WaiterNode))
|
|
{
|
|
WaiterNode.Next = OldHeadWaiter;
|
|
}
|
|
++SpinCount;
|
|
}
|
|
else
|
|
{
|
|
WaitInternal();
|
|
SpinCount = 0;
|
|
}
|
|
}
|