/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: WaitSingle.Unix.cpp Date: 2022-4-4 Author: Reece ***/ #include #include "WaitSingle.hpp" #include #if defined(AURORA_IS_LINUX_DERIVED) #include #endif namespace Aurora::IO::Loop { bool WaitSingleGeneric::WaitForAtleastOne(AuUInt32 timeout, const AuList &handles, const AuList &handlesWrite, AuUInt &one, AuUInt &two, bool bNoAlert) { fd_set readSet, writeSet; AuUInt maxHandle {}; struct timeval tv {}; int active; if (!bNoAlert) { // TODO: IO SUBMIT HOOK } FD_ZERO(&readSet); FD_ZERO(&writeSet); if (timeout) { AuTime::ms2tv(&tv, timeout); } for (const auto i : handles) { if (i == -1) continue; FD_SET(i, &readSet); maxHandle = AuMax(maxHandle, i + 1); } for (const auto i : handlesWrite) { if (i == -1) continue; FD_SET(i, &writeSet); maxHandle = AuMax(maxHandle, i + 1); } active = select(maxHandle, handles.size() ? &readSet : nullptr, handlesWrite.size() ? &writeSet : nullptr, nullptr, timeout == AuUInt32(-1) ? nullptr : &tv); #if defined(AURORA_IS_LINUX_DERIVED) if (!bNoAlert) { (void)IO::UNIX::LinuxOverlappedYield(); } #endif if (active == -1) { // todo push error return false; } if (active == 0) { return false; } for (const auto i : handles) { if (!FD_ISSET(i, &readSet)) { continue; } one = i; break; } for (const auto i : handlesWrite) { if (!FD_ISSET(i, &writeSet)) { continue; } two = i; break; } return true; } // TODO: pass u64 end time, use pselect when available, fallback to this old logic // LinuxOverlappedWaitForOne doesnt understand yields, we have a specific yield op like the thread waitables, but that doesnt help with a single fd // pselect doesnt help much considering we need monotonic clock sleeps // also when we get around to freebsd support, we need to append one to the select array to handle a kqueue of thread local APCs + transactions // this is a mess and will continue to be a mess bool WaitSingleGeneric::WaitForOne(AuUInt32 timeout, AuUInt read, AuUInt write, bool bNoAlert) { fd_set readSet, writeSet; struct timeval tv {}; int maxFd {}; int active; // TODO: see todo #if defined(AURORA_IS_LINUX_DERIVED) if (!bNoAlert && timeout) { bool bWriteTriggered, bReadTriggered; if (IO::UNIX::LinuxOverlappedWaitForOne(timeout == AuUInt32(-1) ? 0 : timeout, read, write, bReadTriggered, bWriteTriggered)) { if (!bWriteTriggered && !bReadTriggered) { return false; } return true; } } #endif FD_ZERO(&readSet); FD_ZERO(&writeSet); if (timeout) { AuTime::ms2tv(&tv, timeout); } if (read != -1) { maxFd = read + 1; FD_SET(read, &readSet); } if (write != -1) { FD_SET(write, &writeSet); maxFd = AuMax(maxFd, int(write) + 1); } active = select(maxFd, read != -1 ? &readSet : nullptr, write != -1 ? &writeSet : nullptr, nullptr, timeout == AuUInt32(-1) ? nullptr : &tv); // TODO: see todo #if defined(AURORA_IS_LINUX_DERIVED) if (!bNoAlert && !timeout) { (void)IO::UNIX::LinuxOverlappedYield(); } #endif if (active == 0) { return false; } if (active == -1) { // todo push error return false; } return active == 1; } void WaitSingleGeneric::OnPresleep() { } void WaitSingleGeneric::OnFinishSleep() { } ELoopSource WaitSingleGeneric::GetType() { return ELoopSource::eSourceInternalReserved1; } }