[+] ILoopSource::IsSignaledExt(...)

[+] ILoopSource::WaitOnExt(...)
[+] ILoopSource::WaitOnAbsExt(...)
This commit is contained in:
Reece Wilson 2024-09-07 22:45:34 +01:00
parent 77546b5098
commit 4d4f5e2501
39 changed files with 513 additions and 158 deletions

View File

@ -9,24 +9,60 @@
namespace Aurora::IO::Loop 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 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 * @return
*/ */
virtual bool IsSignaled() = 0; 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 * @brief Returns a generic description about the loop source handle
* @return * @return
*/ */
virtual ELoopSource GetType() = 0; virtual ELoopSource GetType() = 0;
/** /**
* @breif Blocks the current thread for the kernel primitives * @breif Blocks the current thread for the kernel primitive.
* @warning Are you looking for LoopQueues? You can even reduce async threads down to kernel ILoopQueue's * @warning Are you looking for LoopQueues? You can even reduce async threads down to kernel ILoopQueues.
*/ * @warning see: (stateful wait context) AuIO::Loop::ILoopQueue
virtual bool WaitOn(AuUInt32 timeout = 0) = 0; * @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;
}; };
} }

View File

@ -19,6 +19,13 @@
namespace Aurora::IO::Loop 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 = {} | indefinite
// optTimeoutMS = 0 | poll // optTimeoutMS = 0 | poll
// optTimeoutMS = 1 | 1ms // optTimeoutMS = 1 | 1ms

View File

