BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_chronoutil.h
Go to the documentation of this file.
1/// @file bslmt_chronoutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_chronoutil.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_CHRONOUTIL
9#define INCLUDED_BSLMT_CHRONOUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_chronoutil bslmt_chronoutil
15/// @brief Provide utilities related to threading with C++11-style clocks.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_chronoutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_chronoutil-purpose"> Purpose</a>
25/// * <a href="#bslmt_chronoutil-classes"> Classes </a>
26/// * <a href="#bslmt_chronoutil-description"> Description </a>
27/// * <a href="#bslmt_chronoutil-usage"> Usage </a>
28/// * <a href="#bslmt_chronoutil-prologue-create-a-synchronization-primitive"> Prologue: Create a Synchronization Primitive </a>
29/// * <a href="#bslmt_chronoutil-example-1-using-bslmt-chronoutil-timedwait"> Example 1: Using bslmt::ChronoUtil::timedWait </a>
30///
31/// # Purpose {#bslmt_chronoutil-purpose}
32/// Provide utilities related to threading with C++11-style clocks.
33///
34/// # Classes {#bslmt_chronoutil-classes}
35///
36/// - bslmt::ChronoUtil: namespace for `bsl::chrono`-related operations
37///
38/// @see
39///
40/// # Description {#bslmt_chronoutil-description}
41/// This component defines a utility `struct`, `bslmt::ChronoUtil`,
42/// that serves as a namespace for a suite of classes and functions for
43/// interfacing C++11-style clocks with the clocks that BDE provides.
44///
45/// `bslmt::ChronoUtil` defines a `durationToTimeInterval` function for
46/// converting an arbitrary `bsl::chrono::duration` to a `bsls::TimeInterval`.
47///
48/// `bslmt::ChronoUtil` also defines a `timedWait` function for waiting on a
49/// synchronization primitive that uses a `bsls` system clock type internally
50/// (see @ref bsls_systemclocktype ), while allowing the user to specify the
51/// timeout using a `bsl::chrono::time_point`.
52///
53/// `ChronoUtil::timedWait` requires several things from the underlying
54/// primitive:
55///
56/// (1) an enumeration containing `e_TIMED_OUT`.
57///
58/// (2) a member function, `timedWait`, that takes a `const bsls::TimeInterval&`
59/// denoting the timeout value, and possibly an additional pointer argument.
60/// This function should return 0 upon success, `e_TIMED_OUT` on a timeout, and
61/// some other value on failure. `ChronoUtil::timedWait` will convert the
62/// `bsl::chrono::time_point` that is passed to it into a `bsls::TimeInterval`
63/// that can be used by the synchronization primitive (`ARG_TYPE` is just a
64/// placeholder name; the primitive will have its own type):
65/// @code
66/// int timedWait(const bsls::TimeInterval&);
67/// int timedWait(ARG_TYPE *argument, const bsls::TimeInterval&);
68/// @endcode
69///
70/// (3) a `const` member function, `clockType`, that takes no parameters and
71/// returns the underlying clock that the primitive uses -- either
72/// `bsls::SystemClockType::e_REALTIME` or `bsls::SystemClockType::e_MONOTONIC`:
73/// @code
74/// bsls::SystemClockType::Enum clockType() const;
75/// @endcode
76///
77/// Note that if the clock associated with the time point does not correspond to
78/// the clock used by the underlying synchronization primitive, then the
79/// `timedWait` function of the primitive may be called more than once, so the
80/// method is potentially more efficient if the clocks match.
81///
82/// Finally, `bslmt::ChronoUtil` defines an `isMatchingClock` function that
83/// checks to see if a C++11-style clock matches a `bsls` system clock. See
84/// @ref bsls_systemclocktype .
85///
86/// ## Usage {#bslmt_chronoutil-usage}
87///
88///
89/// This example illustrates intended use of this component.
90///
91/// We first define a synchronization primitive that is compliant with the
92/// requirements of `bslmt::ChronoUtil::timedWait` and then demonstrate use of
93/// that primitive with `timedWait`.
94///
95/// ### Prologue: Create a Synchronization Primitive {#bslmt_chronoutil-prologue-create-a-synchronization-primitive}
96///
97///
98/// The `TimedWaitSuccess` class, defined below, is a synchronization primitive
99/// that complies with the requirements of `bslmt::ChronoUtil::timedWait` (see
100/// the component-level documentation for information).
101///
102/// First, we define the interface of `TimedWaitSuccess`:
103/// @code
104/// /// `TimedWaitSuccess` is a synchronization primitive that always
105/// /// succeeds.
106/// class TimedWaitSuccess {
107///
108/// private:
109/// // DATA
110/// bsls::SystemClockType::Enum d_clockType;
111///
112/// public:
113/// // TYPES
114/// enum { e_TIMED_OUT = 1 };
115///
116/// // CREATORS
117///
118/// /// Create a `TimedWaitSuccess` object. Optionally specify a
119/// /// `clockType` indicating the type of the system clock against
120/// /// which the `bsls::TimeInterval` `absTime` timeouts passed to the
121/// /// `timedWait` method are to be interpreted. If `clockType` is not
122/// /// specified then the realtime system clock is used.
123/// explicit
124/// TimedWaitSuccess(bsls::SystemClockType::Enum clockType
125/// = bsls::SystemClockType::e_REALTIME);
126///
127/// // MANIPULATORS
128///
129/// /// Return 0 immediately. Note that this is for demonstration and
130/// /// testing purposes only.
131/// int timedWait(const bsls::TimeInterval&);
132///
133/// // ACCESSORS
134///
135/// /// Return the clock type used for timeouts.
136/// bsls::SystemClockType::Enum clockType() const;
137/// };
138/// @endcode
139/// Then, we implement the creator. All it has to do is remember the
140/// `clockType` that was passed to it:
141/// @code
142/// inline
143/// TimedWaitSuccess::TimedWaitSuccess(bsls::SystemClockType::Enum clockType)
144/// : d_clockType(clockType)
145/// {
146/// }
147///
148/// @endcode
149/// Next, we implement the `timedWait` function. In this simplistic primitive,
150/// this function always succeeds:
151/// @code
152/// // MANIPULATORS
153/// inline
154/// int TimedWaitSuccess::timedWait(const bsls::TimeInterval&)
155/// {
156/// return 0;
157/// }
158///
159/// @endcode
160/// Next, we implement the `clockType` function, which returns the underlying
161/// `bsls::SystemClockType::Enum` that this primitive uses:
162/// @code
163/// // ACCESSORS
164/// inline
165/// bsls::SystemClockType::Enum TimedWaitSuccess::clockType() const
166/// {
167/// return d_clockType;
168/// }
169/// @endcode
170///
171/// ### Example 1: Using bslmt::ChronoUtil::timedWait {#bslmt_chronoutil-example-1-using-bslmt-chronoutil-timedwait}
172///
173///
174/// This example demonstrates use of `bslmt::ChronoUtil::timedWait` to block on
175/// a synchronization primitive until either a condition is satisfied or a
176/// specified amount of time has elapsed. We use a `bsl::chrono::time_point` to
177/// specify the amount of time to wait. To do this, we call
178/// `bslmt::ChronoUtil::timedWait`, passing in the timeout as an *absolute* time
179/// point. In this example, we're using `TimedWaitSuccess` as the
180/// synchronization primitive, and specifying the timeout using
181/// `bsl::chrono::steady_clock`.
182///
183/// First, we construct the `TimedWaitSuccess` primitive; by default it uses the
184/// `bsls` realtime system clock to measure time:
185/// @code
186/// TimedWaitSuccess aPrimitive;
187/// @endcode
188/// Then, we call `bslmt::ChronoUtil::timedWait` to block on `aPrimitive`, while
189/// passing a timeout of "10 seconds from now", measured on the
190/// `bsl::chrono::steady_clock`:
191/// @code
192/// int rc = bslmt::ChronoUtil::timedWait(
193/// &aPrimitive,
194/// bsl::chrono::steady_clock::now() + bsl::chrono::seconds(10));
195/// @endcode
196/// When this call returns, one of three things will be true: (a) `rc == 0`,
197/// which means that the call succeeded before the timeout expired, (b)
198/// `rc == TimedWaitSuccess::e_TIMED_OUT`, which means that the call did not
199/// succeed before the timeout expired, or (c) `rc` equals some other value,
200/// which means that an error occurred.
201///
202/// If the call to `bslmt::ChronoUtil::timedWait` returned `e_TIMED_OUT` then we
203/// are guaranteed that the current time *on the clock that the time point was
204/// defined on* is greater than the timeout value that was passed in.
205/// @}
206/** @} */
207/** @} */
208
209/** @addtogroup bsl
210 * @{
211 */
212/** @addtogroup bslmt
213 * @{
214 */
215/** @addtogroup bslmt_chronoutil
216 * @{
217 */
218
219#include <bslscm_version.h>
220
221#include <bsls_libraryfeatures.h>
222#include <bsls_systemclocktype.h>
223#include <bsls_systemtime.h>
224#include <bsls_timeinterval.h>
225
226#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
227#include <bsl_chrono.h>
228
229
230namespace bslmt {
231
232 // =================
233 // struct ChronoUtil
234 // =================
235
236/// This `struct` provides a namespace for utility functions that operate on
237/// `bsl::chrono` facilities.
238///
239/// See @ref bslmt_chronoutil
240struct ChronoUtil {
241
242 public:
243 // CLASS METHODS
244
245 /// Return a `bsls::TimeInterval` having the value represented by the
246 /// specified `duration`. Unlike the implicit conversion defined from
247 /// duration defined in `bsls::TimeInterval`, this conversion handles
248 /// floating-point-based durations as well as integral ones.
249 template <class REP_TYPE, class PERIOD_TYPE>
250 static bsls::TimeInterval durationToTimeInterval(
251 const bsl::chrono::duration<REP_TYPE, PERIOD_TYPE>& duration);
252
253 /// Return `true` if the specified (template parameter) type `CLOCK`
254 /// matches the specified `clockType`, and `false` otherwise.
255 template <class CLOCK>
256 static
257 bool isMatchingClock(bsls::SystemClockType::Enum clockType);
258
259 /// Block on the specified `primitive` object of the (template
260 /// parameter) `PRIMITIVE` type by calling its `timedWait` method,
261 /// passing a timeout calculated from the specified `absTime`.
262 /// `absTime` is an *absolute* time represented by a time point with
263 /// respect to some epoch, which is determined by the clock associated
264 /// with the time point. Return 0 on success, `PRIMITIVE::e_TIMED_OUT`
265 /// if the `absTime` timeout expired, and other return values on error.
266 /// The `timedWait` method of `primitive` is called only once if the
267 /// clock type specified by the (template parameter) type `CLOCK`
268 /// corresponds to the clock used by `primitive`, and may be called more than once otherwise.
269 ///
270 /// \note Note that error codes returned from this
271 /// method, necessarily distinct from 0 and `PRIMITIVE::e_TIMED_OUT`,
272 /// are defined by `PRIMITIVE`.
273 template <class PRIMITIVE, class CLOCK, class DURATION>
274 static
275 int timedWait(PRIMITIVE *primitive,
276 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
277
278 /// Block on the specified `primitive` object of the (template
279 /// parameter) `PRIMITIVE` type by calling its `timedWait` method,
280 /// passing the specified `argument` of the (template parameter)
281 /// `ARG_TYPE` and a timeout calculated from the specified `absTime`.
282 /// `absTime` is an *absolute* time represented by a time point with
283 /// respect to some epoch, which is determined by the clock associated
284 /// with the time point. Return 0 on success, `PRIMITIVE::e_TIMED_OUT`
285 /// if the `absTime` timeout expired, and other return values on error.
286 /// The `timedWait` method of `primitive` is called only once if the
287 /// clock type specified by the (template parameter) type `CLOCK`
288 /// corresponds to the clock used by `primitive`, and may be called more than once otherwise.
289 ///
290 /// \note Note that error codes returned from this
291 /// method, necessarily distinct from 0 and `PRIMITIVE::e_TIMED_OUT`,
292 /// are defined by `PRIMITIVE`.
293 template <class PRIMITIVE, class ARG_TYPE, class CLOCK, class DURATION>
294 static
295 int timedWait(PRIMITIVE *primitive,
296 ARG_TYPE *argument,
297 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
298};
299
300// ============================================================================
301// INLINE DEFINITIONS
302// ============================================================================
303
304 // -----------------
305 // struct ChronoUtil
306 // -----------------
307
308// CLASS METHODS
309template <class REP_TYPE, class PERIOD_TYPE>
310inline
311bsls::TimeInterval ChronoUtil::durationToTimeInterval(
312 const bsl::chrono::duration<REP_TYPE, PERIOD_TYPE>& duration)
313{
314 using namespace bsl::chrono;
315
316 // Explicit scope needed due to legacy code using 'seconds' at BloombergLP
317 // namespace scope.
318 bsl::chrono::seconds wholeSecs =
319 duration_cast<bsl::chrono::seconds>(duration);
320 nanoseconds nanoSecs = duration_cast<nanoseconds>(duration - wholeSecs);
321 return bsls::TimeInterval(wholeSecs.count(),
322 static_cast<int>(nanoSecs.count()));
323}
324
325template <class CLOCK>
326inline
327bool ChronoUtil::isMatchingClock(bsls::SystemClockType::Enum)
328{
329 return false;
330}
331
332template <>
333inline
334bool ChronoUtil::isMatchingClock<bsl::chrono::system_clock>(
336{
337 return bsls::SystemClockType::e_REALTIME == clockType;
338}
339
340template <>
341inline
342bool ChronoUtil::isMatchingClock<bsl::chrono::steady_clock>(
344{
345 return bsls::SystemClockType::e_MONOTONIC == clockType;
346}
347
348template <class PRIMITIVE, class CLOCK, class DURATION>
349int ChronoUtil::timedWait(
350 PRIMITIVE *primitive,
351 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
352{
353 if (ChronoUtil::isMatchingClock<CLOCK>(primitive->clockType())) {
354 return primitive->timedWait(
355 bsls::TimeInterval(absTime.time_since_epoch())); // RETURN
356 }
357 else {
358 typename CLOCK::time_point now = CLOCK::now();
359 int ret;
360
361 // Iteration is necessary because the specified 'CLOCK' type is known
362 // to be different from that used internally by 'primitive'.
363
364 while (absTime > now) {
366 bsls::SystemTime::now(primitive->clockType())
367 .addDuration(absTime - now);
368 ret = primitive->timedWait(ti);
369 if (PRIMITIVE::e_TIMED_OUT != ret) {
370 return ret; // RETURN
371 }
372 now = CLOCK::now();
373 }
374 return PRIMITIVE::e_TIMED_OUT; // RETURN
375 }
376}
377
378template <class PRIMITIVE, class ARG_TYPE, class CLOCK, class DURATION>
379int ChronoUtil::timedWait(
380 PRIMITIVE *primitive,
381 ARG_TYPE *argument,
382 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
383{
384 if (ChronoUtil::isMatchingClock<CLOCK>(primitive->clockType())) {
385 return primitive->timedWait(
386 argument,
387 bsls::TimeInterval(absTime.time_since_epoch())); // RETURN
388 }
389 else {
390 typename CLOCK::time_point now = CLOCK::now();
391 int ret;
392
393 // Iteration is necessary because the specified 'CLOCK' type is known
394 // to be different from that used internally by 'primitive'.
395
396 while (absTime > now) {
398 bsls::SystemTime::now(primitive->clockType())
399 .addDuration(absTime - now);
400 ret = primitive->timedWait(argument, ti);
401 if (PRIMITIVE::e_TIMED_OUT != ret) {
402 return ret; // RETURN
403 }
404 now = CLOCK::now();
405 }
406 return PRIMITIVE::e_TIMED_OUT; // RETURN
407 }
408}
409
410} // close package namespace
411
412
413#endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
414#endif
415
416// ----------------------------------------------------------------------------
417// Copyright 2021 Bloomberg Finance L.P.
418//
419// Licensed under the Apache License, Version 2.0 (the "License");
420// you may not use this file except in compliance with the License.
421// You may obtain a copy of the License at
422//
423// http://www.apache.org/licenses/LICENSE-2.0
424//
425// Unless required by applicable law or agreed to in writing, software
426// distributed under the License is distributed on an "AS IS" BASIS,
427// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
428// See the License for the specific language governing permissions and
429// limitations under the License.
430// ----------------------------- END-OF-FILE ----------------------------------
431
432/** @} */
433/** @} */
434/** @} */
Definition bsls_timeinterval.h:307
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344
Enum
Definition bsls_systemclocktype.h:119
@ e_MONOTONIC
Definition bsls_systemclocktype.h:128
@ e_REALTIME
Definition bsls_systemclocktype.h:122
static TimeInterval now(SystemClockType::Enum clockType)
Definition bsls_systemtime.h:177