@@ -165,13 +165,37 @@ class AsioConditionVariable
165
165
/* *
166
166
* I/O timeout emulator
167
167
*
168
+ * This class provides a workaround for Boost.ASIO's lack of built-in timeout support.
169
+ * While Boost.ASIO handles asynchronous operations, it does not natively support timeouts for these operations.
170
+ * This class uses a boost::asio::deadline_timer to emulate a timeout by scheduling a callback to be triggered
171
+ * after a specified duration, effectively adding timeout behavior where none exists.
172
+ * The callback is executed within the provided strand, ensuring thread-safety.
173
+ *
174
+ * The constructor returns immediately after scheduling the timeout callback.
175
+ * The callback itself is invoked asynchronously when the timeout occurs.
176
+ * This allows the caller to continue execution while the timeout is running in the background.
177
+ *
178
+ * The class provides a Cancel() method to unschedule any pending callback. If the callback has already been run,
179
+ * calling Cancel() has no effect. This method can be used to abort the timeout early if the monitored operation
180
+ * completes before the callback has been run. The Timeout destructor also automatically cancels any pending callback.
181
+ * A callback is considered pending even if the timeout has already expired,
182
+ * but the callback has not been executed yet due to a busy strand.
183
+ *
168
184
* @ingroup base
169
185
*/
170
186
class Timeout
171
187
{
172
188
public:
173
189
using Timer = boost::asio::deadline_timer;
174
190
191
+ /* *
192
+ * Schedules onTimeout to be triggered after timeoutFromNow on strand.
193
+ *
194
+ * @param strand The strand in which the callback will be executed.
195
+ * The caller must also run in this strand, as well as Cancel() and the destructor!
196
+ * @param timeoutFromNow The duration after which the timeout callback will be triggered.
197
+ * @param onTimeout The callback to invoke when the timeout occurs.
198
+ */
175
199
template <class OnTimeout >
176
200
Timeout (boost::asio::io_context::strand& strand, const Timer::duration_type& timeoutFromNow, OnTimeout onTimeout)
177
201
: m_Timer(strand.context(), timeoutFromNow), m_Cancelled(Shared<Atomic<bool >>::Make(false ))
@@ -192,6 +216,11 @@ class Timeout
192
216
Timeout& operator =(const Timeout&) = delete ;
193
217
Timeout& operator =(Timeout&&) = delete ;
194
218
219
+ /* *
220
+ * Cancels any pending timeout callback.
221
+ *
222
+ * Must be called in the strand in which the callback was scheduled!
223
+ */
195
224
~Timeout ()
196
225
{
197
226
Cancel ();
@@ -201,6 +230,14 @@ class Timeout
201
230
202
231
private:
203
232
Timer m_Timer;
233
+
234
+ /* *
235
+ * Indicates whether the Timeout has been cancelled.
236
+ *
237
+ * This must be Shared<> between the lambda in the constructor and Cancel() for the case
238
+ * the destructor calls Cancel() while the lambda is already queued in the strand.
239
+ * The whole Timeout instance can't be kept alive by the lambda because this would delay the destructor.
240
+ */
204
241
Shared<Atomic<bool >>::Ptr m_Cancelled;
205
242
};
206
243
0 commit comments