@ -211,7 +211,8 @@ namespace Aurora
int io_getevents(aio_context_t ctx, int io_getevents(aio_context_t ctx,
long min_nr, long max_nr, long min_nr, long max_nr,
struct io_event *events, struct io_event *events,
struct timespec *timeout) struct timespec *timeout,
bool bStrictUserspaceOnly)
{ {
int i {}; int i {};
@ -256,6 +257,11 @@ namespace Aurora
return i; return i;
} }
if (bStrictUserspaceOnly)
{
return i;
}
do_syscall: do_syscall:
int iKernelCount {}; int iKernelCount {};
if ((iKernelCount = syscallFuckYou(__NR_io_getevents, if ((iKernelCount = syscallFuckYou(__NR_io_getevents,

View File

@ -56,7 +56,8 @@ namespace Aurora
int io_getevents(aio_context_t ctx, long min_nr, long max_nr, int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
struct io_event *events, struct io_event *events,
struct timespec *timeout); struct timespec *timeout,
bool bStrictUserspaceOnly);
ssize_t sys_getrandom(void *pBuffer, size_t uLength); ssize_t sys_getrandom(void *pBuffer, size_t uLength);

View File

@ -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; bool bContended;
struct timespec tspec; struct timespec tspec;
@ -315,6 +315,10 @@ static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout)
{ {
AuTime::ms2tsabs(&tspec, timeout); AuTime::ms2tsabs(&tspec, timeout);
} }
else if (uTimeoutAbs)
{
AuTime::ns2ts(&tspec, uTimeoutAbs);
}
do do
{ {
@ -322,7 +326,7 @@ static bool LinuxLockFutex(AuUInt32 *futex, AuUInt32 timeout)
bContended = old != kFutexValueUnlocked; bContended = old != kFutexValueUnlocked;
if (bContended) 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 < 0)
{ {
if (res == -ETIMEDOUT) if (res == -ETIMEDOUT)
@ -541,7 +545,7 @@ namespace Aurora::IO::IPC
return false; return false;
} }
if (!::LinuxLockFutex(futex, timeout)) if (!::LinuxLockFutex(futex, timeout, 0))
{ {
return false; return false;
} }
@ -581,6 +585,45 @@ namespace Aurora::IO::IPC
return true; 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() Loop::ELoopSource IPCMutexProxy::GetType()
{ {
return this->mutex_.GetType(); return this->mutex_.GetType();

View File

@ -28,6 +28,11 @@ namespace Aurora::IO::IPC
bool WaitOn(AuUInt32 timeout) override; bool WaitOn(AuUInt32 timeout) override;
Loop::ELoopSource GetType() 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; AuString ExportToString() override;
AuUInt32 *GetFutex(); AuUInt32 *GetFutex();

View File

@ -36,6 +36,7 @@ namespace Aurora::IO::IPC
~IPCEventProxy(); ~IPCEventProxy();
PROXY_INTERNAL_INTERFACE(event_) PROXY_INTERNAL_INTERFACE(event_)
PROXY_LOOPSOURCE_EXT_APIS(event_)
IMPLEMENT_HANDLE IMPLEMENT_HANDLE
bool Set() override; bool Set() override;
@ -57,6 +58,7 @@ namespace Aurora::IO::IPC
~IPCSemaphoreProxy(); ~IPCSemaphoreProxy();
PROXY_INTERNAL_INTERFACE(semaphore_) PROXY_INTERNAL_INTERFACE(semaphore_)
PROXY_LOOPSOURCE_EXT_APIS(semaphore_)
IMPLEMENT_HANDLE IMPLEMENT_HANDLE
bool AddOne() override; bool AddOne() override;

View File

@ -33,6 +33,7 @@ namespace Aurora::IO::IPC
~IPCMutexProxy(); ~IPCMutexProxy();
PROXY_INTERNAL_INTERFACE(mutex_) PROXY_INTERNAL_INTERFACE(mutex_)
PROXY_LOOPSOURCE_EXT_APIS(mutex_)
IMPLEMENT_HANDLE IMPLEMENT_HANDLE
bool Unlock() override; bool Unlock() override;
@ -151,6 +152,7 @@ namespace Aurora::IO::IPC
~IPCEventProxy(); ~IPCEventProxy();
PROXY_INTERNAL_INTERFACE(event_) PROXY_INTERNAL_INTERFACE(event_)
PROXY_LOOPSOURCE_EXT_APIS(event_)
IMPLEMENT_HANDLE IMPLEMENT_HANDLE
bool Set() override; bool Set() override;
@ -276,6 +278,7 @@ namespace Aurora::IO::IPC
~IPCSemaphoreProxy(); ~IPCSemaphoreProxy();
PROXY_INTERNAL_INTERFACE(semaphore_) PROXY_INTERNAL_INTERFACE(semaphore_)
PROXY_LOOPSOURCE_EXT_APIS(semaphore_)
IMPLEMENT_HANDLE IMPLEMENT_HANDLE
bool AddOne() override; bool AddOne() override;

View File

@ -51,7 +51,7 @@ namespace Aurora::IO::IPC
#else #else
#define PROXY_INTERNAL_INTERFACE_(Base)\ #define PROXY_INTERNAL_INTERFACE_(Base)\
inline virtual void OnPresleep() override \ inline virtual void OnPresleep() override \
{ \ { \
Base OnPresleep(); \ Base OnPresleep(); \
}; \ }; \
@ -59,15 +59,15 @@ namespace Aurora::IO::IPC
{ \ { \
return Base OnTrigger(handle); \ return Base OnTrigger(handle); \
} \ } \
inline virtual void OnFinishSleep() override \ inline virtual void OnFinishSleep() override \
{ \ { \
Base OnFinishSleep(); \ Base OnFinishSleep(); \
} \ } \
inline virtual bool Singular() override \ inline virtual bool Singular() override \
{ \ { \
return Base Singular(); \ return Base Singular(); \
} \ } \
inline virtual AuUInt GetHandle() override \ inline virtual AuUInt GetHandle() override \
{ \ { \
return Base GetHandle(); \ return Base GetHandle(); \
} \ } \
@ -75,13 +75,36 @@ namespace Aurora::IO::IPC
{ \ { \
return Base GetHandles(); \ return Base GetHandles(); \
} \ } \
inline bool HasValidHandle() \ inline bool HasValidHandle() \
{ \ { \
return Base HasValidHandle(); \ return Base HasValidHandle(); \
} }
#endif #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_INTERNAL_INTERFACE(Base) PROXY_INTERNAL_INTERFACE_(Base.)
#define PROXY_LOOPSOURCE_EXT_APIS(Base) PROXY_LOOPSOURCE_EXT_APIS_(Base.)
} }

View File

@ -84,7 +84,12 @@ namespace Aurora::IO::Loop
bool LSEvent::IsSignaled() 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) bool LSEvent::WaitOn(AuUInt32 timeout)

View File

@ -1,36 +1,39 @@
/*** /***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSEvent.Linux.hpp File: LSEvent.Linux.hpp
Date: 2022-4-4 Date: 2022-4-4
Author: Reece Author: Reece
***/ ***/
#pragma once #pragma once
#include "LSHandle.hpp" #include "LSHandle.hpp"
namespace Aurora::IO::Loop namespace Aurora::IO::Loop
{ {
struct LSEvent : ILSEvent, virtual LSHandle struct LSEvent : ILSEvent, virtual LSHandle
{ {
LSEvent(); LSEvent();
LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers); LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers);
LSEvent(int handle, bool triggered, bool atomicRelease); LSEvent(int handle, bool triggered, bool atomicRelease);
~LSEvent(); ~LSEvent();
bool Set() override; PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
bool Reset() override;
bool Set() override;
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers); bool Reset() override;
virtual bool OnTrigger(AuUInt handle) override; bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
virtual bool IsSignaled() override; virtual bool OnTrigger(AuUInt handle) override;
virtual bool WaitOn(AuUInt32 timeout) override;
virtual ELoopSource GetType() override; virtual bool IsSignaled() override;
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
private: virtual bool WaitOn(AuUInt32 timeout) override;
void Init(bool init); virtual ELoopSource GetType() override;
bool IsSignaledNonblocking();
bool atomicRelease_; private:
}; void Init(bool init);
bool IsSignaledNonblocking();
bool atomicRelease_;
};
} }

View File

@ -17,6 +17,8 @@ namespace Aurora::IO::Loop
LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers); LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers);
~LSEvent(); ~LSEvent();
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers); bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
bool Set() override; bool Set() override;

