From 5947e6a2c3a782f1363d1ae308b52441eb52879b Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Fri, 2 Aug 2024 02:23:09 +0100 Subject: [PATCH] [*/+] Added internal AuLoop::WaitMultipleOrObjects function for POSIX Issue4+ users, excluding the BSDs, to optimize AuLoop::WaitForMultipleObject users. (Win32 and Xbox emulators). This mitigates the epoll allocation / release under Linux. --- Source/IO/Loop/Loop.Unix.cpp | 186 +++++++++++++++++++++++++++++++++++ Source/IO/Loop/Loop.cpp | 11 ++- 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/Source/IO/Loop/Loop.Unix.cpp b/Source/IO/Loop/Loop.Unix.cpp index 515eb94e..ef6a6973 100644 --- a/Source/IO/Loop/Loop.Unix.cpp +++ b/Source/IO/Loop/Loop.Unix.cpp @@ -7,8 +7,194 @@ ***/ #include #include "Loop.Unix.hpp" +#include "ILoopSourceEx.hpp" +#include namespace Aurora::IO::Loop { + AuList> WaitMultipleOrObjects(const AuList> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany) + { + #if defined(AURORA_HAS_NO_POSIX_POLL) + // do the WinNT falllback into loop queue. + // + // loop queues should have long term persistency in a user-space ABI (kqueue) or in the kernel (epoll) + // they may take longer to setup, may seem wasteful to create and throw away, but it's probably the best we can do under BSD kernels. + // why? kevents exist for posix aio objects. they dont use fds. + // + // BSDs with posix AIO based async file transactions, >2.2 linux kernels, macos with corefoundation interop with kqueues, and other posix kernels with alternative aio will probably need + // need to use the win32 64 <= handles path. + bTooMany = true; + return false; + #else + AuList> loopSourceExs; + AuList> loopSourceExs2; + AuList> triggered; + AuList handleArray; + AuList> handleIndicies; + try + { + loopSourceExs.reserve(objects.size()); + loopSourceExs2.reserve(objects.size()); + handleArray.reserve(objects.size()); + triggered.reserve(triggered.size()); + handleIndicies.reserve(triggered.size()); + + for (const auto &source : objects) + { + if (!source) + { + continue; + } + + if (auto extended = AuDynamicCast(source)) + { + loopSourceExs2.push_back(extended); + + if (extended->Singular()) + { + auto handle = extended->GetHandle(); + auto handleWrite = extended->GetWriteHandle(); + + auto i = loopSourceExs.size(); + loopSourceExs.push_back(extended); + + if (handle != -1) + { + pollfd poll; + poll.fd = handle; + poll.events = POLLIN; + poll.revents = 0; + + handleArray.push_back(poll); + handleIndicies.push_back(AuMakePair(i, false)); + } + + if (handleWrite != -1) + { + pollfd poll; + poll.fd = handleWrite; + poll.events = POLLOUT; + poll.revents = 0; + + handleArray.push_back(poll); + handleIndicies.push_back(AuMakePair(i, true)); + } + } + else + { + auto handles = extended->GetHandles(); + auto handlesWrite = extended->GetWriteHandles(); + + auto i = loopSourceExs.size(); + loopSourceExs.push_back(extended); + + for (const auto &handle : handles) + { + pollfd poll; + if (handle == -1) + { + continue; + } + + poll.fd = handle; + poll.events = POLLIN; + poll.revents = 0; + + handleArray.push_back(poll); + handleIndicies.push_back(AuMakePair(i, false)); + } + + for (const auto &handle : handlesWrite) + { + pollfd poll; + if (handle == -1) + { + continue; + } + + poll.fd = handle; + poll.events = POLLOUT; + poll.revents = 0; + + handleArray.push_back(poll); + handleIndicies.push_back(AuMakePair(i, true)); + } + } + } + } + } + catch (...) + { + return {}; + } + + for (const auto &source : loopSourceExs2) + { + source->OnPresleep(); + } + + AuUInt32 uTimeout {}; + if (bZeroTick) + { + uTimeout = 0; + } + else if (!dwTimeoutReq) + { + uTimeout = -1; + } + else + { + uTimeout = dwTimeoutReq; + } + + int ret; + do + { + ret = poll(handleArray.data(), handleArray.size(), uTimeout); + uTimeout = 0; + + if (ret > 0) + { + for (AU_ITERATE_N(i, handleArray.size())) + { + if (!handleArray[i].revents) + { + continue; + } + + auto uIndex = AuGet<0>(handleIndicies[i]); + auto bRead = AuGet<1>(handleIndicies[i]); + auto pLoopSource = AuExchange(loopSourceExs[uIndex], nullptr); + if (!pLoopSource) + { + continue; + } + + if (!pLoopSource->OnTrigger(handleArray[i].fd)) + { + loopSourceExs[uIndex] = pLoopSource; + continue; + } + + triggered.push_back(pLoopSource); + + if (!bAllowOthers) + { + break; + } + } + } + } + while (ret == -1 && + errno == EINTR); + + for (const auto &source : loopSourceExs2) + { + source->OnFinishSleep(); + } + + return triggered; + #endif + } } \ No newline at end of file diff --git a/Source/IO/Loop/Loop.cpp b/Source/IO/Loop/Loop.cpp index a199602f..c4e25957 100644 --- a/Source/IO/Loop/Loop.cpp +++ b/Source/IO/Loop/Loop.cpp @@ -53,7 +53,7 @@ namespace Aurora::IO::Loop return workerPid.GetPool()->WorkerToLoopSource(workerPid); } -#if defined(AURORA_IS_MODERNNT_DERIVED) +#if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED) AuList> WaitMultipleOrObjects(const AuList> &objects, bool bZeroTick, AuUInt32 timeout, bool bAllowOthers, bool &bTooMany); #endif AuList> WaitMultipleOrObjectsFallback(const AuList> &objects, AuUInt32 timeout, bool bZeroTick, bool bAllowOthers, bool &bTimeout); @@ -402,6 +402,15 @@ namespace Aurora::IO::Loop false; } else + #elif defined(AURORA_IS_POSIX_DERIVED) + if (true) + { + signaled = WaitMultipleOrObjects(lsList2, bZeroTick, uTimeoutMS, bAllowOthers, bTooMany); + bTimedout = uTimeoutEnd && uTimeoutMS && !bZeroTick ? + Time::SteadyClockNS() >= uTimeoutEnd : + false; + } + else #endif { bTooMany = true;