/*** 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::Loop { AUKN_SYM AuList> WaitMultipleOrObjects(const AuList> &objects, AuUInt32 timeout) { 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 {}; } for (const auto &source : loopSourceExs) { source->OnPresleep(); } DWORD ret; if (isWinLoop) { ret = ::MsgWaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), timeout ? timeout : INFINITE, QS_ALLPOSTMESSAGE | QS_ALLINPUT | QS_ALLEVENTS, MWMO_INPUTAVAILABLE | MWMO_ALERTABLE); } else { ret = ::WaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), false, timeout ? timeout : INFINITE, 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]); } } for (const auto &source : loopSourceExs) { if (!error) { AuUInt lastHandle {}; bool wasTriggered {}; // first handle in group for (const auto &handle : source->GetHandles()) { if ((firstTriggered == handle) || (WaitForSingleObject(reinterpret_cast(handle), 0) == WAIT_OBJECT_0)) { lastHandle = handle; wasTriggered = true; continue; } } // 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(); } if (isPump) { // msg loop queue for trigger AuTryInsert(triggered, msgSource); } return triggered; } }