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