• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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