024b9eb7b3e65052a88271665de022f20fb9a584
[folly.git] / folly / futures / Timekeeper.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/futures/detail/Types.h>
20 #include <folly/futures/Unit.h>
21
22 namespace folly {
23
24 template <class> class Future;
25
26 /// A Timekeeper handles the details of keeping time and fulfilling delay
27 /// promises. The returned Future<Unit> will either complete after the
28 /// elapsed time, or in the event of some kind of exceptional error may hold
29 /// an exception. These Futures respond to cancellation. If you use a lot of
30 /// Delays and many of them ultimately are unneeded (as would be the case for
31 /// Delays that are used to trigger timeouts of async operations), then you
32 /// can and should cancel them to reclaim resources.
33 ///
34 /// Users will typically get one of these via Future::sleep(Duration) or
35 /// use them implicitly behind the scenes by passing a timeout to some Future
36 /// operation.
37 ///
38 /// Although we don't formally alias Delay = Future<Unit>,
39 /// that's an appropriate term for it. People will probably also call these
40 /// Timeouts, and that's ok I guess, but that term is so overloaded I thought
41 /// it made sense to introduce a cleaner term.
42 ///
43 /// Remember that Duration is a std::chrono duration (millisecond resolution
44 /// at the time of writing). When writing code that uses specific durations,
45 /// prefer using the explicit std::chrono type, e.g. std::chrono::milliseconds
46 /// over Duration. This makes the code more legible and means you won't be
47 /// unpleasantly surprised if we redefine Duration to microseconds, or
48 /// something.
49 class Timekeeper {
50  public:
51   virtual ~Timekeeper() = default;
52
53   /// Returns a future that will complete after the given duration with the
54   /// elapsed time. Exceptional errors can happen but they must be
55   /// exceptional. Use the steady (monotonic) clock.
56   ///
57   /// You may cancel this Future to reclaim resources.
58   ///
59   /// This future probably completes on the timer thread. You should almost
60   /// certainly follow it with a via() call or the accuracy of other timers
61   /// will suffer.
62   virtual Future<Unit> after(Duration) = 0;
63
64   /// Returns a future that will complete at the requested time.
65   ///
66   /// You may cancel this Future to reclaim resources.
67   ///
68   /// NB This is sugar for `after(when - now)`, so while you are welcome to
69   /// use a std::chrono::system_clock::time_point it will not track changes to
70   /// the system clock but rather execute that many milliseconds in the future
71   /// according to the steady clock.
72   template <class Clock>
73   Future<Unit> at(std::chrono::time_point<Clock> when);
74 };
75
76 } // namespace folly
77
78 // now get those definitions
79 #include <folly/futures/Future.h>
80
81 // finally we can use Future
82 namespace folly {
83
84 template <class Clock>
85 Future<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
86   auto now = Clock::now();
87
88   if (when <= now) {
89     return makeFuture();
90   }
91
92   return after(when - now);
93 }
94
95 } // namespace folly