diff --git a/Include/Aurora/IO/Loop/Loop.hpp b/Include/Aurora/IO/Loop/Loop.hpp index 89ba7232..4da3aba3 100644 --- a/Include/Aurora/IO/Loop/Loop.hpp +++ b/Include/Aurora/IO/Loop/Loop.hpp @@ -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 diff --git a/Source/IO/Loop/Loop.NT.cpp b/Source/IO/Loop/Loop.NT.cpp index d62df28b..d4f171f3 100644 --- a/Source/IO/Loop/Loop.NT.cpp +++ b/Source/IO/Loop/Loop.NT.cpp @@ -14,59 +14,76 @@ namespace Aurora::IO::Loop { AuList> WaitMultipleOrObjects(const AuList> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany) { - bool isWinLoop; - AuList> loopSourceExs; + bool bIsWinLoop; + AuSPtr loopSourceExs[MAXIMUM_WAIT_OBJECTS]; + HANDLE handleArray[MAXIMUM_WAIT_OBJECTS]; + AuUInt32 uCounterHandle, uCounterFD; + AuSPtr pMsgSource; AuList> triggered; - AuList handleArray; - AuSPtr 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(source)) - { - loopSourceExs.push_back(extended); - if (extended->Singular()) - { - handleArray.push_back(reinterpret_cast(extended->GetHandle())); - } - else - { - for (const auto &handle : extended->GetHandles()) - { - handleArray.push_back(reinterpret_cast(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(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(extended->GetHandle()); + } + else + { + for (const auto &handle : extended->GetHandles()) + { + auto uNewIndex = uCounterFD++; + if (uNewIndex == MAXIMUM_WAIT_OBJECTS) + { + bTooMany = true; + return {}; + } + handleArray[uNewIndex] = reinterpret_cast(extended->GetHandle()); + } + } + } } for (const auto &source : loopSourceExs) @@ -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), 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), 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); } } \ No newline at end of file diff --git a/Source/IO/Loop/Loop.Unix.cpp b/Source/IO/Loop/Loop.Unix.cpp index 0dbb4e51..47a5a099 100644 --- a/Source/IO/Loop/Loop.Unix.cpp +++ b/Source/IO/Loop/Loop.Unix.cpp @@ -36,19 +36,85 @@ namespace Aurora::IO::Loop bTooMany = true; return false; #else - AuList> loopSourceExs; - AuList> loopSourceExs2; AuList> triggered; - AuList handleArray; - AuList> handleIndicies; + + // fallback + AuList> loopSourceExs1; + AuList> loopSourceExs21; + AuList handleArray1; + AuList> handleIndicies1; + + // 4k~ of stack + AuSPtr loopSourceExs12[128]; + AuSPtr loopSourceExs22[128]; + pollfd handleArray2[128]; + AuPair handleIndicies2[128]; + + // phead + AuSPtr * pLoopSourceExs1; + AuSPtr * pLoopSourceExs2; + pollfd * pHandleArray; + AuPair * 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(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 } } \ No newline at end of file