135 lines
3.9 KiB
C++
135 lines
3.9 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: Loop.NT.cpp
|
|
Date: 2021-10-1
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "Loop.NT.hpp"
|
|
#include "ILoopSourceEx.hpp"
|
|
#include "LSWin32.NT.hpp"
|
|
|
|
namespace Aurora::IO::Loop
|
|
{
|
|
AUKN_SYM AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, AuUInt32 timeout)
|
|
{
|
|
bool isWinLoop;
|
|
AuList<AuSPtr<ILoopSourceEx>> loopSourceExs;
|
|
AuList<AuSPtr<ILoopSource>> triggered;
|
|
AuList<HANDLE> handleArray;
|
|
AuSPtr<ILoopSource> 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<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 {};
|
|
}
|
|
|
|
for (const auto &source : loopSourceExs)
|
|
{
|
|
source->OnPresleep();
|
|
}
|
|
|
|
DWORD ret;
|
|
if (isWinLoop)
|
|
{
|
|
ret = ::MsgWaitForMultipleObjectsEx(handleArray.size(), handleArray.data(), timeout ? timeout : INFINITE, QS_ALLPOSTMESSAGE | QS_ALLINPUT, 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<AuUInt>(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>(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;
|
|
}
|
|
} |