[+] ILoopSource::IsSignaledExt(...)
[+] ILoopSource::WaitOnExt(...) [+] ILoopSource::WaitOnAbsExt(...)
This commit is contained in:
parent
77546b5098
commit
4d4f5e2501
@ -9,24 +9,60 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
/// Is the IO primitive is not IPC, entirely inprocess, this might avoid the kernel or a spinloop
|
||||
static const AuUInt8 kFlagLSTryNoSpin = 1;
|
||||
|
||||
/// Disallows IO Async transaction callbacks and APC callbacks from being called
|
||||
static const AuUInt8 kFlagLSTryNoIOAlerts = 2;
|
||||
|
||||
struct ILoopSource
|
||||
{
|
||||
/**
|
||||
* @brief Atomic is-signaled-and-latch
|
||||
* @brief Atomic is-signaled-and-latch.
|
||||
* Approx equiv to NT: WaitForSingleObjectEx(this, 0, TRUE); but will not break (WAIT_IO_COMPLETION) on APC or IO interruption.
|
||||
* @return
|
||||
*/
|
||||
*/
|
||||
virtual bool IsSignaled() = 0;
|
||||
|
||||
/**
|
||||
* @brief Atomic is-signaled-and-latch.
|
||||
* Approx equiv to NT: WaitForSingleObjectEx(this, 0, !(uFlags & kFlagLSTryNoIOAlerts)); but will not break (WAIT_IO_COMPLETION) on APC or IO interruption
|
||||
* @return
|
||||
*/
|
||||
virtual bool IsSignaledExt(AuUInt8 uFlags) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns a generic description about the loop source handle
|
||||
* @return
|
||||
*/
|
||||
*/
|
||||
virtual ELoopSource GetType() = 0;
|
||||
|
||||
/**
|
||||
* @breif Blocks the current thread for the kernel primitives
|
||||
* @warning Are you looking for LoopQueues? You can even reduce async threads down to kernel ILoopQueue's
|
||||
*/
|
||||
virtual bool WaitOn(AuUInt32 timeout = 0) = 0;
|
||||
* @breif Blocks the current thread for the kernel primitive.
|
||||
* @warning Are you looking for LoopQueues? You can even reduce async threads down to kernel ILoopQueues.
|
||||
* @warning see: (stateful wait context) AuIO::Loop::ILoopQueue
|
||||
* @warning see: (arbitrary stateless wait) AuIO::Loop::WaitMultipleLoopSources
|
||||
* @warning see: (arbitrary stateless wait) AuIO::Loop::WaitMultipleLoopSourcesEx
|
||||
* @warning see: (scheduling on registered thread) Async/IThreadPool::ToKernelWorkQueue
|
||||
* @warning see: (scheduling on registered thread) Async/IWorkItem::SetSchedByLoopSourceOnce
|
||||
* @warning see: (scheduling on registered thread) Async/IWorkItem::SetSchedByLoopSourceRepeating
|
||||
*/
|
||||
virtual bool WaitOn(AuUInt32 uTimeoutRelMS = 0) = 0;
|
||||
|
||||
virtual bool WaitOnExt(AuUInt8 uFlags, AuUInt32 uTimeoutRelMS = 0) = 0;
|
||||
|
||||
/**
|
||||
* Follows steady time & 0 = indefinite convention
|
||||
* @warning: The IO subsystem uses miliseconds internally. Expect under and overshoots.
|
||||
* nanosec resolution is useful for dealing with hidden interruptions requiring a resleep.
|
||||
*/
|
||||
virtual bool WaitOnAbs(AuUInt64 uTimeoutAbs = 0) = 0;
|
||||
|
||||
/**
|
||||
* Follows steady time & 0 = indefinite convention
|
||||
* @warning: The IO subsystem uses miliseconds internally. Expect under and overshoots.
|
||||
* nanosec resolution is useful for dealing with hidden interruptions requiring a resleep.
|
||||
*/
|
||||
virtual bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs = 0) = 0;
|
||||
};
|
||||
}
|
@ -19,6 +19,13 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
|
||||
// TODO: Win32 enters an alertable state, does not break
|
||||
// Linux does not enter an alertable state, but will soon-ish
|
||||
// There is no flag for enter alertable state
|
||||
// Cannot reach true parity with WaitForMultipleObjectsEx in this current state
|
||||
// Also, there is no flag for awoken by APC
|
||||
|
||||
// optTimeoutMS = {} | indefinite
|
||||
// optTimeoutMS = 0 | poll
|
||||
// optTimeoutMS = 1 | 1ms
|
||||
|
@ -211,7 +211,8 @@ namespace Aurora
|
||||
int io_getevents(aio_context_t ctx,
|
||||
long min_nr, long max_nr,
|
||||
struct io_event *events,
|
||||
struct timespec *timeout)
|
||||
struct timespec *timeout,
|
||||
bool bStrictUserspaceOnly)
|
||||
{
|
||||
int i {};
|
||||
|
||||
@ -256,6 +257,11 @@ namespace Aurora
|
||||
return i;
|
||||
}
|
||||
|
||||
if (bStrictUserspaceOnly)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
do_syscall:
|
||||
int iKernelCount {};
|
||||
if ((iKernelCount = syscallFuckYou(__NR_io_getevents,
|
||||
|
@ -56,7 +56,8 @@ namespace Aurora
|
||||
|
||||
int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
|
||||
struct io_event *events,
|
||||
struct timespec *timeout);
|
||||
struct timespec *timeout,
|
||||
bool bStrictUserspaceOnly);
|
||||
|
||||
ssize_t sys_getrandom(void *pBuffer, size_t uLength);
|
||||
|
||||
|
@ -305,7 +305,7 @@ static void LinuxRemoveRobustFutexSlow(AuUInt32 *futex)
|
||||
}
|
||||
}
|
||||
|
||||
static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout)
|
||||
static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout, AuUInt64 uTimeoutAbs)
|
||||
{
|
||||
bool bContended;
|
||||
struct timespec tspec;
|
||||
@ -315,6 +315,10 @@ static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout)
|
||||
{
|
||||
AuTime::ms2tsabs(&tspec, timeout);
|
||||
}
|
||||
else if (uTimeoutAbs)
|
||||
{
|
||||
AuTime::ns2ts(&tspec, uTimeoutAbs);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
@ -322,7 +326,7 @@ static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout)
|
||||
bContended = old != kFutexValueUnlocked;
|
||||
if (bContended)
|
||||
{
|
||||
int res = Aurora::futex_wait_shared(futex, old, timeout ? &tspec : nullptr);
|
||||
int res = Aurora::futex_wait_shared(futex, old, (timeout || uTimeoutAbs) ? &tspec : nullptr);
|
||||
if (res < 0)
|
||||
{
|
||||
if (res == -ETIMEDOUT)
|
||||
@ -541,7 +545,7 @@ namespace Aurora::IO::IPC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::LinuxLockFutex(futex, timeout))
|
||||
if (!::LinuxLockFutex(futex, timeout, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -581,6 +585,45 @@ namespace Aurora::IO::IPC
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPCMutexProxy::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
return this->IsSignaled();
|
||||
}
|
||||
|
||||
bool IPCMutexProxy::WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout)
|
||||
{
|
||||
return this->WaitOn(timeout);
|
||||
}
|
||||
|
||||
bool IPCMutexProxy::WaitOnAbs(AuUInt64 uTimeoutAbs)
|
||||
{
|
||||
auto futex = this->GetFutex();
|
||||
if (!futex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::LinuxLockFutex(futex, 0, uTimeoutAbs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->mutex_.IsSignaled())
|
||||
{
|
||||
::LinuxUnlockFutex(futex);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->leakSelf_ = AuSharedFromThis();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPCMutexProxy::WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs)
|
||||
{
|
||||
return this->WaitOnAbs(uTimeoutAbs);
|
||||
}
|
||||
|
||||
Loop::ELoopSource IPCMutexProxy::GetType()
|
||||
{
|
||||
return this->mutex_.GetType();
|
||||
|
@ -28,6 +28,11 @@ namespace Aurora::IO::IPC
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
Loop::ELoopSource GetType() override;
|
||||
|
||||
bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
bool WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) override;
|
||||
bool WaitOnAbs(AuUInt64 uTimeoutAbs) override;
|
||||
bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs) override;
|
||||
|
||||
AuString ExportToString() override;
|
||||
|
||||
AuUInt32 *GetFutex();
|
||||
|
@ -36,6 +36,7 @@ namespace Aurora::IO::IPC
|
||||
~IPCEventProxy();
|
||||
|
||||
PROXY_INTERNAL_INTERFACE(event_)
|
||||
PROXY_LOOPSOURCE_EXT_APIS(event_)
|
||||
IMPLEMENT_HANDLE
|
||||
|
||||
bool Set() override;
|
||||
@ -57,6 +58,7 @@ namespace Aurora::IO::IPC
|
||||
~IPCSemaphoreProxy();
|
||||
|
||||
PROXY_INTERNAL_INTERFACE(semaphore_)
|
||||
PROXY_LOOPSOURCE_EXT_APIS(semaphore_)
|
||||
IMPLEMENT_HANDLE
|
||||
|
||||
bool AddOne() override;
|
||||
|
@ -33,6 +33,7 @@ namespace Aurora::IO::IPC
|
||||
~IPCMutexProxy();
|
||||
|
||||
PROXY_INTERNAL_INTERFACE(mutex_)
|
||||
PROXY_LOOPSOURCE_EXT_APIS(mutex_)
|
||||
IMPLEMENT_HANDLE
|
||||
|
||||
bool Unlock() override;
|
||||
@ -151,6 +152,7 @@ namespace Aurora::IO::IPC
|
||||
~IPCEventProxy();
|
||||
|
||||
PROXY_INTERNAL_INTERFACE(event_)
|
||||
PROXY_LOOPSOURCE_EXT_APIS(event_)
|
||||
IMPLEMENT_HANDLE
|
||||
|
||||
bool Set() override;
|
||||
@ -276,6 +278,7 @@ namespace Aurora::IO::IPC
|
||||
~IPCSemaphoreProxy();
|
||||
|
||||
PROXY_INTERNAL_INTERFACE(semaphore_)
|
||||
PROXY_LOOPSOURCE_EXT_APIS(semaphore_)
|
||||
IMPLEMENT_HANDLE
|
||||
|
||||
bool AddOne() override;
|
||||
|
@ -51,7 +51,7 @@ namespace Aurora::IO::IPC
|
||||
#else
|
||||
|
||||
#define PROXY_INTERNAL_INTERFACE_(Base)\
|
||||
inline virtual void OnPresleep() override \
|
||||
inline virtual void OnPresleep() override \
|
||||
{ \
|
||||
Base OnPresleep(); \
|
||||
}; \
|
||||
@ -59,15 +59,15 @@ namespace Aurora::IO::IPC
|
||||
{ \
|
||||
return Base OnTrigger(handle); \
|
||||
} \
|
||||
inline virtual void OnFinishSleep() override \
|
||||
inline virtual void OnFinishSleep() override \
|
||||
{ \
|
||||
Base OnFinishSleep(); \
|
||||
} \
|
||||
inline virtual bool Singular() override \
|
||||
inline virtual bool Singular() override \
|
||||
{ \
|
||||
return Base Singular(); \
|
||||
} \
|
||||
inline virtual AuUInt GetHandle() override \
|
||||
inline virtual AuUInt GetHandle() override \
|
||||
{ \
|
||||
return Base GetHandle(); \
|
||||
} \
|
||||
@ -75,13 +75,36 @@ namespace Aurora::IO::IPC
|
||||
{ \
|
||||
return Base GetHandles(); \
|
||||
} \
|
||||
inline bool HasValidHandle() \
|
||||
inline bool HasValidHandle() \
|
||||
{ \
|
||||
return Base HasValidHandle(); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: 2024/09 (this doesnt belong here but im lazy and no primitive actually needs these overloads)
|
||||
// (fill the entire interface and drop the _IM_SO_LAZY part)
|
||||
|
||||
#define PROXY_LOOPSOURCE_EXT_APIS_(Base) \
|
||||
inline virtual bool IsSignaledExt(AuUInt8 uFlags) override \
|
||||
{ \
|
||||
return Base IsSignaledExt(uFlags); \
|
||||
} \
|
||||
inline virtual bool WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) override \
|
||||
{ \
|
||||
return Base WaitOnExt(uFlags, timeout); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbs(AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
return Base WaitOnAbs(uTimeoutAbs); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
return Base WaitOnAbsExt(uFlags, uTimeoutAbs); \
|
||||
}
|
||||
|
||||
#define PROXY_INTERNAL_INTERFACE(Base) PROXY_INTERNAL_INTERFACE_(Base.)
|
||||
#define PROXY_LOOPSOURCE_EXT_APIS(Base) PROXY_LOOPSOURCE_EXT_APIS_(Base.)
|
||||
|
||||
|
||||
}
|
@ -84,7 +84,12 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool LSEvent::IsSignaled()
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSEvent::IsSignaledNonblocking);
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSEvent::IsSignaledNonblocking, true);
|
||||
}
|
||||
|
||||
bool LSEvent::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSEvent::IsSignaledNonblocking, !(uFlags & kFlagLSTryNoIOAlerts));
|
||||
}
|
||||
|
||||
bool LSEvent::WaitOn(AuUInt32 timeout)
|
||||
|
@ -17,6 +17,8 @@ namespace Aurora::IO::Loop
|
||||
LSEvent(int handle, bool triggered, bool atomicRelease);
|
||||
~LSEvent();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
|
||||
|
||||
bool Set() override;
|
||||
bool Reset() override;
|
||||
|
||||
@ -25,6 +27,7 @@ namespace Aurora::IO::Loop
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
||||
virtual bool IsSignaled() override;
|
||||
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
virtual bool WaitOn(AuUInt32 timeout) override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
||||
|
@ -17,6 +17,8 @@ namespace Aurora::IO::Loop
|
||||
LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers);
|
||||
~LSEvent();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
|
||||
|
||||
bool Set() override;
|
||||
|
@ -7,15 +7,37 @@
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
|
||||
namespace Aurora::IO::UNIX
|
||||
{
|
||||
bool LinuxOverlappedYield(bool bUserspaceOnly);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
template<typename T>
|
||||
inline bool IsSignaledFromNonblockingImpl(ILoopSourceEx *source, T * that, bool(T::*IsSignaledNonblocking)())
|
||||
inline bool IsSignaledFromNonblockingImpl(ILoopSourceEx *source, T * that, bool(T::*IsSignaledNonblocking)(), bool bIOTick)
|
||||
{
|
||||
bool val {};
|
||||
source->OnPresleep();
|
||||
val = ((that)->*(IsSignaledNonblocking))();
|
||||
source->OnFinishSleep();
|
||||
// Required for precise Windows on Linux OVERLAPPED semantics for emulators.
|
||||
// IAsyncTransaction::Complete()/Wait() will always enter an alertable state and dispatch io completion callbacks.
|
||||
// In theory, we don't need this.
|
||||
// In practice, if NT can atomically set an event and update the apc queue, we could be out of parity.
|
||||
if (bIOTick)
|
||||
{
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
// Do not syscall after read or select again under Linux
|
||||
UNIX::LinuxOverlappedYield(true);
|
||||
#else
|
||||
IOYield();
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
@ -9,6 +9,73 @@
|
||||
|
||||
#include "WaitSingle.hpp"
|
||||
|
||||
#define PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_ \
|
||||
inline virtual bool WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) override \
|
||||
{ \
|
||||
return LSHandle::WaitOnExt(uFlags, timeout); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbs(AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
return LSHandle::WaitOnAbs(uTimeoutAbs); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
return LSHandle::WaitOnAbsExt(uFlags, uTimeoutAbs); \
|
||||
}
|
||||
|
||||
#define PROXY_LOOP_LOOPSOURCE_EXT_APIS_ \
|
||||
inline virtual bool IsSignaledExt(AuUInt8 uFlags) override \
|
||||
{ \
|
||||
return LSHandle::IsSignaledExt(uFlags); \
|
||||
} \
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_
|
||||
|
||||
// TODO: more work required
|
||||
#define PROXY_LOCAL_LOOPSOURCE_EXT_APIS_ \
|
||||
inline virtual bool IsSignaledExt(AuUInt8 uFlags) override \
|
||||
{ \
|
||||
bool bFlagUser = uFlags & kFlagLSTryNoSpin; \
|
||||
if (bFlagUser) \
|
||||
{ \
|
||||
return this->TryTakeNoSpin(); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return this->TryTakeSpin(); \
|
||||
} \
|
||||
} \
|
||||
inline virtual bool WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) override \
|
||||
{ \
|
||||
return this->WaitOn(timeout); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbs(AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
return this->WaitOnAbs(uTimeoutAbs); \
|
||||
} \
|
||||
inline virtual bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs) override \
|
||||
{ \
|
||||
if (!uTimeoutAbs) \
|
||||
{ \
|
||||
return this->TryTakeWaitNS(0); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return this->TryTakeWaitNS(uTimeoutAbs); \
|
||||
} \
|
||||
} \
|
||||
inline virtual bool WaitOn(AuUInt32 timeout) override \
|
||||
{ \
|
||||
if (!timeout) \
|
||||
{ \
|
||||
return this->TryTakeWaitNS(0); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return this->TryTakeWaitNS(AuMSToNS<AuUInt64>(timeout) + AuTime::SteadyClockNS()); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
|
@ -84,11 +84,6 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTake();
|
||||
}
|
||||
|
||||
bool LSLocalEvent::WaitOn(AuUInt32 timeout)
|
||||
{
|
||||
return this->TryTakeWaitMS(timeout);
|
||||
}
|
||||
|
||||
ELoopSource LSLocalEvent::GetType()
|
||||
{
|
||||
return ELoopSource::eSourceFastEvent;
|
||||
@ -234,12 +229,8 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTakeSpin();
|
||||
}
|
||||
|
||||
bool LSLocalEvent::TryTakeWaitMS(AuUInt32 timeout)
|
||||
bool LSLocalEvent::TryTakeWaitNS(AuUInt64 uEndTime)
|
||||
{
|
||||
auto uEndTime = timeout ?
|
||||
AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) :
|
||||
0;
|
||||
|
||||
if (this->TryTakeSpin())
|
||||
{
|
||||
return true;
|
||||
@ -247,7 +238,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
while (!this->TryTakeNoSpin())
|
||||
{
|
||||
if (!timeout)
|
||||
if (!uEndTime)
|
||||
{
|
||||
if (LSSemaphore::WaitOn(0))
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ namespace Aurora::IO::Loop
|
||||
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
|
||||
|
||||
virtual bool IsSignaled() override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
ELoopSource GetType() override;
|
||||
|
||||
bool Set() override;
|
||||
@ -30,7 +29,9 @@ namespace Aurora::IO::Loop
|
||||
bool TryTakeNoSpin();
|
||||
bool TryTakeSpin();
|
||||
bool TryTake();
|
||||
bool TryTakeWaitMS(AuUInt32 timeout);
|
||||
bool TryTakeWaitNS(AuUInt64 timeout);
|
||||
|
||||
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
bool IsSignaledNoSpinIfUserland() override;
|
||||
void OnPresleep() override;
|
||||
|
@ -91,11 +91,6 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTakeNoSpin();
|
||||
}
|
||||
|
||||
bool LSLocalMutex::WaitOn(AuUInt32 timeout)
|
||||
{
|
||||
return this->TryTakeWaitMS(timeout);
|
||||
}
|
||||
|
||||
ELoopSource LSLocalMutex::GetType()
|
||||
{
|
||||
return ELoopSource::eSourceFastMutex;
|
||||
@ -119,12 +114,8 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTakeSpin();
|
||||
}
|
||||
|
||||
bool LSLocalMutex::TryTakeWaitMS(AuUInt32 timeout)
|
||||
bool LSLocalMutex::TryTakeWaitNS(AuUInt64 uEndTime)
|
||||
{
|
||||
auto uEndTime = timeout ?
|
||||
AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) :
|
||||
0;
|
||||
|
||||
if (this->TryTakeSpin())
|
||||
{
|
||||
return true;
|
||||
@ -132,7 +123,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
while (!this->TryTakeNoSpin())
|
||||
{
|
||||
if (!timeout)
|
||||
if (!uEndTime)
|
||||
{
|
||||
if (LSSemaphore::WaitOn(0))
|
||||
{
|
||||
|
@ -20,7 +20,6 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool IsSignaled() override;
|
||||
bool IsSignaledNoSpinIfUserland() override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
ELoopSource GetType() override;
|
||||
|
||||
bool Unlock() override;
|
||||
@ -30,7 +29,9 @@ namespace Aurora::IO::Loop
|
||||
bool TryTakeNoSpin();
|
||||
bool TryTakeSpin();
|
||||
bool TryTake();
|
||||
bool TryTakeWaitMS(AuUInt32 timeout);
|
||||
bool TryTakeWaitNS(AuUInt64 timeout);
|
||||
|
||||
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
AuAUInt32 uAtomicWord {};
|
||||
};
|
||||
|
@ -251,11 +251,6 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTakeNoSpin();
|
||||
}
|
||||
|
||||
bool LSLocalSemaphore::WaitOn(AuUInt32 timeout)
|
||||
{
|
||||
return this->TryTakeWaitMS(timeout);
|
||||
}
|
||||
|
||||
ELoopSource LSLocalSemaphore::GetType()
|
||||
{
|
||||
return ELoopSource::eSourceFastSemaphore;
|
||||
@ -289,12 +284,8 @@ namespace Aurora::IO::Loop
|
||||
return this->TryTakeSpin();
|
||||
}
|
||||
|
||||
bool LSLocalSemaphore::TryTakeWaitMS(AuUInt32 timeout)
|
||||
bool LSLocalSemaphore::TryTakeWaitNS(AuUInt64 uEndTime)
|
||||
{
|
||||
auto uEndTime = timeout ?
|
||||
AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) :
|
||||
0;
|
||||
|
||||
if (this->TryTakeSpin())
|
||||
{
|
||||
return true;
|
||||
@ -302,7 +293,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
while (!this->TryTakeNoSpin())
|
||||
{
|
||||
if (!timeout)
|
||||
if (!uEndTime)
|
||||
{
|
||||
if (LSSemaphore::WaitOn(0))
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ namespace Aurora::IO::Loop
|
||||
bool TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount = 0);
|
||||
|
||||
bool IsSignaled() override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
bool IsSignaledNoSpinIfUserland() override;
|
||||
ELoopSource GetType() override;
|
||||
|
||||
@ -31,7 +30,9 @@ namespace Aurora::IO::Loop
|
||||
bool TryTakeNoSpin();
|
||||
bool TryTakeSpin();
|
||||
bool TryTake();
|
||||
bool TryTakeWaitMS(AuUInt32 timeout);
|
||||
bool TryTakeWaitNS(AuUInt64 timeout);
|
||||
|
||||
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
void OnPresleep() override;
|
||||
void OnFinishSleep() override;
|
||||
|
@ -61,7 +61,12 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool LSMutex::IsSignaled()
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSMutex::IsSignaledNonblocking);
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSMutex::IsSignaledNonblocking, true);
|
||||
}
|
||||
|
||||
bool LSMutex::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSMutex::IsSignaledNonblocking, !(uFlags & kFlagLSTryNoIOAlerts));
|
||||
}
|
||||
|
||||
bool LSMutex::WaitOn(AuUInt32 timeout)
|
||||
|
@ -16,11 +16,14 @@ namespace Aurora::IO::Loop
|
||||
LSMutex(int handle);
|
||||
~LSMutex();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
|
||||
|
||||
bool Unlock() override;
|
||||
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
||||
bool IsSignaled() override;
|
||||
bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
||||
|
@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
|
||||
LSMutex(HANDLE handle);
|
||||
~LSMutex();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
bool Unlock() override;
|
||||
|
||||
bool IsSignaled() override;
|
||||
|
@ -85,7 +85,12 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool LSSemaphore::IsSignaled()
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSSemaphore::IsSignaledNonblocking);
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSSemaphore::IsSignaledNonblocking, true);
|
||||
}
|
||||
|
||||
bool LSSemaphore::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSSemaphore::IsSignaledNonblocking, !(uFlags & kFlagLSTryNoIOAlerts));
|
||||
}
|
||||
|
||||
bool LSSemaphore::WaitOn(AuUInt32 timeout)
|
||||
|
@ -17,15 +17,17 @@ namespace Aurora::IO::Loop
|
||||
LSSemaphore(int handle, int tag);
|
||||
~LSSemaphore();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
|
||||
|
||||
bool TryInit(AuUInt32 initialCount = 0);
|
||||
|
||||
bool AddOne() override;
|
||||
bool AddMany(AuUInt32 uCount) override;
|
||||
|
||||
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
||||
bool IsSignaled() override;
|
||||
bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
||||
|
@ -16,6 +16,8 @@ namespace Aurora::IO::Loop
|
||||
LSSemaphore(HANDLE handle);
|
||||
~LSSemaphore();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
bool TryInit(AuUInt32 initialCount = 0);
|
||||
|
||||
bool AddOne() override;
|
||||
|
@ -56,7 +56,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool LSSignalCatcher::IsSignaled()
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSSignalCatcher::IsSignaledNonblocking);
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSSignalCatcher::IsSignaledNonblocking, true);
|
||||
}
|
||||
|
||||
bool LSSignalCatcher::WaitOn(AuUInt32 timeout)
|
||||
|
@ -82,7 +82,12 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool LSTimer::IsSignaled()
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSTimer::IsSignaledNonblocking);
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSTimer::IsSignaledNonblocking, true);
|
||||
}
|
||||
|
||||
bool LSTimer::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
return IsSignaledFromNonblockingImpl(this, this, &LSTimer::IsSignaledNonblocking, !(uFlags & kFlagLSTryNoIOAlerts));
|
||||
}
|
||||
|
||||
bool LSTimer::WaitOn(AuUInt32 timeout)
|
||||
|
@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
|
||||
LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, int handle);
|
||||
~LSTimer();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
|
||||
|
||||
virtual void UpdateTime(AuUInt64 absTimeMs) override;
|
||||
virtual void UpdateTimeNs(AuUInt64 absTimeNs) override;
|
||||
virtual void UpdateTickRateIfAny(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero) override;
|
||||
@ -24,6 +26,7 @@ namespace Aurora::IO::Loop
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
||||
virtual bool IsSignaled() override;
|
||||
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
virtual bool WaitOn(AuUInt32 timeout) override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
||||
|
@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
|
||||
LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, HANDLE handle);
|
||||
~LSTimer();
|
||||
|
||||
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
|
||||
|
||||
virtual void UpdateTime(AuUInt64 absTimeMs) override;
|
||||
virtual void UpdateTimeNs(AuUInt64 absTimeNs) override;
|
||||
virtual void UpdateTickRateIfAny(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero) override;
|
||||
|
@ -10,6 +10,16 @@
|
||||
#include "ILoopSourceEx.hpp"
|
||||
#include <poll.h>
|
||||
|
||||
// TODO:
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
|
||||
namespace Aurora::IO::UNIX
|
||||
{
|
||||
bool LinuxOverlappedYield(bool bUserspaceOnly);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany)
|
||||
@ -194,6 +204,16 @@ namespace Aurora::IO::Loop
|
||||
source->OnFinishSleep();
|
||||
}
|
||||
|
||||
// TODO: ugly workaround (see: LSFromHdNonblocking rationale) for an ugly TODO issue implicating all targets (see public Loop.hpp)
|
||||
{
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
// Do not syscall after read or select again under Linux
|
||||
UNIX::LinuxOverlappedYield(true);
|
||||
#else
|
||||
IOYield();
|
||||
#endif
|
||||
}
|
||||
|
||||
return triggered;
|
||||
#endif
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
bool WaitSingleGeneric::WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one)
|
||||
bool WaitSingleGeneric::WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one, bool bNoAlert)
|
||||
{
|
||||
if (handles.empty())
|
||||
{
|
||||
@ -43,7 +43,7 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handles.at(0)), uRemMS, true);
|
||||
ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handles.at(0)), uRemMS, bNoAlert ? FALSE : TRUE);
|
||||
|
||||
if (timeout &&
|
||||
ret != WAIT_IO_COMPLETION &&
|
||||
@ -94,7 +94,7 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
ret = WaitForMultipleObjectsEx(ntHandles.size(), ntHandles.data(), false, uRemMS, true);
|
||||
ret = WaitForMultipleObjectsEx(ntHandles.size(), ntHandles.data(), false, uRemMS, bNoAlert ? FALSE : TRUE);
|
||||
if (ret < WAIT_OBJECT_0)
|
||||
{
|
||||
continue;
|
||||
@ -121,13 +121,13 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
bool WaitSingleGeneric::WaitForOne(AuUInt32 timeout, AuUInt handle)
|
||||
bool WaitSingleGeneric::WaitForOne(AuUInt32 timeout, AuUInt handle, bool bNoAlert)
|
||||
{
|
||||
DWORD ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handle), timeout, true);
|
||||
ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handle), timeout, bNoAlert ? FALSE : TRUE);
|
||||
}
|
||||
while (ret == WAIT_IO_COMPLETION);
|
||||
|
||||
|
@ -11,8 +11,8 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
struct WaitSingleGeneric : virtual WaitSingleBase
|
||||
{
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one) override;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle) override;
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one, bool bNoAlert) override;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle, bool bNoAlert) override;
|
||||
virtual void OnPresleep() override;
|
||||
virtual void OnFinishSleep() override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
@ -15,13 +15,17 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
bool WaitSingleGeneric::WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, const AuList<AuUInt> &handlesWrite, AuUInt &one, AuUInt &two)
|
||||
bool WaitSingleGeneric::WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, const AuList<AuUInt> &handlesWrite, AuUInt &one, AuUInt &two, bool bNoAlert)
|
||||
{
|
||||
fd_set readSet, writeSet;
|
||||
AuUInt maxHandle {};
|
||||
struct timeval tv {};
|
||||
int active;
|
||||
|
||||
// TODO: IO SUBMIT HOOK
|
||||
if (!bNoAlert)
|
||||
{
|
||||
// TODO: IO SUBMIT HOOK
|
||||
}
|
||||
|
||||
FD_ZERO(&readSet);
|
||||
FD_ZERO(&writeSet);
|
||||
@ -45,11 +49,18 @@ namespace Aurora::IO::Loop
|
||||
maxHandle = AuMax(maxHandle, i + 1);
|
||||
}
|
||||
|
||||
auto active = select(maxHandle,
|
||||
handles.size() ? &readSet : nullptr,
|
||||
handlesWrite.size() ? &writeSet : nullptr,
|
||||
nullptr,
|
||||
timeout == AuUInt32(-1) ? nullptr : &tv);
|
||||
active = select(maxHandle,
|
||||
handles.size() ? &readSet : nullptr,
|
||||
handlesWrite.size() ? &writeSet : nullptr,
|
||||
nullptr,
|
||||
timeout == AuUInt32(-1) ? nullptr : &tv);
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
if (!bNoAlert)
|
||||
{
|
||||
(void)IO::UNIX::LinuxOverlappedYield();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (active == -1)
|
||||
{
|
||||
@ -87,17 +98,25 @@ namespace Aurora::IO::Loop
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaitSingleGeneric::WaitForOne(AuUInt32 timeout, AuUInt read, AuUInt write)
|
||||
// TODO: pass u64 end time, use pselect when available, fallback to this old logic
|
||||
// LinuxOverlappedWaitForOne doesnt understand yields, we have a specific yield op like the thread waitables, but that doesnt help with a single fd
|
||||
// pselect doesnt help much considering we need monotonic clock sleeps
|
||||
// also when we get around to freebsd support, we need to append one to the select array to handle a kqueue of thread local APCs + transactions
|
||||
// this is a mess and will continue to be a mess
|
||||
bool WaitSingleGeneric::WaitForOne(AuUInt32 timeout, AuUInt read, AuUInt write, bool bNoAlert)
|
||||
{
|
||||
fd_set readSet, writeSet;
|
||||
struct timeval tv {};
|
||||
int maxFd {};
|
||||
int active;
|
||||
|
||||
// TODO: see todo
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
if (!bNoAlert &&
|
||||
timeout)
|
||||
{
|
||||
bool bWriteTriggered, bReadTriggered;
|
||||
|
||||
if (IO::UNIX::LinuxOverlappedWaitForOne(timeout, read, write, bReadTriggered, bWriteTriggered))
|
||||
if (IO::UNIX::LinuxOverlappedWaitForOne(timeout == AuUInt32(-1) ? 0 : timeout, read, write, bReadTriggered, bWriteTriggered))
|
||||
{
|
||||
if (!bWriteTriggered && !bReadTriggered)
|
||||
{
|
||||
@ -129,11 +148,20 @@ namespace Aurora::IO::Loop
|
||||
maxFd = AuMax(maxFd, int(write) + 1);
|
||||
}
|
||||
|
||||
auto active = select(maxFd,
|
||||
read != -1 ? &readSet : nullptr,
|
||||
write != -1 ? &writeSet : nullptr,
|
||||
nullptr,
|
||||
timeout == AuUInt32(-1) ? nullptr : &tv);
|
||||
active = select(maxFd,
|
||||
read != -1 ? &readSet : nullptr,
|
||||
write != -1 ? &writeSet : nullptr,
|
||||
nullptr,
|
||||
timeout == AuUInt32(-1) ? nullptr : &tv);
|
||||
|
||||
// TODO: see todo
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
if (!bNoAlert &&
|
||||
!timeout)
|
||||
{
|
||||
(void)IO::UNIX::LinuxOverlappedYield();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (active == 0)
|
||||
{
|
||||
|
@ -11,8 +11,8 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
struct WaitSingleGeneric : virtual WaitSingleBase
|
||||
{
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &read _OPT_WRITE_REF) override;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE) override;
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &read _OPT_WRITE_REF, bool bNoAlert) override;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE, bool bNoAlert) override;
|
||||
virtual void OnPresleep() override;
|
||||
virtual void OnFinishSleep() override;
|
||||
virtual ELoopSource GetType() override;
|
||||
|
@ -16,10 +16,24 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
|
||||
bool WaitSingleBase::IsSignaled()
|
||||
{
|
||||
return this->IsSignaledExt(0);
|
||||
}
|
||||
|
||||
bool WaitSingleBase::IsSignaledExt(AuUInt8 uFlags)
|
||||
{
|
||||
bool val {};
|
||||
AuUInt one {AuNumericLimits<AuUInt>::max()};
|
||||
AuUInt two {AuNumericLimits<AuUInt>::max()};
|
||||
|
||||
bool bFlagUser = uFlags & kFlagLSTryNoSpin;
|
||||
bool bFlagNoAlert = uFlags & kFlagLSTryNoIOAlerts;
|
||||
|
||||
if (bFlagUser)
|
||||
{
|
||||
return this->IsSignaledNoSpinIfUserland();
|
||||
}
|
||||
|
||||
this->OnPresleep();
|
||||
|
||||
if (this->Singular())
|
||||
@ -27,10 +41,10 @@ namespace Aurora::IO::Loop
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
auto handle = this->GetHandle();
|
||||
auto handleRw = this->GetWriteHandle();
|
||||
val = this->WaitForOne(0, handle, handleRw);
|
||||
val = this->WaitForOne(0, handle, handleRw, bFlagNoAlert);
|
||||
#else
|
||||
auto handle = this->GetHandle();
|
||||
val = this->WaitForOne(0, handle);
|
||||
val = this->WaitForOne(0, handle, bFlagNoAlert);
|
||||
#endif
|
||||
if (val)
|
||||
{
|
||||
@ -42,11 +56,11 @@ namespace Aurora::IO::Loop
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
auto handles = this->GetHandles();
|
||||
auto handlesRw = this->GetWriteHandles();
|
||||
val = this->WaitForAtleastOne(0, handles, handlesRw, one, two);
|
||||
val = this->WaitForAtleastOne(0, handles, handlesRw, one, two, bFlagNoAlert);
|
||||
if (one == -1) one = two;
|
||||
#else
|
||||
auto handles = this->GetHandles();
|
||||
val = this->WaitForAtleastOne(0, handles, one);
|
||||
val = this->WaitForAtleastOne(0, handles, one, bFlagNoAlert);
|
||||
#endif
|
||||
|
||||
if (val)
|
||||
@ -61,27 +75,93 @@ namespace Aurora::IO::Loop
|
||||
|
||||
bool WaitSingleBase::WaitOn(AuUInt32 timeout)
|
||||
{
|
||||
bool val {};
|
||||
AuUInt one {AuNumericLimits<AuUInt>::max()};
|
||||
AuUInt two {AuNumericLimits<AuUInt>::max()};
|
||||
return this->WaitOnExt(0, timeout);
|
||||
}
|
||||
|
||||
this->OnPresleep();
|
||||
bool WaitSingleBase::WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout)
|
||||
{
|
||||
bool bFlagUser = uFlags & kFlagLSTryNoSpin;
|
||||
|
||||
if (bFlagUser)
|
||||
{
|
||||
if (this->IsSignaledNoSpinIfUserland())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uFlags &= ~kFlagLSTryNoSpin;
|
||||
}
|
||||
|
||||
auto uEndTime = timeout ?
|
||||
AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) :
|
||||
0;
|
||||
|
||||
return this->WaitOnAbsExt(uFlags, uEndTime);
|
||||
}
|
||||
|
||||
bool WaitSingleBase::WaitOnAbs(AuUInt64 uTimeoutAbs)
|
||||
{
|
||||
return this->WaitOnAbsExt(0, uTimeoutAbs);
|
||||
}
|
||||
|
||||
bool WaitSingleBase::WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uEndTime)
|
||||
{
|
||||
bool val {};
|
||||
AuUInt32 uMSTimeout {};
|
||||
AuUInt64 uNSTimeout {};
|
||||
bool bAgain {};
|
||||
AuUInt one {AuNumericLimits<AuUInt>::max()};
|
||||
AuUInt two {AuNumericLimits<AuUInt>::max()};
|
||||
|
||||
bool bFlagUser = uFlags & kFlagLSTryNoSpin;
|
||||
bool bFlagNoAlert = uFlags & kFlagLSTryNoIOAlerts;
|
||||
|
||||
if (bFlagUser)
|
||||
{
|
||||
if (this->IsSignaledNoSpinIfUserland())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this->OnPresleep();
|
||||
|
||||
do
|
||||
{
|
||||
if (uEndTime)
|
||||
{
|
||||
auto uStartTime = Time::SteadyClockNS();
|
||||
if (uStartTime >= uEndTime)
|
||||
{
|
||||
uMSTimeout = 0;
|
||||
uNSTimeout = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uNSTimeout = uEndTime - uStartTime;
|
||||
uMSTimeout = AuNSToMS<AuInt64>(uNSTimeout);
|
||||
}
|
||||
|
||||
if (bAgain && !uMSTimeout)
|
||||
{
|
||||
val = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uMSTimeout = AuUInt32(-1);
|
||||
}
|
||||
|
||||
if (this->Singular())
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
auto handle = this->GetHandle();
|
||||
auto handleRw = this->GetWriteHandle();
|
||||
val = this->WaitForOne(timeout ? timeout : AuUInt32(-1), handle, handleRw);
|
||||
val = this->WaitForOne(uMSTimeout, handle, handleRw, bFlagNoAlert);
|
||||
#else
|
||||
auto handle = this->GetHandle();
|
||||
val = this->WaitForOne(timeout ? timeout : AuUInt32(-1), handle);
|
||||
val = this->WaitForOne(uMSTimeout, handle, bFlagNoAlert);
|
||||
#endif
|
||||
if (val)
|
||||
{
|
||||
@ -93,11 +173,11 @@ namespace Aurora::IO::Loop
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
auto handles = this->GetHandles();
|
||||
auto handlesRw = this->GetWriteHandles();
|
||||
val = this->WaitForAtleastOne(timeout ? timeout : AuUInt32(-1), handles, handlesRw, one, two);
|
||||
val = this->WaitForAtleastOne(uMSTimeout, handles, handlesRw, one, two, bFlagNoAlert);
|
||||
if (one == -1) one = two;
|
||||
#else
|
||||
auto handles = this->GetHandles();
|
||||
val = this->WaitForAtleastOne(timeout ? timeout : AuUInt32(-1), handles, one);
|
||||
val = this->WaitForAtleastOne(uMSTimeout, handles, one, bFlagNoAlert);
|
||||
#endif
|
||||
|
||||
if (val)
|
||||
@ -106,18 +186,9 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
auto uStartTime = Time::SteadyClockNS();
|
||||
if (uStartTime >= uEndTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
timeout = AuNSToMS<AuInt64>(uEndTime - uStartTime);
|
||||
}
|
||||
bAgain = true;
|
||||
}
|
||||
while (timeout && !val);
|
||||
while (uEndTime && !val);
|
||||
|
||||
this->OnFinishSleep();
|
||||
return val;
|
||||
|
@ -29,11 +29,14 @@ namespace Aurora::IO::Loop
|
||||
|
||||
struct WaitSingleBase : virtual ILoopSourceEx
|
||||
{
|
||||
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
|
||||
virtual bool IsSignaledNoSpinIfUserland() override;
|
||||
virtual bool IsSignaled() override;
|
||||
virtual bool WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) override;
|
||||
virtual bool WaitOn(AuUInt32 timeout) override;
|
||||
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &one _OPT_WRITE_REF) = 0;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE) = 0;
|
||||
virtual bool WaitOnAbs(AuUInt64 uTimeoutAbs) override;
|
||||
virtual bool WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uTimeoutAbs) override;
|
||||
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &one _OPT_WRITE_REF, bool bNoAlert) = 0;
|
||||
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE, bool bNoAlert) = 0;
|
||||
};
|
||||
}
|
@ -580,7 +580,7 @@ namespace Aurora::IO::UNIX
|
||||
AuTime::ns2ts(&targetTime, uTimeNow - uTargetTime);
|
||||
}
|
||||
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, timeout ? &targetTime : nullptr);
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, timeout ? &targetTime : nullptr, false);
|
||||
|
||||
if (temp >= 0)
|
||||
{
|
||||
@ -748,7 +748,7 @@ namespace Aurora::IO::UNIX
|
||||
{
|
||||
break;
|
||||
}
|
||||
temp = io_getevents(io->context, 1, uCount, ioEvents, timeout ? &targetTime : nullptr);
|
||||
temp = io_getevents(io->context, 1, uCount, ioEvents, timeout ? &targetTime : nullptr, false);
|
||||
|
||||
if (temp >= 0)
|
||||
{
|
||||
@ -971,7 +971,7 @@ namespace Aurora::IO::UNIX
|
||||
{
|
||||
break;
|
||||
}
|
||||
temp = io_getevents(io->context, 1, uCount, ioEvents, timeout ? &targetTime : nullptr);
|
||||
temp = io_getevents(io->context, 1, uCount, ioEvents, timeout ? &targetTime : nullptr, false);
|
||||
|
||||
if (temp >= 0)
|
||||
{
|
||||
@ -1106,7 +1106,7 @@ namespace Aurora::IO::UNIX
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LinuxOverlappedYield()
|
||||
bool LinuxOverlappedYield(bool bUserspaceOnly)
|
||||
{
|
||||
io_event ioEvents[512];
|
||||
int temp;
|
||||
@ -1131,7 +1131,7 @@ namespace Aurora::IO::UNIX
|
||||
return false;
|
||||
}
|
||||
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, &targetTime);
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, &targetTime, bUserspaceOnly);
|
||||
|
||||
if (temp >= 0)
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <linux/aio_abi.h>
|
||||
#include <poll.h>
|
||||
|
||||
namespace Aurora::IO::UNIX
|
||||
{
|
||||
@ -64,8 +65,10 @@ namespace Aurora::IO::UNIX
|
||||
|
||||
int LinuxOverlappedEpollShim(int epfd, struct epoll_event *events,
|
||||
int maxevents, int timeout);
|
||||
// TODO:
|
||||
//int LinuxOverlappedPosixPoll(struct pollfd *pPollFDs, nfds_t uCount, int timeout);
|
||||
|
||||
bool LinuxOverlappedYield();
|
||||
bool LinuxOverlappedYield(bool bUserspaceOnly = false);
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user