[*/+] 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.
This commit is contained in:
Reece Wilson 2024-08-02 02:23:09 +01:00
parent 67c4cdbee0
commit 5947e6a2c3
2 changed files with 196 additions and 1 deletions

View File

@ -7,8 +7,194 @@
***/ ***/
#include <Source/RuntimeInternal.hpp> #include <Source/RuntimeInternal.hpp>
#include "Loop.Unix.hpp" #include "Loop.Unix.hpp"
#include "ILoopSourceEx.hpp"
#include <poll.h>
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)
{
#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<AuSPtr<ILoopSourceEx>> loopSourceExs;
AuList<AuSPtr<ILoopSourceEx>> loopSourceExs2;
AuList<AuSPtr<ILoopSource>> triggered;
AuList<pollfd> handleArray;
AuList<AuPair<AuUInt, bool>> 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<ILoopSourceEx>(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
}
} }

View File

@ -53,7 +53,7 @@ namespace Aurora::IO::Loop
return workerPid.GetPool()->WorkerToLoopSource(workerPid); return workerPid.GetPool()->WorkerToLoopSource(workerPid);
} }
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED)
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 timeout, bool bAllowOthers, bool &bTooMany); AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 timeout, bool bAllowOthers, bool &bTooMany);
#endif #endif
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjectsFallback(const AuList<AuSPtr<ILoopSource>> &objects, AuUInt32 timeout, bool bZeroTick, bool bAllowOthers, bool &bTimeout); AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjectsFallback(const AuList<AuSPtr<ILoopSource>> &objects, AuUInt32 timeout, bool bZeroTick, bool bAllowOthers, bool &bTimeout);
@ -402,6 +402,15 @@ namespace Aurora::IO::Loop
false; false;
} }
else 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 #endif
{ {
bTooMany = true; bTooMany = true;