200 lines
6.4 KiB
C++
200 lines
6.4 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: Loop.Unix.cpp
|
|
Date: 2021-10-1
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "Loop.Unix.hpp"
|
|
#include "ILoopSourceEx.hpp"
|
|
#include <poll.h>
|
|
|
|
namespace Aurora::IO::Loop
|
|
{
|
|
AuList<AuSPtr<ILoopSource>> WaitMultipleOrObjects(const AuList<AuSPtr<ILoopSource>> &objects, bool bZeroTick, AuUInt32 dwTimeoutReq, bool bAllowOthers, bool &bTooMany)
|
|
{
|
|
#if defined(AURORA_HAS_NO_POSIX_POLL)
|
|
// do the WinNT falllback into loop queue.
|
|
//
|
|
// loop queues should have long term persistency in a user-space ABI (kqueue) or in the kernel (epoll)
|
|
// they may take longer to setup, may seem wasteful to create and throw away, but it's probably the best we can do under BSD kernels.
|
|
// why? kevents exist for posix aio objects. they dont use fds.
|
|
//
|
|
// BSDs with posix AIO based async file transactions, >2.2 linux kernels, macos with corefoundation interop with kqueues, and other posix kernels with alternative aio will probably need
|
|
// need to use the win32 64 <= handles path.
|
|
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;
|
|
|
|
try
|
|
{
|
|
loopSourceExs.reserve(objects.size());
|
|
loopSourceExs2.reserve(objects.size());
|
|
handleArray.reserve(objects.size());
|
|
triggered.reserve(triggered.size());
|
|
handleIndicies.reserve(triggered.size());
|
|
|
|
for (const auto &source : objects)
|
|
{
|
|
if (!source)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (auto extended = AuDynamicCast<ILoopSourceEx>(source))
|
|
{
|
|
loopSourceExs2.push_back(extended);
|
|
|
|
if (extended->Singular())
|
|
{
|
|
auto handle = extended->GetHandle();
|
|
auto handleWrite = extended->GetWriteHandle();
|
|
|
|
auto i = loopSourceExs.size();
|
|
loopSourceExs.push_back(extended);
|
|
|
|
if (handle != -1)
|
|
{
|
|
pollfd poll;
|
|
poll.fd = handle;
|
|
poll.events = POLLIN;
|
|
poll.revents = 0;
|
|
|
|
handleArray.push_back(poll);
|
|
handleIndicies.push_back(AuMakePair(i, false));
|
|
}
|
|
|
|
if (handleWrite != -1)
|
|
{
|
|
pollfd poll;
|
|
poll.fd = handleWrite;
|
|
poll.events = POLLOUT;
|
|
poll.revents = 0;
|
|
|
|
handleArray.push_back(poll);
|
|
handleIndicies.push_back(AuMakePair(i, true));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto handles = extended->GetHandles();
|
|
auto handlesWrite = extended->GetWriteHandles();
|
|
|
|
auto i = loopSourceExs.size();
|
|
loopSourceExs.push_back(extended);
|
|
|
|
for (const auto &handle : handles)
|
|
{
|
|
pollfd poll;
|
|
if (handle == -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
poll.fd = handle;
|
|
poll.events = POLLIN;
|
|
poll.revents = 0;
|
|
|
|
handleArray.push_back(poll);
|
|
handleIndicies.push_back(AuMakePair(i, false));
|
|
}
|
|
|
|
for (const auto &handle : handlesWrite)
|
|
{
|
|
pollfd poll;
|
|
if (handle == -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
poll.fd = handle;
|
|
poll.events = POLLOUT;
|
|
poll.revents = 0;
|
|
|
|
handleArray.push_back(poll);
|
|
handleIndicies.push_back(AuMakePair(i, true));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
for (const auto &source : loopSourceExs2)
|
|
{
|
|
source->OnPresleep();
|
|
}
|
|
|
|
AuUInt32 uTimeout {};
|
|
if (bZeroTick)
|
|
{
|
|
uTimeout = 0;
|
|
}
|
|
else if (!dwTimeoutReq)
|
|
{
|
|
uTimeout = -1;
|
|
}
|
|
else
|
|
{
|
|
uTimeout = dwTimeoutReq;
|
|
}
|
|
|
|
int ret;
|
|
do
|
|
{
|
|
ret = poll(handleArray.data(), handleArray.size(), uTimeout);
|
|
uTimeout = 0;
|
|
|
|
if (ret > 0)
|
|
{
|
|
for (AU_ITERATE_N(i, handleArray.size()))
|
|
{
|
|
if (!handleArray[i].revents)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto uIndex = AuGet<0>(handleIndicies[i]);
|
|
auto bRead = AuGet<1>(handleIndicies[i]);
|
|
auto pLoopSource = AuExchange(loopSourceExs[uIndex], nullptr);
|
|
if (!pLoopSource)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!pLoopSource->OnTrigger(handleArray[i].fd))
|
|
{
|
|
loopSourceExs[uIndex] = pLoopSource;
|
|
continue;
|
|
}
|
|
|
|
triggered.push_back(pLoopSource);
|
|
|
|
if (!bAllowOthers)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (ret == -1 &&
|
|
errno == EINTR);
|
|
|
|
for (const auto &source : loopSourceExs2)
|
|
{
|
|
source->OnFinishSleep();
|
|
}
|
|
|
|
return triggered;
|
|
#endif
|
|
}
|
|
} |