/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Loop.NT.cpp Date: 2021-10-1 Author: Reece ***/ #include #include "Loop.NT.hpp" #include "ILoopSourceEx.hpp" #include "LSWin32.NT.hpp" namespace Aurora::IO::Loop { AuList> WaitMultipleOrObjects(const AuList> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany) { bool isWinLoop; AuList> loopSourceExs; AuList> triggered; AuList handleArray; AuSPtr msgSource; 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) { bTooMany = true; return {}; } for (const auto &source : loopSourceExs) { source->OnPresleep(); } AuUInt32 uTimeout {}; if (!bZeroTick) { uTimeout = dwTimeoutReq ? dwTimeoutReq : INFINITE; } DWORD ret; if (isWinLoop && pMsgWaitForMultipleObjectsEx) { ret = pMsgWaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), uTimeout, QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_INPUTAVAILABLE | MWMO_ALERTABLE); } else { ret = ::WaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), false, uTimeout, true); } bool error = ((ret == WAIT_TIMEOUT) || (ret == WAIT_IO_COMPLETION) || (ret == WAIT_FAILED)); bool isPump = WAIT_OBJECT_0 + handleArray.size() == ret; AuUInt firstTriggered {}; if (!error) { if (!isPump) { firstTriggered = reinterpret_cast(handleArray[ret - WAIT_OBJECT_0]); } } if (isPump) { // msg loop queue for trigger AuTryInsert(triggered, msgSource); if (!bAllowOthers) { error = true; } } for (const auto &source : loopSourceExs) { if (!error) { AuUInt lastHandle {}; bool wasTriggered {}; if (source->Singular()) { auto handle = source->GetHandle(); if ((firstTriggered == handle) || (bAllowOthers && WaitForSingleObject(reinterpret_cast(handle), 0) == WAIT_OBJECT_0)) { lastHandle = handle; wasTriggered = true; } } else { for (const auto &handle : source->GetHandles()) { if ((firstTriggered == handle) || (bAllowOthers && WaitForSingleObject(reinterpret_cast(handle), 0) == WAIT_OBJECT_0)) { lastHandle = handle; wasTriggered = true; break; } } } // notify the loopsource of ex, only signal once we've filtered the kernel signal if (wasTriggered && source->OnTrigger(lastHandle)) { // pog AuTryInsert(triggered, source); } } source->OnFinishSleep(); } return triggered; } }