BDE 4.14.0 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.
239
240 public:
241 // CLASS METHODS
242
243 /// Return a `bsls::TimeInterval` having the value represented by the
244 /// specified `duration`. Unlike the implicit conversion defined from
245 /// duration defined in `bsls::TimeInterval`, this conversion handles
246 /// floating-point-based durations as well as integral ones.
247 template <class REP_TYPE, class PERIOD_TYPE>
249 const bsl::chrono::duration<REP_TYPE, PERIOD_TYPE>& duration);
250
251 /// Return `true` if the specified (template parameter) type `CLOCK`
252 /// matches the specified `clockType`, and `false` otherwise.
253 template <class CLOCK>
254 static
256
257 /// Block on the specified `primitive` object of the (template
258 /// parameter) `PRIMITIVE` type by calling its `timedWait` method,
259 /// passing a timeout calculated from the specified `absTime`.
260 /// `absTime` is an *absolute* time represented by a time point with
261 /// respect to some epoch, which is determined by the clock associated
262 /// with the time point. Return 0 on success, `PRIMITIVE::e_TIMED_OUT`
263 /// if the `absTime` timeout expired, and other return values on error.
264 /// The `timedWait` method of `primitive` is called only once if the
265 /// clock type specified by the (template parameter) type `CLOCK`
266 /// corresponds to the clock used by `primitive`, and may be called more
267 /// than once otherwise. Note that error codes returned from this
268 /// method, necessarily distinct from 0 and `PRIMITIVE::e_TIMED_OUT`,
269 /// are defined by `PRIMITIVE`.
270 template <class PRIMITIVE, class CLOCK, class DURATION>
271 static
272 int timedWait(PRIMITIVE *primitive,
273 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
274
275 /// Block on the specified `primitive` object of the (template
276 /// parameter) `PRIMITIVE` type by calling its `timedWait` method,
277 /// passing the specified `argument` of the (template parameter)
278 /// `ARG_TYPE` and a timeout calculated from the specified `absTime`.
279 /// `absTime` is an *absolute* time represented by a time point with
280 /// respect to some epoch, which is determined by the clock associated
281 /// with the time point. Return 0 on success, `PRIMITIVE::e_TIMED_OUT`
282 /// if the `absTime` timeout expired, and other return values on error.
283 /// The `timedWait` method of `primitive` is called only once if the
284 /// clock type specified by the (template parameter) type `CLOCK`
285 /// corresponds to the clock used by `primitive`, and may be called more
286 /// than once otherwise. Note that error codes returned from this
287 /// method, necessarily distinct from 0 and `PRIMITIVE::e_TIMED_OUT`,
288 /// are defined by `PRIMITIVE`.
289 template <class PRIMITIVE, class ARG_TYPE, class CLOCK, class DURATION>
290 static
291 int timedWait(PRIMITIVE *primitive,
292 ARG_TYPE *argument,
293 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
294};
295
296// ============================================================================
297// INLINE DEFINITIONS
298// ============================================================================
299
300 // -----------------
301 // struct ChronoUtil
302 // -----------------
303
304// CLASS METHODS
305template <class REP_TYPE, class PERIOD_TYPE>
306inline
308 const bsl::chrono::duration<REP_TYPE, PERIOD_TYPE>& duration)
309{
310 using namespace bsl::chrono;
311
312 // Explicit scope needed due to legacy code using 'seconds' at BloombergLP
313 // namespace scope.
314 bsl::chrono::seconds wholeSecs =
315 duration_cast<bsl::chrono::seconds>(duration);
316 nanoseconds nanoSecs = duration_cast<nanoseconds>(duration - wholeSecs);
317 return bsls::TimeInterval(wholeSecs.count(),
318 static_cast<int>(nanoSecs.count()));
319}
320
321template <class CLOCK>
322inline
327
328template <>
329inline
330bool ChronoUtil::isMatchingClock<bsl::chrono::system_clock>(
332{
333 return bsls::SystemClockType::e_REALTIME == clockType;
334}
335
336template <>
337inline
338bool ChronoUtil::isMatchingClock<bsl::chrono::steady_clock>(
340{
341 return bsls::SystemClockType::e_MONOTONIC == clockType;
342}
343
344template <class PRIMITIVE, class CLOCK, class DURATION>
346 PRIMITIVE *primitive,
347 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
348{
349 if (ChronoUtil::isMatchingClock<CLOCK>(primitive->clockType())) {
350 return primitive->timedWait(
351 bsls::TimeInterval(absTime.time_since_epoch())); // RETURN
352 }
353 else {
354 typename CLOCK::time_point now = CLOCK::now();
355 int ret;
356
357 // Iteration is necessary because the specified 'CLOCK' type is known
358 // to be different from that used internally by 'primitive'.
359
360 while (absTime > now) {
362 bsls::SystemTime::now(primitive->clockType())
363 .addDuration(absTime - now);
364 ret = primitive->timedWait(ti);
365 if (PRIMITIVE::e_TIMED_OUT != ret) {
366 return ret; // RETURN
367 }
368 now = CLOCK::now();
369 }
370 return PRIMITIVE::e_TIMED_OUT; // RETURN
371 }
372}
373
374template <class PRIMITIVE, class ARG_TYPE, class CLOCK, class DURATION>
376 PRIMITIVE *primitive,
377 ARG_TYPE *argument,
378 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
379{
380 if (ChronoUtil::isMatchingClock<CLOCK>(primitive->clockType())) {
381 return primitive->timedWait(
382 argument,
383 bsls::TimeInterval(absTime.time_since_epoch())); // RETURN
384 }
385 else {
386 typename CLOCK::time_point now = CLOCK::now();
387 int ret;
388
389 // Iteration is necessary because the specified 'CLOCK' type is known
390 // to be different from that used internally by 'primitive'.
391
392 while (absTime > now) {
394 bsls::SystemTime::now(primitive->clockType())
395 .addDuration(absTime - now);
396 ret = primitive->timedWait(argument, ti);
397 if (PRIMITIVE::e_TIMED_OUT != ret) {
398 return ret; // RETURN
399 }
400 now = CLOCK::now();
401 }
402 return PRIMITIVE::e_TIMED_OUT; // RETURN
403 }
404}
405
406} // close package namespace
407
408
409#endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
410#endif
411
412// ----------------------------------------------------------------------------
413// Copyright 2021 Bloomberg Finance L.P.
414//
415// Licensed under the Apache License, Version 2.0 (the "License");
416// you may not use this file except in compliance with the License.
417// You may obtain a copy of the License at
418//
419// http://www.apache.org/licenses/LICENSE-2.0
420//
421// Unless required by applicable law or agreed to in writing, software
422// distributed under the License is distributed on an "AS IS" BASIS,
423// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
424// See the License for the specific language governing permissions and
425// limitations under the License.
426// ----------------------------- END-OF-FILE ----------------------------------
427
428/** @} */
429/** @} */
430/** @} */
Definition bsls_timeinterval.h:301
BSLS_KEYWORD_CONSTEXPR_CPP14 TimeInterval & addDuration(const std::chrono::duration< REP_TYPE, PERIOD_TYPE > &duration, typename std::enable_if< TimeInterval_DurationTraits< REP_TYPE, PERIOD_TYPE >::k_IMPLICIT_CONVERSION_ENABLED, int >::type *=0)
Definition bsls_timeinterval.h:1226
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslstl_chrono.h:146
Definition bslmt_barrier.h:344
Definition bslmt_chronoutil.h:238
static bool isMatchingClock(bsls::SystemClockType::Enum clockType)
Definition bslmt_chronoutil.h:323
static int timedWait(PRIMITIVE *primitive, const bsl::chrono::time_point< CLOCK, DURATION > &absTime)
Definition bslmt_chronoutil.h:345
static bsls::TimeInterval durationToTimeInterval(const bsl::chrono::duration< REP_TYPE, PERIOD_TYPE > &duration)
Definition bslmt_chronoutil.h:307
Enum
Definition bsls_systemclocktype.h:117
@ e_MONOTONIC
Definition bsls_systemclocktype.h:126
@ e_REALTIME
Definition bsls_systemclocktype.h:120
static TimeInterval now(SystemClockType::Enum clockType)
Definition bsls_systemtime.h:175