#include "Stroika/Foundation/StroikaPreComp.h"#include <version>#include "Stroika/Foundation/Common/Common.h"#include "Stroika/Foundation/Containers/Collection.h"#include "Stroika/Foundation/Containers/Set.h"#include "Stroika/Foundation/Debug/AssertExternallySynchronizedChecker.h"#include "Stroika/Foundation/Execution/Synchronized.h"#include "Stroika/Foundation/IO/Network/Socket.h"#include "Stroika/Foundation/Time/Duration.h"#include "WaitForIOReady.inl"Go to the source code of this file.
Classes | |
| class | Stroika::Foundation::Execution::WaitForIOReady_Support::EventFD |
| class | Stroika::Foundation::Execution::WaitForIOReady< T, TRAITS > |
Namespaces | |
| namespace | Stroika::Foundation |
| namespace | Stroika::Foundation::Execution |
Macros | |
| #define | qStroika_Foundation_Execution_WaitForIOReady_UseStopTokenAbortWakeup 0 |
| #define | qStroika_Foundation_Execution_WaitForIOReady_UsePPoll 0 |
Typedefs | |
| using | Stroika::Foundation::Execution::WaitForIOReady_Support::SDKPollableType = int |
Variables | |
| static Time::DurationSeconds | Stroika::Foundation::Execution::WaitForIOReady_Support::sPollWaitChunkTime {3s} |
WaitForIOReady utility - portably provide facility to check a bunch of file descriptors/sockets if input is ready (like select, epoll, WaitForMutlipleObjects, etc)
Definition in file WaitForIOReady.h.
| #define qStroika_Foundation_Execution_WaitForIOReady_UseStopTokenAbortWakeup 0 |
Wake a pending wait through the waiting thread's std::stop_token, instead of depending on the thread-interrupt signal (POSIX) or APC (Windows) to interrupt the underlying poll () call.
The interrupt signal cannot carry this reliably. Its whole effect is the EINTR it causes in a call that is already in flight, so a signal delivered while the thread is still setting up its poll set runs the (deliberately empty) handler and is spent, having interrupted nothing - and the thread then sleeps out its entire timeout. A std::stop_callback has the property the signal lacks: it is guaranteed to run, and to run DURING ITS OWN CONSTRUCTION if stop was already requested. Registering one to Set () a pollable EventFD, with that EventFD in the poll set, therefore leaves no window - however the abort and the wait are ordered, the descriptor ends up readable and poll () returns.
Thread::Abort () already calls stop_source::request_stop (), so nothing on the aborting side changes.
FIRST choice of three, because it is the only one that is portable - it covers Windows and macOS as well as Linux.
Definition at line 58 of file WaitForIOReady.h.
| #define qStroika_Foundation_Execution_WaitForIOReady_UsePPoll 0 |
SECOND choice, where the stop_token wakeup is unavailable: use ppoll () rather than poll (), blocking the thread-interrupt signal across the setup window and handing the original mask to the wait, which unblocks it atomically for exactly the duration of the wait. An abort arriving anywhere in the window then leaves the signal PENDING rather than spending it, and it fires the instant ppoll () unblocks it.
This closes the race just as completely as the stop_token wakeup does, and it is worth having as well because the two are available in DIFFERENT configurations: ppoll () is glibc, so it does not care which C++ standard library is in use, while __cpp_lib_jthread is undefined for every libc++ before LLVM 20. So the clang++-NN-*-libc++ configurations get this one and not the stop_token path.
Defined as 0 whenever the stop_token wakeup is available, so that exactly one mechanism is in play.
Definition at line 80 of file WaitForIOReady.h.
| using Stroika::Foundation::Execution::WaitForIOReady_Support::SDKPollableType = typedef int |
This is the underlying native type 'HighLevelType objects must be converted to in order to be used with the operating-system poll/select feature.
Definition at line 127 of file WaitForIOReady.h.
|
static |
LAST choice of the three wakeup mechanisms, used only where neither the stop_token wakeup nor ppoll () is available. There, the wait is broken into chunks this long, re-checking for thread interruption between them.
This is NOT hypothetical, despite being the fallback: macOS has no ppoll () at all (the UsePPoll default requires linux), and Apple's libc++ had no jthread before Xcode 26 - measured 2026-09-10, Xcode 15 and 16 lack __cpp_lib_jthread while 26.3 has it. So every XCode <= 16 build lands here, which includes the MacOS-15-XCode-16.4 CI job that runs on every push. Verified independently by forcing both macros to 0 on Linux/g++: all 54 regression tests pass.
Unlike the other two, this only BOUNDS a lost wakeup rather than preventing one: an abort whose signal was spent before the wait began costs one chunk instead of the whole timeout. Nothing better is available in that configuration. It is deliberately NOT used when either other mechanism is in play - there, waking early could only mask a failure of the mechanism that is supposed to be doing the work, which is exactly how such a failure goes unnoticed.
Smaller means an abort is noticed sooner, at the cost of more wakeups. Must be > 0.
Definition at line 117 of file WaitForIOReady.h.