xref: /commonlibrary/c_utils/base/include/timer.h (revision 3f4cbf05)
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
28namespace OHOS {
29namespace Utils {
30class 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 */
49class Timer {
50public:
51    using TimerCallback = std::function<void ()>;
52    using TimerCallbackPtr = std::shared_ptr<TimerCallback>;
53    using TimerListCallback = std::function<void (int timerFd)>;
54
55public:
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
116private:
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
126private:
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