1 /* 2 * Copyright (C) 2021 The Android Open Source Project 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 android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_ 18 #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_ 19 20 #include <android-base/thread_annotations.h> 21 22 #include <memory> 23 #include <mutex> 24 #include <queue> 25 #include <thread> 26 #include <unordered_map> 27 #include <vector> 28 29 namespace android { 30 namespace hardware { 31 namespace automotive { 32 namespace vehicle { 33 34 // A thread-safe recurrent timer. 35 class RecurrentTimer final { 36 public: 37 // The class for the function that would be called recurrently. 38 using Callback = std::function<void()>; 39 40 RecurrentTimer(); 41 42 ~RecurrentTimer(); 43 44 // Registers a recurrent callback for a given interval. 45 // Registering the same callback twice will override the interval provided before. 46 void registerTimerCallback(int64_t intervalInNano, std::shared_ptr<Callback> callback); 47 48 // Unregisters a previously registered recurrent callback. 49 void unregisterTimerCallback(std::shared_ptr<Callback> callback); 50 51 private: 52 // friend class for unit testing. 53 friend class RecurrentTimerTest; 54 55 struct CallbackInfo { 56 std::shared_ptr<Callback> callback; 57 int64_t interval; 58 int64_t nextTime; 59 // A flag to indicate whether this CallbackInfo is already outdated and should be ignored. 60 // The reason we need this flag is because we cannot easily remove an element from a heap. 61 bool outdated = false; 62 63 static bool cmp(const std::unique_ptr<CallbackInfo>& lhs, 64 const std::unique_ptr<CallbackInfo>& rhs); 65 }; 66 67 std::mutex mLock; 68 std::thread mThread; 69 std::condition_variable mCond; 70 bool mStopRequested GUARDED_BY(mLock) = false; 71 // A map to map each callback to its current active CallbackInfo in the mCallbackQueue. 72 std::unordered_map<std::shared_ptr<Callback>, CallbackInfo*> mCallbacks GUARDED_BY(mLock); 73 // A min-heap sorted by nextTime. Note that because we cannot remove arbitrary element from the 74 // heap, a single Callback can have multiple entries in this queue, all but one should be valid. 75 // The rest should be mark as outdated. The valid one is one stored in mCallbacks. 76 std::vector<std::unique_ptr<CallbackInfo>> mCallbackQueue GUARDED_BY(mLock); 77 78 void loop(); 79 80 // Mark the callbackInfo as outdated and should be ignored when popped from the heap. 81 void markOutdatedLocked(CallbackInfo* callback) REQUIRES(mLock); 82 // Remove all outdated callbackInfos from the top of the heap. This function must be called 83 // each time we might introduce outdated elements to the top. We must make sure the heap is 84 // always valid from the top. 85 void removeInvalidCallbackLocked() REQUIRES(mLock); 86 // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put 87 // it back to the heap. 88 std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock); 89 }; 90 91 } // namespace vehicle 92 } // namespace automotive 93 } // namespace hardware 94 } // namespace android 95 96 #endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_ 97