[+] LSLocalEvent

This commit is contained in:
Reece Wilson 2023-10-21 09:04:48 +01:00
parent f0aef1f712
commit f185f13dc7
6 changed files with 329 additions and 2 deletions

View File

@ -111,6 +111,7 @@ namespace Aurora::IO::Loop
return ELoopSource::eSourceEvent;
}
#if 0
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers)
{
auto event = AuMakeShared<LSEvent>(triggered, atomicRelease, permitMultipleTriggers);
@ -126,4 +127,5 @@ namespace Aurora::IO::Loop
return event;
}
#endif
}

View File

@ -54,6 +54,7 @@ namespace Aurora::IO::Loop
return ELoopSource::eSourceEvent;
}
#if 0
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool triggerd, bool atomicRelease, bool permitMultipleTriggers)
{
AuSPtr<LSEvent> ret;
@ -70,4 +71,5 @@ namespace Aurora::IO::Loop
return ret;
}
#endif
}

View File

@ -0,0 +1,259 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSLocalEvent.cpp
Date: 2023-10-21
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "LSLocalEvent.hpp"
#include <Source/Threading/Primitives/SMTYield.hpp>
namespace Aurora::IO::Loop
{
LSLocalEvent::LSLocalEvent()
{
}
LSLocalEvent::~LSLocalEvent()
{
}
bool LSLocalEvent::TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers)
{
if (!LSSemaphore::TryInit(1))
{
return false;
}
this->bTriggered_ = bTriggered;
this->bAtomicRelease_ = bAtomicRelease;
this->bPermitMultipleTriggers_= bPermitMultipleTriggers;
return true;
}
bool LSLocalEvent::OnTrigger(AuUInt handle)
{
while (true)
{
EventBits bits;
bits.state = AuAtomicLoad(&this->state_);
if (bits.bAtomicRelease)
{
if (bits.bTriggered)
{
auto next = bits;
next.bTriggered = 0;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) != bits.state)
{
continue;
}
return true;
}
else
{
return false;
}
}
else
{
if (bits.bTriggered)
{
LSSemaphore::AddOne();
return true;
}
else
{
return false;
}
}
}
}
bool LSLocalEvent::IsSignaled()
{
return this->TryTake();
}
bool LSLocalEvent::WaitOn(AuUInt32 timeout)
{
return this->TryTakeWaitMS(timeout);
}
ELoopSource LSLocalEvent::GetType()
{
return ELoopSource::eSourceEvent;
}
bool LSLocalEvent::Set()
{
EventBits bits, next;
while (true)
{
bits.state = AuAtomicLoad(&this->state_);
if (!bits.bPermitMultipleTriggers)
{
if (bits.bTriggered)
{
return false;
}
}
next.state = bits.state;
next.bTriggered = 1;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state)
{
break;
}
}
if (auto count = AuAtomicLoad(&this->uApproxSleepCount))
{
if (bits.bAtomicRelease)
{
LSSemaphore::AddOne();
}
else
{
for (AU_ITERATE_N(n, count))
{
LSSemaphore::AddOne();
}
}
}
return true;
}
void LSLocalEvent::OnPresleep()
{
AuAtomicAdd(&this->uApproxSleepCount, 1u);
}
void LSLocalEvent::OnFinishSleep()
{
AuAtomicSub(&this->uApproxSleepCount, 1u);
}
bool LSLocalEvent::Reset()
{
while (true)
{
EventBits bits, next;
bits.state = AuAtomicLoad(&this->state_);
if (!bits.bTriggered)
{
return false;
}
next.state = bits.state;
next.bTriggered = 0;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state)
{
break;
}
}
return true;
}
bool LSLocalEvent::TryTakeNoSpin()
{
EventBits bits;
bits.state = AuAtomicLoad(&this->state_);
if (bits.bAtomicRelease)
{
if (bits.bTriggered)
{
auto next = bits;
next.bTriggered = 0;
return AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state;
}
else
{
return false;
}
}
else
{
return bits.bTriggered;
}
}
bool LSLocalEvent::TryTakeSpin()
{
return Threading::Primitives::DoTryIf([&]
{
return this->TryTakeNoSpin();
});
}
bool LSLocalEvent::TryTake()
{
return this->TryTakeNoSpin();
}
bool LSLocalEvent::TryTakeWaitMS(AuUInt32 timeout)
{
auto uEndTime = AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout);
if (this->TryTakeSpin())
{
return true;
}
while (!this->TryTakeNoSpin())
{
if (!timeout)
{
if (LSSemaphore::WaitOn(0))
{
return true;
}
}
else
{
auto uStartTime = Time::SteadyClockNS();
if (uStartTime >= uEndTime)
{
return false;
}
auto uDeltaMs = AuNSToMS<AuInt64>(uEndTime - uStartTime);
if (uDeltaMs &&
LSSemaphore::WaitOn(uDeltaMs))
{
return true;
}
}
}
return true;
}
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers)
{
auto pMutex = AuMakeShared<LSLocalEvent>();
if (!pMutex)
{
SysPushErrorGeneric();
return {};
}
if (!pMutex->TryInit(bTriggered, bAtomicRelease, bPermitMultipleTriggers))
{
SysPushErrorNested();
return {};
}
return pMutex;
}
}

View File

@ -0,0 +1,63 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSLocalEvent.hpp
Date: 2023-10-21
Author: Reece
***/
#pragma once
#include "LSSemaphore.hpp"
namespace Aurora::IO::Loop
{
struct LSLocalEvent : LSSemaphore, ILSEvent
{
LSLocalEvent();
~LSLocalEvent();
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
ELoopSource GetType() override;
bool Set() override;
bool Reset() override;
virtual bool OnTrigger(AuUInt handle) override;
bool TryTakeNoSpin();
bool TryTakeSpin();
bool TryTake();
bool TryTakeWaitMS(AuUInt32 timeout);
void OnPresleep() override;
void OnFinishSleep() override;
union EventBits
{
struct
{
AuUInt8 bAtomicRelease : 1;
AuUInt8 bPermitMultipleTriggers : 1;
AuUInt8 bTriggered : 1;
};
AuUInt32 state;
};
union
{
struct
{
AuUInt8 bAtomicRelease_ : 1;
AuUInt8 bPermitMultipleTriggers_ : 1;
AuUInt8 bTriggered_ : 1;
};
AuUInt32 state_;
};
AuUInt32 uApproxSleepCount;
};
}

View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSLocalMutex.hpp
File: LSLocalSemaphore.hpp
Date: 2023-10-21
Author: Reece
***/

View File

@ -183,7 +183,8 @@ namespace Aurora::IO::Loop
auto type = lsList[0];
if (type->GetType() == ELoopSource::eSourceMutex ||
type->GetType() == ELoopSource::eSourceSemaphore)
type->GetType() == ELoopSource::eSourceSemaphore ||
type->GetType() == ELoopSource::eSourceEvent)
{
for (AU_ITERATE_N(i, lsList.size()))
{