1 /* 2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef UTILS_TIMER_H 17 #define UTILS_TIMER_H 18 19 #include <sys/types.h> 20 #include <cstdint> 21 #include <string> 22 #include <list> 23 #include <map> 24 #include <mutex> 25 #include <thread> 26 #include <vector> 27 28 namespace OHOS { 29 namespace Utils { 30 class EventReactor; 31 /** 32 * @brief Implements a timer manager. 33 * 34 * After a timer is started, users can register several timed events, which 35 * can be continuous or one-shot, to it. Some points need to be noticed:\n 36 * 1. A timer must be set up (through Setup()) before use, and be shut down 37 * (via Shutdown()) before its deconstruction.\n 38 * 2. A timer must be set up first and then shut down. Avoid delegating a 39 * timer to different threads. Otherwise, multithreading issues may occur.\n 40 * 3. Setting up a timer again will not reset the timer, but return 41 * `TIMER_ERR_INVALID_VALUE`. If a reset operation is required, shut down 42 * the timer first and then set it up.\n 43 * 4. The parameter in Shutdown() determines whether the thread in the timer 44 * will be detached. A detach operation may cause possible 45 * multithreading problems, and is therefore not recommended. If a 46 * detach operation is required, availability of related objects used in 47 * `thread_` must be guaranteed. 48 */ 49 class Timer { 50 public: 51 using TimerCallback = std::function<void ()>; 52 using TimerCallbackPtr = std::shared_ptr<TimerCallback>; 53 using TimerListCallback = std::function<void (int timerFd)>; 54 55 public: 56 /** 57 * @brief Creates a timer. 58 * 59 * In performance-sensitive scenarios, set `timeoutMs` to a 60 * greater value before timer setup based on your timed event setttings. The 61 * default value is 1000 ms. The timeout event requires 100 us to respond. 62 * 63 * @param name Indicates the name of the timer. It is used as the name 64 * of the thread in the timer. 65 * @param timeoutMs Indicates the duration for which the timer will wait. 66 * The value is an integer in [-1, INT32MAX], but `-1` and `0` are not 67 * recommended. `-1` means to wait indefinitely (until the timed event is 68 * triggered). `0` means not to wait, which occupies too much CPU time. 69 */ 70 explicit Timer(const std::string& name, int timeoutMs = 1000); 71 virtual ~Timer(); 72 73 /** 74 * @brief Sets up a timer. 75 * 76 * Do not set up a timer before shutting down the existing one. 77 */ 78 virtual uint32_t Setup(); 79 80 /** 81 * @brief Shuts down this timer. 82 * 83 * A timer can be shut down in blocking or unblocking mode. In blocking 84 * mode, the timer will be shut down only after all running events 85 * in the timer have finished. If `timeoutMs` is set to `-1`, use 86 * unblocking mode to avoid deadloop. 87 * 88 * @param useJoin Specifies whether to use blocking mode. The value `true` 89 * means to use blocking mode, and `false` (not recommended) means 90 * the opposite. 91 */ 92 virtual void Shutdown(bool useJoin = true); 93 94 /** 95 * @brief Registers timed events. 96 * 97 * @param callback Indicates the callback function of a timed event. 98 * @param interval Indicates the interval of a timed event, in ms. 99 * @param once Indicates whether the timed event is one-shot. 100 * The value `true` means that the timed event is one-shot, 101 * and `false` means the opposite. The default value is `false`. 102 * @return Returns the ID of a timed event. You can use it as the 103 * parameter of Unregister(). 104 * @see Unregister 105 */ 106 uint32_t Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once = false); 107 /** 108 * @brief Deletes a timed event. 109 * 110 * @param timerId Indicates the ID of the timed event to delete. 111 * It can be obtained through Register(). 112 * @see Register 113 */ 114 void Unregister(uint32_t timerId); 115 116 private: 117 void MainLoop(); 118 void OnTimer(int timerFd); 119 virtual uint32_t DoRegister(const TimerListCallback& callback, uint32_t interval, bool once, int &timerFd); 120 virtual void DoUnregister(uint32_t interval); 121 void DoTimerListCallback(const TimerListCallback& callback, int timerFd); 122 uint32_t GetValidId(uint32_t timerId) const; 123 int GetTimerFd(uint32_t interval /* ms */); 124 void EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds); 125 126 private: 127 struct TimerEntry { 128 uint32_t timerId; // Unique ID. 129 uint32_t interval; // million second 130 TimerCallback callback; 131 bool once; 132 int timerFd; 133 }; 134 135 using TimerEntryPtr = std::shared_ptr<TimerEntry>; 136 using TimerEntryList = std::list<TimerEntryPtr>; 137 138 std::map<uint32_t, TimerEntryList> intervalToTimers_; // interval to TimerEntryList 139 std::map<uint32_t, TimerEntryPtr> timerToEntries_; // timer_id to TimerEntry 140 141 std::string name_; 142 int timeoutMs_; 143 std::thread thread_; 144 EventReactor *reactor_; 145 std::map<uint32_t, uint32_t> timers_; // timer_fd to interval 146 std::mutex mutex_; 147 }; 148 149 } // namespace Utils 150 } // namespace OHOS 151 #endif 152 153