minor Timekeeper bug
[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 ///
50 ///    timekeeper.after(std::chrono::duration_cast<Duration>(
51 ///      someNanoseconds))
52 class Timekeeper {
53  public:
54   virtual ~Timekeeper() = default;
55
56   /// Returns a future that will complete after the given duration with the
57   /// elapsed time. Exceptional errors can happen but they must be
58   /// exceptional. Use the steady (monotonic) clock.
59   ///
60   /// You may cancel this Future to reclaim resources.
61   ///
62   /// This future probably completes on the timer thread. You should almost
63   /// certainly follow it with a via() call or the accuracy of other timers
64   /// will suffer.
65   virtual Future<Unit> after(Duration) = 0;
66
67   /// Returns a future that will complete at the requested time.
68   ///
69   /// You may cancel this Future to reclaim resources.
70   ///
71   /// NB This is sugar for `after(when - now)`, so while you are welcome to
72   /// use a std::chrono::system_clock::time_point it will not track changes to
73   /// the system clock but rather execute that many milliseconds in the future
74   /// according to the steady clock.
75   template <class Clock>
76   Future<Unit> at(std::chrono::time_point<Clock> when);
77 };
78
79 } // namespace folly
80
81 // now get those definitions
82 #include <folly/futures/Future.h>
83
84 // finally we can use Future
85 namespace folly {
86
87 template <class Clock>
88 Future<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
89   auto now = Clock::now();
90
91   if (when <= now) {
92     return makeFuture();
93   }
94
95   return after(std::chrono::duration_cast<Duration>(when - now));
96 }
97
98 } // namespace folly