View File

@ -7,15 +7,37 @@
***/ ***/
#pragma once #pragma once
#if defined(AURORA_IS_LINUX_DERIVED)
namespace Aurora::IO::UNIX
{
bool LinuxOverlappedYield(bool bUserspaceOnly);
}
#endif
namespace Aurora::IO::Loop namespace Aurora::IO::Loop
{ {
template<typename T> 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 {}; bool val {};
source->OnPresleep(); source->OnPresleep();
val = ((that)->*(IsSignaledNonblocking))(); val = ((that)->*(IsSignaledNonblocking))();
source->OnFinishSleep(); 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; return val;
} }
} }

View File

@ -9,6 +9,73 @@
#include "WaitSingle.hpp" #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 namespace Aurora::IO::Loop
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)

View File

@ -84,11 +84,6 @@ namespace Aurora::IO::Loop
return this->TryTake(); return this->TryTake();
} }
bool LSLocalEvent::WaitOn(AuUInt32 timeout)
{
return this->TryTakeWaitMS(timeout);
}
ELoopSource LSLocalEvent::GetType() ELoopSource LSLocalEvent::GetType()
{ {
return ELoopSource::eSourceFastEvent; return ELoopSource::eSourceFastEvent;
@ -234,12 +229,8 @@ namespace Aurora::IO::Loop
return this->TryTakeSpin(); 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()) if (this->TryTakeSpin())
{ {
return true; return true;
@ -247,7 +238,7 @@ namespace Aurora::IO::Loop
while (!this->TryTakeNoSpin()) while (!this->TryTakeNoSpin())
{ {
if (!timeout) if (!uEndTime)
{ {
if (LSSemaphore::WaitOn(0)) if (LSSemaphore::WaitOn(0))
{ {

View File

@ -19,7 +19,6 @@ namespace Aurora::IO::Loop
bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers); bool TryInit(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
virtual bool IsSignaled() override; virtual bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
ELoopSource GetType() override; ELoopSource GetType() override;
bool Set() override; bool Set() override;
@ -30,8 +29,10 @@ namespace Aurora::IO::Loop
bool TryTakeNoSpin(); bool TryTakeNoSpin();
bool TryTakeSpin(); bool TryTakeSpin();
bool TryTake(); bool TryTake();
bool TryTakeWaitMS(AuUInt32 timeout); bool TryTakeWaitNS(AuUInt64 timeout);
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
bool IsSignaledNoSpinIfUserland() override; bool IsSignaledNoSpinIfUserland() override;
void OnPresleep() override; void OnPresleep() override;
void OnFinishSleep() override; void OnFinishSleep() override;

View File

@ -91,11 +91,6 @@ namespace Aurora::IO::Loop
return this->TryTakeNoSpin(); return this->TryTakeNoSpin();
} }
bool LSLocalMutex::WaitOn(AuUInt32 timeout)
{
return this->TryTakeWaitMS(timeout);
}
ELoopSource LSLocalMutex::GetType() ELoopSource LSLocalMutex::GetType()
{ {
return ELoopSource::eSourceFastMutex; return ELoopSource::eSourceFastMutex;
@ -119,12 +114,8 @@ namespace Aurora::IO::Loop
return this->TryTakeSpin(); 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()) if (this->TryTakeSpin())
{ {
return true; return true;
@ -132,7 +123,7 @@ namespace Aurora::IO::Loop
while (!this->TryTakeNoSpin()) while (!this->TryTakeNoSpin())
{ {
if (!timeout) if (!uEndTime)
{ {
if (LSSemaphore::WaitOn(0)) if (LSSemaphore::WaitOn(0))
{ {

View File

@ -20,7 +20,6 @@ namespace Aurora::IO::Loop
bool IsSignaled() override; bool IsSignaled() override;
bool IsSignaledNoSpinIfUserland() override; bool IsSignaledNoSpinIfUserland() override;
bool WaitOn(AuUInt32 timeout) override;
ELoopSource GetType() override; ELoopSource GetType() override;
bool Unlock() override; bool Unlock() override;
@ -30,7 +29,9 @@ namespace Aurora::IO::Loop
bool TryTakeNoSpin(); bool TryTakeNoSpin();
bool TryTakeSpin(); bool TryTakeSpin();
bool TryTake(); bool TryTake();
bool TryTakeWaitMS(AuUInt32 timeout); bool TryTakeWaitNS(AuUInt64 timeout);
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
AuAUInt32 uAtomicWord {}; AuAUInt32 uAtomicWord {};
}; };

View File

@ -251,11 +251,6 @@ namespace Aurora::IO::Loop
return this->TryTakeNoSpin(); return this->TryTakeNoSpin();
} }
bool LSLocalSemaphore::WaitOn(AuUInt32 timeout)
{
return this->TryTakeWaitMS(timeout);
}
ELoopSource LSLocalSemaphore::GetType() ELoopSource LSLocalSemaphore::GetType()
{ {
return ELoopSource::eSourceFastSemaphore; return ELoopSource::eSourceFastSemaphore;
@ -289,12 +284,8 @@ namespace Aurora::IO::Loop
return this->TryTakeSpin(); 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()) if (this->TryTakeSpin())
{ {
return true; return true;
@ -302,7 +293,7 @@ namespace Aurora::IO::Loop
while (!this->TryTakeNoSpin()) while (!this->TryTakeNoSpin())
{ {
if (!timeout) if (!uEndTime)
{ {
if (LSSemaphore::WaitOn(0)) if (LSSemaphore::WaitOn(0))
{ {

View File

@ -19,7 +19,6 @@ namespace Aurora::IO::Loop
bool TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount = 0); bool TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount = 0);
bool IsSignaled() override; bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
bool IsSignaledNoSpinIfUserland() override; bool IsSignaledNoSpinIfUserland() override;
ELoopSource GetType() override; ELoopSource GetType() override;
@ -31,7 +30,9 @@ namespace Aurora::IO::Loop
bool TryTakeNoSpin(); bool TryTakeNoSpin();
bool TryTakeSpin(); bool TryTakeSpin();
bool TryTake(); bool TryTake();
bool TryTakeWaitMS(AuUInt32 timeout); bool TryTakeWaitNS(AuUInt64 timeout);
PROXY_LOCAL_LOOPSOURCE_EXT_APIS_;
void OnPresleep() override; void OnPresleep() override;
void OnFinishSleep() override; void OnFinishSleep() override;

View File

@ -61,7 +61,12 @@ namespace Aurora::IO::Loop
bool LSMutex::IsSignaled() 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) bool LSMutex::WaitOn(AuUInt32 timeout)

View File

@ -16,11 +16,14 @@ namespace Aurora::IO::Loop
LSMutex(int handle); LSMutex(int handle);
~LSMutex(); ~LSMutex();
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
bool Unlock() override; bool Unlock() override;
virtual bool OnTrigger(AuUInt handle) override; virtual bool OnTrigger(AuUInt handle) override;
bool IsSignaled() override; bool IsSignaled() override;
bool IsSignaledExt(AuUInt8 uFlags) override;
bool WaitOn(AuUInt32 timeout) override; bool WaitOn(AuUInt32 timeout) override;
virtual ELoopSource GetType() override; virtual ELoopSource GetType() override;

View File

@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
LSMutex(HANDLE handle); LSMutex(HANDLE handle);
~LSMutex(); ~LSMutex();
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
bool Unlock() override; bool Unlock() override;
bool IsSignaled() override; bool IsSignaled() override;

View File

@ -85,7 +85,12 @@ namespace Aurora::IO::Loop
bool LSSemaphore::IsSignaled() 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) bool LSSemaphore::WaitOn(AuUInt32 timeout)

View File

@ -17,15 +17,17 @@ namespace Aurora::IO::Loop
LSSemaphore(int handle, int tag); LSSemaphore(int handle, int tag);
~LSSemaphore(); ~LSSemaphore();
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
bool TryInit(AuUInt32 initialCount = 0); bool TryInit(AuUInt32 initialCount = 0);
bool AddOne() override; bool AddOne() override;
bool AddMany(AuUInt32 uCount) override; bool AddMany(AuUInt32 uCount) override;
virtual bool OnTrigger(AuUInt handle) override; virtual bool OnTrigger(AuUInt handle) override;
bool IsSignaled() override; bool IsSignaled() override;
bool IsSignaledExt(AuUInt8 uFlags) override;
bool WaitOn(AuUInt32 timeout) override; bool WaitOn(AuUInt32 timeout) override;
virtual ELoopSource GetType() override; virtual ELoopSource GetType() override;

View File

@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
LSSemaphore(); LSSemaphore();
LSSemaphore(HANDLE handle); LSSemaphore(HANDLE handle);
~LSSemaphore(); ~LSSemaphore();
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
bool TryInit(AuUInt32 initialCount = 0); bool TryInit(AuUInt32 initialCount = 0);

View File

@ -56,7 +56,7 @@ namespace Aurora::IO::Loop
bool LSSignalCatcher::IsSignaled() bool LSSignalCatcher::IsSignaled()
{ {
return IsSignaledFromNonblockingImpl(this, this, &LSSignalCatcher::IsSignaledNonblocking); return IsSignaledFromNonblockingImpl(this, this, &LSSignalCatcher::IsSignaledNonblocking, true);
} }
bool LSSignalCatcher::WaitOn(AuUInt32 timeout) bool LSSignalCatcher::WaitOn(AuUInt32 timeout)

View File

@ -82,7 +82,12 @@ namespace Aurora::IO::Loop
bool LSTimer::IsSignaled() 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) bool LSTimer::WaitOn(AuUInt32 timeout)

View File

@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, int handle); LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, int handle);
~LSTimer(); ~LSTimer();
PROXY_LOOP_LOOPSOURCE_EXT_WAIT_APIS_;
virtual void UpdateTime(AuUInt64 absTimeMs) override; virtual void UpdateTime(AuUInt64 absTimeMs) override;
virtual void UpdateTimeNs(AuUInt64 absTimeNs) override; virtual void UpdateTimeNs(AuUInt64 absTimeNs) override;
virtual void UpdateTickRateIfAny(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero) 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 OnTrigger(AuUInt handle) override;
virtual bool IsSignaled() override; virtual bool IsSignaled() override;
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
virtual bool WaitOn(AuUInt32 timeout) override; virtual bool WaitOn(AuUInt32 timeout) override;
virtual ELoopSource GetType() override; virtual ELoopSource GetType() override;

View File

@ -15,6 +15,8 @@ namespace Aurora::IO::Loop
LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, HANDLE handle); LSTimer(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero, bool bSingleshot, HANDLE handle);
~LSTimer(); ~LSTimer();
PROXY_LOOP_LOOPSOURCE_EXT_APIS_;
virtual void UpdateTime(AuUInt64 absTimeMs) override; virtual void UpdateTime(AuUInt64 absTimeMs) override;
virtual void UpdateTimeNs(AuUInt64 absTimeNs) override; virtual void UpdateTimeNs(AuUInt64 absTimeNs) override;
virtual void UpdateTickRateIfAny(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero) override; virtual void UpdateTickRateIfAny(AuUInt32 reschedStepMsOrZero, AuUInt32 maxIterationsOrZero) override;

View File

@ -10,6 +10,16 @@
#include "ILoopSourceEx.hpp" #include "ILoopSourceEx.hpp"
#include <poll.h> #include <poll.h>
// TODO:
#if defined(AURORA_IS_LINUX_DERIVED)
namespace Aurora::IO::UNIX
{
bool LinuxOverlappedYield(bool bUserspaceOnly);
}
#endif
namespace Aurora::IO::Loop namespace Aurora::IO::Loop
{ {
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany) 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(); 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; return triggered;
#endif #endif
} }

View File

@ -10,7 +10,7 @@
namespace Aurora::IO::Loop 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()) 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 && if (timeout &&
ret != WAIT_IO_COMPLETION && 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) if (ret < WAIT_OBJECT_0)
{ {
continue; 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; DWORD ret;
do do
{ {
ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handle), timeout, true); ret = WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handle), timeout, bNoAlert ? FALSE : TRUE);
} }
while (ret == WAIT_IO_COMPLETION); while (ret == WAIT_IO_COMPLETION);

View File

@ -11,8 +11,8 @@ namespace Aurora::IO::Loop
{ {
struct WaitSingleGeneric : virtual WaitSingleBase struct WaitSingleGeneric : virtual WaitSingleBase
{ {
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one) override; virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles, AuUInt &one, bool bNoAlert) override;
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle) override; virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle, bool bNoAlert) override;
virtual void OnPresleep() override; virtual void OnPresleep() override;
virtual void OnFinishSleep() override; virtual void OnFinishSleep() override;
virtual ELoopSource GetType() override; virtual ELoopSource GetType() override;

View File

@ -15,13 +15,17 @@
namespace Aurora::IO::Loop 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; fd_set readSet, writeSet;
AuUInt maxHandle {}; AuUInt maxHandle {};
struct timeval tv {}; struct timeval tv {};
int active;
// TODO: IO SUBMIT HOOK
if (!bNoAlert)
{
// TODO: IO SUBMIT HOOK
}
FD_ZERO(&readSet); FD_ZERO(&readSet);
FD_ZERO(&writeSet); FD_ZERO(&writeSet);
@ -45,11 +49,18 @@ namespace Aurora::IO::Loop
maxHandle = AuMax(maxHandle, i + 1); maxHandle = AuMax(maxHandle, i + 1);
} }
auto active = select(maxHandle, active = select(maxHandle,
handles.size() ? &readSet : nullptr, handles.size() ? &readSet : nullptr,
handlesWrite.size() ? &writeSet : nullptr, handlesWrite.size() ? &writeSet : nullptr,
nullptr, nullptr,
timeout == AuUInt32(-1) ? nullptr : &tv); timeout == AuUInt32(-1) ? nullptr : &tv);
#if defined(AURORA_IS_LINUX_DERIVED)
if (!bNoAlert)
{
(void)IO::UNIX::LinuxOverlappedYield();
}
#endif
if (active == -1) if (active == -1)
{ {
@ -87,17 +98,25 @@ namespace Aurora::IO::Loop
return true; 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; fd_set readSet, writeSet;
struct timeval tv {}; struct timeval tv {};
int maxFd {}; int maxFd {};
int active;
// TODO: see todo
#if defined(AURORA_IS_LINUX_DERIVED) #if defined(AURORA_IS_LINUX_DERIVED)
if (!bNoAlert &&
timeout)
{ {
bool bWriteTriggered, bReadTriggered; bool bWriteTriggered, bReadTriggered;
if (IO::UNIX::LinuxOverlappedWaitForOne(timeout == AuUInt32(-1) ? 0 : timeout, read, write, bReadTriggered, bWriteTriggered))
if (IO::UNIX::LinuxOverlappedWaitForOne(timeout, read, write, bReadTriggered, bWriteTriggered))
{ {
if (!bWriteTriggered && !bReadTriggered) if (!bWriteTriggered && !bReadTriggered)
{ {
@ -129,11 +148,20 @@ namespace Aurora::IO::Loop
maxFd = AuMax(maxFd, int(write) + 1); maxFd = AuMax(maxFd, int(write) + 1);
} }
auto active = select(maxFd, active = select(maxFd,
read != -1 ? &readSet : nullptr, read != -1 ? &readSet : nullptr,
write != -1 ? &writeSet : nullptr, write != -1 ? &writeSet : nullptr,
nullptr, nullptr,
timeout == AuUInt32(-1) ? nullptr : &tv); 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) if (active == 0)
{ {

View File

@ -11,8 +11,8 @@ namespace Aurora::IO::Loop
{ {
struct WaitSingleGeneric : virtual WaitSingleBase struct WaitSingleGeneric : virtual WaitSingleBase
{ {
virtual bool WaitForAtleastOne(AuUInt32 timeout, const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &read _OPT_WRITE_REF) 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) override; virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE, bool bNoAlert) override;
virtual void OnPresleep() override; virtual void OnPresleep() override;
virtual void OnFinishSleep() override; virtual void OnFinishSleep() override;
virtual ELoopSource GetType() override; virtual ELoopSource GetType() override;

View File

@ -16,10 +16,24 @@ namespace Aurora::IO::Loop
} }
bool WaitSingleBase::IsSignaled() bool WaitSingleBase::IsSignaled()
{
return this->IsSignaledExt(0);
}
bool WaitSingleBase::IsSignaledExt(AuUInt8 uFlags)
{ {
bool val {}; bool val {};
AuUInt one {AuNumericLimits<AuUInt>::max()}; AuUInt one {AuNumericLimits<AuUInt>::max()};
AuUInt two {AuNumericLimits<AuUInt>::max()}; AuUInt two {AuNumericLimits<AuUInt>::max()};
bool bFlagUser = uFlags & kFlagLSTryNoSpin;
bool bFlagNoAlert = uFlags & kFlagLSTryNoIOAlerts;
if (bFlagUser)
{
return this->IsSignaledNoSpinIfUserland();
}
this->OnPresleep(); this->OnPresleep();
if (this->Singular()) if (this->Singular())
@ -27,10 +41,10 @@ namespace Aurora::IO::Loop
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
auto handle = this->GetHandle(); auto handle = this->GetHandle();
auto handleRw = this->GetWriteHandle(); auto handleRw = this->GetWriteHandle();
val = this->WaitForOne(0, handle, handleRw); val = this->WaitForOne(0, handle, handleRw, bFlagNoAlert);
#else #else
auto handle = this->GetHandle(); auto handle = this->GetHandle();
val = this->WaitForOne(0, handle); val = this->WaitForOne(0, handle, bFlagNoAlert);
#endif #endif
if (val) if (val)
{ {
@ -42,11 +56,11 @@ namespace Aurora::IO::Loop
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
auto handles = this->GetHandles(); auto handles = this->GetHandles();
auto handlesRw = this->GetWriteHandles(); 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; if (one == -1) one = two;
#else #else
auto handles = this->GetHandles(); auto handles = this->GetHandles();
val = this->WaitForAtleastOne(0, handles, one); val = this->WaitForAtleastOne(0, handles, one, bFlagNoAlert);
#endif #endif
if (val) if (val)
@ -61,27 +75,93 @@ namespace Aurora::IO::Loop
bool WaitSingleBase::WaitOn(AuUInt32 timeout) bool WaitSingleBase::WaitOn(AuUInt32 timeout)
{ {
bool val {}; return this->WaitOnExt(0, timeout);
AuUInt one {AuNumericLimits<AuUInt>::max()}; }
AuUInt two {AuNumericLimits<AuUInt>::max()};
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 ? auto uEndTime = timeout ?
AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) : AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(timeout) :
0; 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 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 (this->Singular())
{ {
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
auto handle = this->GetHandle(); auto handle = this->GetHandle();
auto handleRw = this->GetWriteHandle(); auto handleRw = this->GetWriteHandle();
val = this->WaitForOne(timeout ? timeout : AuUInt32(-1), handle, handleRw); val = this->WaitForOne(uMSTimeout, handle, handleRw, bFlagNoAlert);
#else #else
auto handle = this->GetHandle(); auto handle = this->GetHandle();
val = this->WaitForOne(timeout ? timeout : AuUInt32(-1), handle); val = this->WaitForOne(uMSTimeout, handle, bFlagNoAlert);
#endif #endif
if (val) if (val)
{ {
@ -93,11 +173,11 @@ namespace Aurora::IO::Loop
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
auto handles = this->GetHandles(); auto handles = this->GetHandles();
auto handlesRw = this->GetWriteHandles(); 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; if (one == -1) one = two;
#else #else
auto handles = this->GetHandles(); auto handles = this->GetHandles();
val = this->WaitForAtleastOne(timeout ? timeout : AuUInt32(-1), handles, one); val = this->WaitForAtleastOne(uMSTimeout, handles, one, bFlagNoAlert);
#endif #endif
if (val) if (val)
@ -106,18 +186,9 @@ namespace Aurora::IO::Loop
} }
} }
if (timeout) bAgain = true;
{
auto uStartTime = Time::SteadyClockNS();
if (uStartTime >= uEndTime)
{
return false;
}
timeout = AuNSToMS<AuInt64>(uEndTime - uStartTime);
}
} }
while (timeout && !val); while (uEndTime && !val);
this->OnFinishSleep(); this->OnFinishSleep();
return val; return val;

View File

@ -29,11 +29,14 @@ namespace Aurora::IO::Loop
struct WaitSingleBase : virtual ILoopSourceEx struct WaitSingleBase : virtual ILoopSourceEx
{ {
virtual bool IsSignaledExt(AuUInt8 uFlags) override;
virtual bool IsSignaledNoSpinIfUserland() override; virtual bool IsSignaledNoSpinIfUserland() override;
virtual bool IsSignaled() override; virtual bool IsSignaled() override;
virtual bool WaitOn(AuUInt32 timeout) 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 WaitOnAbs(AuUInt64 uTimeoutAbs) override;
virtual bool WaitForOne(AuUInt32 timeout, AuUInt handle _OPT_WRITE) = 0; 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;
}; };
} }

View File

@ -580,7 +580,7 @@ namespace Aurora::IO::UNIX
AuTime::ns2ts(&targetTime, uTimeNow - uTargetTime); 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) if (temp >= 0)
{ {
@ -748,7 +748,7 @@ namespace Aurora::IO::UNIX
{ {
break; 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) if (temp >= 0)
{ {
@ -971,7 +971,7 @@ namespace Aurora::IO::UNIX
{ {
break; 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) if (temp >= 0)
{ {
@ -1106,7 +1106,7 @@ namespace Aurora::IO::UNIX
return false; return false;
} }
bool LinuxOverlappedYield() bool LinuxOverlappedYield(bool bUserspaceOnly)
{ {
io_event ioEvents[512]; io_event ioEvents[512];
int temp; int temp;
@ -1131,7 +1131,7 @@ namespace Aurora::IO::UNIX
return false; return false;
} }
temp = io_getevents(io->context, 1, 512, ioEvents, &targetTime); temp = io_getevents(io->context, 1, 512, ioEvents, &targetTime, bUserspaceOnly);
if (temp >= 0) if (temp >= 0)
{ {

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include <linux/aio_abi.h> #include <linux/aio_abi.h>
#include <poll.h>
namespace Aurora::IO::UNIX namespace Aurora::IO::UNIX
{ {
@ -64,8 +65,10 @@ namespace Aurora::IO::UNIX
int LinuxOverlappedEpollShim(int epfd, struct epoll_event *events, int LinuxOverlappedEpollShim(int epfd, struct epoll_event *events,
int maxevents, int timeout); int maxevents, int timeout);
// TODO:
bool LinuxOverlappedYield(); //int LinuxOverlappedPosixPoll(struct pollfd *pPollFDs, nfds_t uCount, int timeout);
bool LinuxOverlappedYield(bool bUserspaceOnly = false);