xref: /aosp_15_r20/external/federated-compute/fcp/base/clock.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2020 Google LLC
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 #ifndef FCP_BASE_CLOCK_H_
18 #define FCP_BASE_CLOCK_H_
19 
20 #include <map>
21 #include <memory>
22 #include <optional>
23 #include <vector>
24 
25 #include "absl/synchronization/mutex.h"
26 #include "absl/time/time.h"
27 
28 namespace fcp {
29 
30 /*
31  * Clock is an abstract class representing a Clock, which is an object that can
32  * tell you the current time and schedule a wakeable event in a future.
33  */
34 class Clock {
35  public:
36   // Returns a pointer to the global realtime clock. The caller does not
37   // own the returned pointer and should not delete it. The returned clock
38   // is thread-safe.
39   static Clock* RealClock();
40 
41   virtual ~Clock() = default;
42 
43   // Returns current time.
44   virtual absl::Time Now() = 0;
45 
46   // Sleeps for the specified duration.
47   virtual void Sleep(absl::Duration d) = 0;
48 
49   // An abstract interface for a waiter class that is passed to
50   // WakeupWithDeadline and is responsible for handling a timer wake-up.
51   // Waiter interface doesn't support a cancellation mechanism which means
52   //
53   // Note: it is up to Waiter implementation how to handle a cancellation. Clock
54   // itself doesn't manage cancellation and will call WakeUp() on all all alarms
55   // once their deadline time is past due.
56   class Waiter {
57    public:
58     virtual ~Waiter() = default;
59     // A callback method that is called when the corresponding deadline is
60     // reached. This method may be called on an arbitrary thread.
61     virtual void WakeUp() = 0;
62   };
63 
64   // Schedule the waiter to be waked up at the specified deadline.
65   void WakeupWithDeadline(absl::Time deadline,
66                           const std::shared_ptr<Waiter>& waiter);
67 
68  protected:
69   // Accessors shared for derived clases.
mutex()70   absl::Mutex* mutex() { return &mu_; }
71 
72   // Internal version of now which is called under mutex.
73   virtual absl::Time NowLocked()
74       ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex()) = 0;
75 
76   // Overloaded by derived class to implement the actual scheduling.
77   virtual void ScheduleWakeup(absl::Time wakeup_time)
78       ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex()) = 0;
79 
80   // Called to dispatch wakeup to all due waiters.
81   void DispatchWakeups();
82 
83  private:
84   using WaiterList = std::vector<std::shared_ptr<Waiter>>;
85   using WaiterMap = std::map<absl::Time, WaiterList>;
86 
87   bool CheckReentrancy();
88   WaiterList GetExpiredWaiters();
89   bool FinishDispatchAndScheduleNextWakeup();
90 
91   // Mutex that protects the internal state.
92   absl::Mutex mu_;
93   // Pending (unexpired) waiters ordered by deadline - soonest to latest.
94   // Waiters with exactly the same deadline are stored in the same bucket and
95   // the order at which they were added is preserved.
96   WaiterMap pending_waiters_ ABSL_GUARDED_BY(mutex());
97   // This value =0 when no DispatchWakeups() is running;
98   //            =1 when DispatchWakeups() is running
99   //            >1 when at least one additional DispatchWakeups() call happened
100   //               while DispatchWakeups() was running, for example from
101   //               a timer elapsing and triggering a wake-up.
102   int dispatch_level_ ABSL_GUARDED_BY(mutex()) = 0;
103 };
104 
105 }  // namespace fcp
106 
107 #endif  // FCP_BASE_CLOCK_H_
108