[*] AuLoop::WaitMultipleLoopSources optimizations (do not allocate so much, if we can), and
[*] Updated Loop.hpp comment
This commit is contained in:
parent
ff6409859f
commit
6e9e962c84
@ -19,12 +19,11 @@
|
||||
|
||||
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
|
||||
// TODO: We cannot reach true parity with NTs WaitForMultipleObjectsEx in this current state ( TODO )
|
||||
// [1] There is no flag for enter/do-not-enter alertable state (processes file transactions and their subscribers, network transactions and their subscribers, APCs, etc)
|
||||
// (also see: ./../IOSleep.hpp)
|
||||
// [2] There is no explicit flag for awoken by APC ( could use true && signaled.empty() ).
|
||||
// [3] And we can't do timer callbacks in-thread with the state of our current APC implementation ( TODO ).
|
||||
|
||||
// optTimeoutMS = {} | indefinite
|
||||
// optTimeoutMS = 0 | poll
|
||||
|
@ -14,64 +14,81 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany)
|
||||
{
|
||||
bool isWinLoop;
|
||||
AuList<AuSPtr<ILoopSourceEx>> loopSourceExs;
|
||||
bool bIsWinLoop;
|
||||
AuSPtr<ILoopSourceEx> loopSourceExs[MAXIMUM_WAIT_OBJECTS];
|
||||
HANDLE handleArray[MAXIMUM_WAIT_OBJECTS];
|
||||
AuUInt32 uCounterHandle, uCounterFD;
|
||||
AuSPtr<ILoopSource> pMsgSource;
|
||||
AuList<AuSPtr<ILoopSource>> triggered;
|
||||
AuList<HANDLE> handleArray;
|
||||
AuSPtr<ILoopSource> msgSource;
|
||||
|
||||
bIsWinLoop = false;
|
||||
uCounterHandle = 0;
|
||||
uCounterFD = 0;
|
||||
|
||||
try
|
||||
{
|
||||
isWinLoop = false;
|
||||
loopSourceExs.reserve(objects.size());
|
||||
handleArray.reserve(objects.size());
|
||||
triggered.reserve(triggered.size());
|
||||
|
||||
for (const auto &source : objects)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source->GetType() == ELoopSource::eSourceWin32)
|
||||
{
|
||||
isWinLoop = true;
|
||||
msgSource = source;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto extended = AuDynamicCast<ILoopSourceEx>(source))
|
||||
{
|
||||
loopSourceExs.push_back(extended);
|
||||
if (extended->Singular())
|
||||
{
|
||||
handleArray.push_back(reinterpret_cast<HANDLE>(extended->GetHandle()));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &handle : extended->GetHandles())
|
||||
{
|
||||
handleArray.push_back(reinterpret_cast<HANDLE>(handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (handleArray.size() >= MAXIMUM_WAIT_OBJECTS)
|
||||
for (const auto &source : objects)
|
||||
{
|
||||
bTooMany = true;
|
||||
return {};
|
||||
if (!source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source->GetType() == ELoopSource::eSourceWin32)
|
||||
{
|
||||
bIsWinLoop = true;
|
||||
pMsgSource = source;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto extended = AuDynamicCast<ILoopSourceEx>(source))
|
||||
{
|
||||
{
|
||||
auto uNewIndex = uCounterHandle++;
|
||||
if (uNewIndex == MAXIMUM_WAIT_OBJECTS)
|
||||
{
|
||||
bTooMany = true;
|
||||
return {};
|
||||
}
|
||||
loopSourceExs[uNewIndex] = extended;
|
||||
}
|
||||
|
||||
if (extended->Singular())
|
||||
{
|
||||
auto uNewIndex = uCounterFD++;
|
||||
if (uNewIndex == MAXIMUM_WAIT_OBJECTS)
|
||||
{
|
||||
bTooMany = true;
|
||||
return {};
|
||||
}
|
||||
handleArray[uNewIndex] = reinterpret_cast<HANDLE>(extended->GetHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &handle : extended->GetHandles())
|
||||
{
|
||||
auto uNewIndex = uCounterFD++;
|
||||
if (uNewIndex == MAXIMUM_WAIT_OBJECTS)
|
||||
{
|
||||
bTooMany = true;
|
||||
return {};
|
||||
}
|
||||
handleArray[uNewIndex] = reinterpret_cast<HANDLE>(extended->GetHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &source : loopSourceExs)
|
||||
for (AU_ITERATE_N(i, uCounterHandle))
|
||||
{
|
||||
source->OnPresleep();
|
||||
loopSourceExs[i]->OnPresleep();
|
||||
}
|
||||
|
||||
AuUInt32 uTimeout {};
|
||||
@ -83,21 +100,21 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
|
||||
DWORD ret;
|
||||
if (isWinLoop &&
|
||||
if (bIsWinLoop &&
|
||||
pMsgWaitForMultipleObjectsEx)
|
||||
{
|
||||
ret = pMsgWaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), uTimeout, QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_INPUTAVAILABLE | MWMO_ALERTABLE);
|
||||
ret = pMsgWaitForMultipleObjectsEx(uCounterFD, handleArray, uTimeout, QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_INPUTAVAILABLE | MWMO_ALERTABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ::WaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), false, uTimeout, true);
|
||||
ret = ::WaitForMultipleObjectsEx(uCounterFD, handleArray, false, uTimeout, true);
|
||||
}
|
||||
|
||||
bool error = ((ret == WAIT_TIMEOUT) ||
|
||||
(ret == WAIT_IO_COMPLETION) ||
|
||||
(ret == WAIT_FAILED));
|
||||
|
||||
bool isPump = WAIT_OBJECT_0 + handleArray.size() == ret;
|
||||
bool isPump = WAIT_OBJECT_0 + uCounterFD == ret;
|
||||
|
||||
AuUInt firstTriggered {};
|
||||
if (!error)
|
||||
@ -111,7 +128,7 @@ namespace Aurora::IO::Loop
|
||||
if (isPump)
|
||||
{
|
||||
// msg loop queue for trigger
|
||||
AuTryInsert(triggered, msgSource);
|
||||
AuTryInsert(triggered, pMsgSource);
|
||||
|
||||
if (!bAllowOthers)
|
||||
{
|
||||
@ -119,16 +136,18 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &source : loopSourceExs)
|
||||
for (AU_ITERATE_N(i, uCounterHandle))
|
||||
{
|
||||
auto &pSource = loopSourceExs[i];
|
||||
|
||||
if (!error)
|
||||
{
|
||||
AuUInt lastHandle {};
|
||||
bool wasTriggered {};
|
||||
|
||||
if (source->Singular())
|
||||
if (pSource->Singular())
|
||||
{
|
||||
auto handle = source->GetHandle();
|
||||
auto handle = pSource->GetHandle();
|
||||
if ((firstTriggered == handle) ||
|
||||
(bAllowOthers && WaitForSingleObject(reinterpret_cast<HANDLE>(handle), 0) == WAIT_OBJECT_0))
|
||||
{
|
||||
@ -138,7 +157,7 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &handle : source->GetHandles())
|
||||
for (const auto &handle : pSource->GetHandles())
|
||||
{
|
||||
if ((firstTriggered == handle) ||
|
||||
(bAllowOthers && WaitForSingleObject(reinterpret_cast<HANDLE>(handle), 0) == WAIT_OBJECT_0))
|
||||
@ -151,16 +170,16 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
|
||||
// notify the loopsource of ex, only signal once we've filtered the kernel signal
|
||||
if (wasTriggered && source->OnTrigger(lastHandle))
|
||||
if (wasTriggered && pSource->OnTrigger(lastHandle))
|
||||
{
|
||||
// pog
|
||||
AuTryInsert(triggered, source);
|
||||
AuTryInsert(triggered, pSource);
|
||||
}
|
||||
}
|
||||
|
||||
source->OnFinishSleep();
|
||||
pSource->OnFinishSleep();
|
||||
}
|
||||
|
||||
return triggered;
|
||||
return AuMove(triggered);
|
||||
}
|
||||
}
|
@ -36,19 +36,85 @@ namespace Aurora::IO::Loop
|
||||
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;
|
||||
|
||||
// fallback
|
||||
AuList<AuSPtr<ILoopSourceEx>> loopSourceExs1;
|
||||
AuList<AuSPtr<ILoopSourceEx>> loopSourceExs21;
|
||||
AuList<pollfd> handleArray1;
|
||||
AuList<AuPair<AuUInt, bool>> handleIndicies1;
|
||||
|
||||
// 4k~ of stack
|
||||
AuSPtr<ILoopSourceEx> loopSourceExs12[128];
|
||||
AuSPtr<ILoopSourceEx> loopSourceExs22[128];
|
||||
pollfd handleArray2[128];
|
||||
AuPair<AuUInt, bool> handleIndicies2[128];
|
||||
|
||||
// phead
|
||||
AuSPtr<ILoopSourceEx> * pLoopSourceExs1;
|
||||
AuSPtr<ILoopSourceEx> * pLoopSourceExs2;
|
||||
pollfd * pHandleArray;
|
||||
AuPair<AuUInt, bool> * pHandleIndicies;
|
||||
AuUInt32 uHandleOffset, uFDOffset, uHandleOffset2;
|
||||
|
||||
// length / size
|
||||
uHandleOffset = 0;
|
||||
uHandleOffset2 = 0;
|
||||
uFDOffset = 0;
|
||||
|
||||
// default heads
|
||||
pLoopSourceExs1 = loopSourceExs12;
|
||||
pLoopSourceExs2 = loopSourceExs22;
|
||||
pHandleArray = handleArray2;
|
||||
pHandleIndicies = handleIndicies2;
|
||||
|
||||
#define HANDLE_PUSH_CHILD_Z(value, aaa, bbb, ccc, ggg, FF) \
|
||||
{ \
|
||||
if (FF > AuArraySize(aaa)) \
|
||||
{ \
|
||||
ccc.push_back(value); \
|
||||
bbb = ccc.data(); \
|
||||
} \
|
||||
else if (FF == AuArraySize(aaa)) \
|
||||
{ \
|
||||
ccc.insert(ccc.begin(), &ggg[0], &ggg[AuArraySize(aaa)]); \
|
||||
ccc.push_back(value); \
|
||||
bbb = ccc.data(); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
bbb[FF] = value; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define HANDLE_PUSH_MAIN2(value) \
|
||||
HANDLE_PUSH_CHILD_Z(value, loopSourceExs22, pLoopSourceExs2, loopSourceExs21, pLoopSourceExs2, uCurHandle)
|
||||
|
||||
#define HANDLE_PUSH_MAIN(value, handle) \
|
||||
HANDLE_PUSH_CHILD_Z(value, loopSourceExs22, pLoopSourceExs1, loopSourceExs1, pLoopSourceExs1, handle)
|
||||
|
||||
#define HANDLE_PUSH_CHILD(value) \
|
||||
{ \
|
||||
auto uCurFD = uFDOffset++; \
|
||||
HANDLE_PUSH_CHILD_Z(value, loopSourceExs22, pHandleArray, handleArray1, handleArray2, uCurFD) \
|
||||
}
|
||||
|
||||
#define HANDLE_PUSH_CHILD2(value) \
|
||||
{ \
|
||||
HANDLE_PUSH_CHILD_Z(value, loopSourceExs22, pHandleIndicies, handleIndicies1, handleIndicies2, (uFDOffset - 1)) \
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
loopSourceExs.reserve(objects.size());
|
||||
loopSourceExs2.reserve(objects.size());
|
||||
handleArray.reserve(objects.size());
|
||||
if (AuArraySize(loopSourceExs22) < objects.size())
|
||||
{
|
||||
loopSourceExs1.reserve(objects.size());
|
||||
loopSourceExs21.reserve(objects.size());
|
||||
handleArray1.reserve(objects.size());
|
||||
handleIndicies1.reserve(triggered.size());
|
||||
}
|
||||
|
||||
triggered.reserve(triggered.size());
|
||||
handleIndicies.reserve(triggered.size());
|
||||
|
||||
for (const auto &source : objects)
|
||||
{
|
||||
@ -59,15 +125,17 @@ namespace Aurora::IO::Loop
|
||||
|
||||
if (auto extended = AuDynamicCast<ILoopSourceEx>(source))
|
||||
{
|
||||
loopSourceExs2.push_back(extended);
|
||||
auto uCurHandle = uHandleOffset++;
|
||||
|
||||
HANDLE_PUSH_MAIN2(extended)
|
||||
|
||||
if (extended->Singular())
|
||||
{
|
||||
auto handle = extended->GetHandle();
|
||||
auto handleWrite = extended->GetWriteHandle();
|
||||
|
||||
auto i = loopSourceExs.size();
|
||||
loopSourceExs.push_back(extended);
|
||||
auto i = uHandleOffset2++;
|
||||
HANDLE_PUSH_MAIN(extended, i);
|
||||
|
||||
if (handle != -1)
|
||||
{
|
||||
@ -76,8 +144,8 @@ namespace Aurora::IO::Loop
|
||||
poll.events = POLLIN;
|
||||
poll.revents = 0;
|
||||
|
||||
handleArray.push_back(poll);
|
||||
handleIndicies.push_back(AuMakePair(i, false));
|
||||
HANDLE_PUSH_CHILD(poll);
|
||||
HANDLE_PUSH_CHILD2(AuMakePair(i, false));
|
||||
}
|
||||
|
||||
if (handleWrite != -1)
|
||||
@ -87,8 +155,8 @@ namespace Aurora::IO::Loop
|
||||
poll.events = POLLOUT;
|
||||
poll.revents = 0;
|
||||
|
||||
handleArray.push_back(poll);
|
||||
handleIndicies.push_back(AuMakePair(i, true));
|
||||
HANDLE_PUSH_CHILD(poll);
|
||||
HANDLE_PUSH_CHILD2(AuMakePair(i, false));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -96,8 +164,8 @@ namespace Aurora::IO::Loop
|
||||
auto handles = extended->GetHandles();
|
||||
auto handlesWrite = extended->GetWriteHandles();
|
||||
|
||||
auto i = loopSourceExs.size();
|
||||
loopSourceExs.push_back(extended);
|
||||
auto i = uHandleOffset2++;
|
||||
HANDLE_PUSH_MAIN(extended, i);
|
||||
|
||||
for (const auto &handle : handles)
|
||||
{
|
||||
@ -111,8 +179,8 @@ namespace Aurora::IO::Loop
|
||||
poll.events = POLLIN;
|
||||
poll.revents = 0;
|
||||
|
||||
handleArray.push_back(poll);
|
||||
handleIndicies.push_back(AuMakePair(i, false));
|
||||
HANDLE_PUSH_CHILD(poll);
|
||||
HANDLE_PUSH_CHILD2(AuMakePair(i, false));
|
||||
}
|
||||
|
||||
for (const auto &handle : handlesWrite)
|
||||
@ -127,8 +195,8 @@ namespace Aurora::IO::Loop
|
||||
poll.events = POLLOUT;
|
||||
poll.revents = 0;
|
||||
|
||||
handleArray.push_back(poll);
|
||||
handleIndicies.push_back(AuMakePair(i, true));
|
||||
HANDLE_PUSH_CHILD(poll);
|
||||
HANDLE_PUSH_CHILD2(AuMakePair(i, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,9 +207,10 @@ namespace Aurora::IO::Loop
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const auto &source : loopSourceExs2)
|
||||
// must be 1:1 - do not mess with
|
||||
for (AU_ITERATE_N(i, uHandleOffset))
|
||||
{
|
||||
source->OnPresleep();
|
||||
pLoopSourceExs2[i]->OnPresleep();
|
||||
}
|
||||
|
||||
AuUInt32 uTimeout {};
|
||||
@ -161,29 +230,30 @@ namespace Aurora::IO::Loop
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = poll(handleArray.data(), handleArray.size(), uTimeout);
|
||||
ret = poll(pHandleArray, uFDOffset, uTimeout);
|
||||
uTimeout = 0;
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
for (AU_ITERATE_N(i, handleArray.size()))
|
||||
for (AU_ITERATE_N(i, uFDOffset))
|
||||
{
|
||||
if (!handleArray[i].revents)
|
||||
if (!pHandleArray[i].revents)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto uIndex = AuGet<0>(handleIndicies[i]);
|
||||
auto bRead = AuGet<1>(handleIndicies[i]);
|
||||
auto pLoopSource = AuExchange(loopSourceExs[uIndex], nullptr);
|
||||
auto uIndex = AuGet<0>(pHandleIndicies[i]);
|
||||
auto bRead = AuGet<1>(pHandleIndicies[i]);
|
||||
auto pLoopSource = AuExchange(pLoopSourceExs1[uIndex], nullptr);
|
||||
if (!pLoopSource)
|
||||
{
|
||||
// TODO: notify other? special types go here?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pLoopSource->OnTrigger(handleArray[i].fd))
|
||||
if (!pLoopSource->OnTrigger(pHandleArray[i].fd))
|
||||
{
|
||||
loopSourceExs[uIndex] = pLoopSource;
|
||||
pLoopSourceExs1[uIndex] = pLoopSource;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -199,9 +269,10 @@ namespace Aurora::IO::Loop
|
||||
while (ret == -1 &&
|
||||
errno == EINTR);
|
||||
|
||||
for (const auto &source : loopSourceExs2)
|
||||
// must be 1:1 - do not mess with
|
||||
for (AU_ITERATE_N(i, uHandleOffset))
|
||||
{
|
||||
source->OnFinishSleep();
|
||||
pLoopSourceExs2[i]->OnFinishSleep();
|
||||
}
|
||||
|
||||
// TODO: ugly workaround (see: LSFromHdNonblocking rationale) for an ugly TODO issue implicating all targets (see public Loop.hpp)
|
||||
@ -214,7 +285,7 @@ namespace Aurora::IO::Loop
|
||||
#endif
|
||||
}
|
||||
|
||||
return triggered;
|
||||
return AuMove(triggered);
|
||||
#endif
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user