Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
UpdatableWaitForIOReady.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_UpdatableWaitForIOReady_h_
5#define _Stroika_Foundation_Execution_UpdatableWaitForIOReady_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
10
11/**
12 * \file
13 *
14 */
15
17
18 /**
19 * \brief Simple wrapper on WaitForIOReady (POSIX select/poll/etc API) - except it allows for the list
20 * if polled descriptors to be updated dynamically from any thread, and have that automatically wakeup any
21 * waiters to restart waiting
22 *
23 * \note Calls to Add/Remove/clear/SetDescriptors () cause Wait() to return prematurely, almost as if a timeout, except that
24 * a timeout exception won't be caused by this return (per-se). This means wait can legitimately return zero items
25 * without throwing a timeout exception
26 *
27 * \par Example Usage
28 * \code
29 * ...INSIDE CLASS DECLARATION
30 * struct MyWaitForIOReady_Traits_ {
31 * using HighLevelType = shared_ptr<Connection>;
32 * static inline auto GetSDKPollable (const HighLevelType& t)
33 * {
34 * return t->GetSocket ().GetNativeSocket ();
35 * }
36 * };
37 * UpdatableWaitForIOReady<shared_ptr<Connection>, MyWaitForIOReady_Traits_> fSockSetPoller_{};
38 * ...
39 *
40 * loopWaitingForWorkTodo()
41 * while (true) {
42 * for (shared_ptr<Connection> readyConnection : fSockSetPoller_.WaitQuietly ()) {
43 * ... handle ready connection
44 *
45 * ... elsewhere
46 * onAccept(shared_ptr<Connection) c) {
47 * fSockSetPoller_.Add (c);
48 * }
49 *
50 * \endcode
51 *
52 * \note ***Performance: linear in the number of descriptors, on EVERY wait.*** Each wait snapshots the whole
53 * list and polls all of it, and each Add/Remove wakes the waiter to do that again - fine for tens of
54 * descriptors, not for thousands. epoll (Linux) and kqueue (macOS/BSD) keep the list in the kernel
55 * instead, so a wait costs only what is ready, and could go behind this same API.
56 *
57 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
58 *
59 * \todo @todo Back this with epoll/kqueue (and perhaps an optional one-shot mode), should anything need it to
60 * scale. Design and performance evaluation, comparison with other libraries and APIs, and the options:
61 * https://github.com/SophistSolutions/Stroika/issues/1176
62 *
63 * \todo @todo DECIDE IF T is a KEY - that is - if allowed to appear more than once in the list.
64 * Update the logic for Add/Remove and constructors accordingly!!!
65 * PROBABLY best definition is that its a KEY, but you can in constructor/add pass in more than once, and they get merged together like a set.
66 * (NOTE - NYI but easy). Then Remove functions need overloads letting you specify the POLL params too.
67 *
68 */
69 template <typename T = WaitForIOReady_Support::SDKPollableType, typename TRAITS = WaitForIOReady_Support::WaitForIOReady_Traits<T>>
70 class UpdatableWaitForIOReady : public WaitForIOReady_Support::WaitForIOReady_Base {
71 public:
72 /**
73 */
76 UpdatableWaitForIOReady (const Traversal::Iterable<pair<T, TypeOfMonitorSet>>& fds);
77 UpdatableWaitForIOReady (const Traversal::Iterable<T>& fds, const TypeOfMonitorSet& flags = kDefaultTypeOfMonitor);
78 UpdatableWaitForIOReady (const T& fd, const TypeOfMonitorSet& flags = kDefaultTypeOfMonitor);
79
80 public:
81 ~UpdatableWaitForIOReady () = default;
82
83 public:
84 nonvirtual UpdatableWaitForIOReady& operator= (const UpdatableWaitForIOReady&) = delete;
85
86 public:
87 /**
88 */
89 nonvirtual void Add (T fd, const TypeOfMonitorSet& flags = kDefaultTypeOfMonitor);
90
91 public:
92 /**
93 */
94 nonvirtual void AddAll (const Traversal::Iterable<pair<T, TypeOfMonitorSet>>& fds);
95 nonvirtual void AddAll (const Traversal::Iterable<T>& fds, const TypeOfMonitorSet& flags = kDefaultTypeOfMonitor);
96
97 public:
98 /**
99 */
100 nonvirtual void Remove (T fd);
101
102 public:
103 /**
104 */
105 nonvirtual void RemoveAll (const Traversal::Iterable<T>& fds);
106
107 public:
108 /**
109 */
110 nonvirtual Containers::Collection<pair<T, TypeOfMonitorSet>> GetDescriptors () const;
111
112 public:
113 /**
114 */
115 nonvirtual void SetDescriptors (const Traversal::Iterable<pair<T, TypeOfMonitorSet>>& fds);
116 nonvirtual void SetDescriptors (const Traversal::Iterable<T>& fds, const TypeOfMonitorSet& flags = kDefaultTypeOfMonitor);
117
118 public:
119 /**
120 * Clear the set of watched file descriptors, and cause any waiters to wake immediately to re-examine the situation.
121 */
122 nonvirtual void clear ();
123
124 public:
125 /*
126 * Waits the given amount of time, and returns as soon as any one (or more) requires service (see TypeOfMonitor), or possibly zero if pollable2Wakeup Set.
127 *
128 * \note Throws a timeout on timeout - @see Execution::ThrowError (errc::timed_out).
129 *
130 * \note ***Cancelation Point***
131 *
132 * @see WaitQuietly
133 * @see WaitUntil
134 * @see WaitQuietlyUntil
135 */
136 nonvirtual Containers::Set<T> Wait (Time::DurationSeconds waitFor = Time::kInfinity);
137 nonvirtual Containers::Set<T> Wait (const Time::Duration& waitFor);
138
139 public:
140 /*
141 * Waits the given amount of time, and returns as soon as any one (or more) requires service (see TypeOfMonitor), or possibly zero if pollable2Wakeup Set.
142 *
143 * Returns set of file descriptors which are ready, or empty set if timeout.
144 *
145 * \note ***Cancelation Point***
146 *
147 * @see Wait
148 * @see WaitUntil
149 * @see WaitQuietlyUntil
150 */
151 nonvirtual Containers::Set<T> WaitQuietly (Time::DurationSeconds waitFor = Time::kInfinity);
152 nonvirtual Containers::Set<T> WaitQuietly (const Time::Duration& waitFor);
153
154 public:
155 /*
156 * Waits until the given timeoutAt, and returns as soon as any one (or more) requires service (see TypeOfMonitor), or possibly zero if pollable2Wakeup Set.
157 *
158 * \note Throws a timeout on timeout - @see Execution::ThrowError (errc::timed_out).
159 *
160 * \note ***Cancelation Point***
161 *
162 * @see Wait
163 * @see WaitQuietly
164 * @see WaitQuietlyUntil
165 */
166 nonvirtual Containers::Set<T> WaitUntil (Time::TimePointSeconds timeoutAt = Time::TimePointSeconds{Time::kInfinity});
167
168 public:
169 /*
170 * Waits until the given timeoutAt, and returns as soon as any one (or more) requires service (see TypeOfMonitor), or possibly zero if pollable2Wakeup Set.
171 *
172 * Returns set of file descriptors which are ready, or an empty set if time expired before any became ready.
173 *
174 * if timeout is <= 0, this will not wait (but may still find some file descriptors ready).
175 *
176 * \note ***Cancelation Point***
177 *
178 * @see Wait
179 * @see WaitQuietly
180 * @see WaitUntil
181 */
182 nonvirtual Containers::Set<T> WaitQuietlyUntil (Time::TimePointSeconds timeoutAt = Time::TimePointSeconds{Time::kInfinity});
183
184 private:
185 /*
186 * note: lock design - keep short locks on fData_, and make a new 'waiter' with a copy of the FDs list (COW copy)
187 * so don't hold fData synchronized lock during wait on 'select'
188 */
189
190 private:
191 nonvirtual WaitForIOReady<T, TRAITS> mkWaiter_ ();
192
193 private:
194 unique_ptr<WaitForIOReady_Support::EventFD> fEventFD_;
195 pair<SDKPollableType, TypeOfMonitorSet> fPollable2Wakeup_;
197 };
198
199}
200
201/*
202 ********************************************************************************
203 ***************************** Implementation Details ***************************
204 ********************************************************************************
205 */
206#include "UpdatableWaitForIOReady.inl"
207
208#endif /*_Stroika_Foundation_Execution_UpdatableWaitForIOReady_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
Simple wrapper on WaitForIOReady (POSIX select/poll/etc API) - except it allows for the list if polle...
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:234