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