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