13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License.
53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at
63f4cbf05Sopenharmony_ci *
73f4cbf05Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83f4cbf05Sopenharmony_ci *
93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and
133f4cbf05Sopenharmony_ci * limitations under the License.
143f4cbf05Sopenharmony_ci */
153f4cbf05Sopenharmony_ci
163f4cbf05Sopenharmony_ci#ifndef UTILS_TIMER_H
173f4cbf05Sopenharmony_ci#define UTILS_TIMER_H
183f4cbf05Sopenharmony_ci
193f4cbf05Sopenharmony_ci#include <sys/types.h>
203f4cbf05Sopenharmony_ci#include <cstdint>
213f4cbf05Sopenharmony_ci#include <string>
223f4cbf05Sopenharmony_ci#include <list>
233f4cbf05Sopenharmony_ci#include <map>
243f4cbf05Sopenharmony_ci#include <mutex>
253f4cbf05Sopenharmony_ci#include <thread>
263f4cbf05Sopenharmony_ci#include <vector>
273f4cbf05Sopenharmony_ci
283f4cbf05Sopenharmony_cinamespace OHOS {
293f4cbf05Sopenharmony_cinamespace Utils {
303f4cbf05Sopenharmony_ciclass EventReactor;
313f4cbf05Sopenharmony_ci/**
323f4cbf05Sopenharmony_ci * @brief Implements a timer manager.
333f4cbf05Sopenharmony_ci *
343f4cbf05Sopenharmony_ci * After a timer is started, users can register several timed events, which
353f4cbf05Sopenharmony_ci * can be continuous or one-shot, to it. Some points need to be noticed:\n
363f4cbf05Sopenharmony_ci * 1. A timer must be set up (through Setup()) before use, and be shut down
373f4cbf05Sopenharmony_ci * (via Shutdown()) before its deconstruction.\n
383f4cbf05Sopenharmony_ci * 2. A timer must be set up first and then shut down. Avoid delegating a
393f4cbf05Sopenharmony_ci * timer to different threads. Otherwise, multithreading issues may occur.\n
403f4cbf05Sopenharmony_ci * 3. Setting up a timer again will not reset the timer, but return
413f4cbf05Sopenharmony_ci * `TIMER_ERR_INVALID_VALUE`. If a reset operation is required, shut down
423f4cbf05Sopenharmony_ci * the timer first and then set it up.\n
433f4cbf05Sopenharmony_ci * 4. The parameter in Shutdown() determines whether the thread in the timer
443f4cbf05Sopenharmony_ci * will be detached. A detach operation may cause possible
453f4cbf05Sopenharmony_ci * multithreading problems, and is therefore not recommended. If a
463f4cbf05Sopenharmony_ci * detach operation is required, availability of related objects used in
473f4cbf05Sopenharmony_ci * `thread_` must be guaranteed.
483f4cbf05Sopenharmony_ci */
493f4cbf05Sopenharmony_ciclass Timer {
503f4cbf05Sopenharmony_cipublic:
513f4cbf05Sopenharmony_ci    using TimerCallback = std::function<void ()>;
523f4cbf05Sopenharmony_ci    using TimerCallbackPtr = std::shared_ptr<TimerCallback>;
533f4cbf05Sopenharmony_ci    using TimerListCallback = std::function<void (int timerFd)>;
543f4cbf05Sopenharmony_ci
553f4cbf05Sopenharmony_cipublic:
563f4cbf05Sopenharmony_ci    /**
573f4cbf05Sopenharmony_ci     * @brief Creates a timer.
583f4cbf05Sopenharmony_ci     *
593f4cbf05Sopenharmony_ci     * In performance-sensitive scenarios, set `timeoutMs` to a
603f4cbf05Sopenharmony_ci	 * greater value before timer setup based on your timed event setttings. The
613f4cbf05Sopenharmony_ci     * default value is 1000 ms. The timeout event requires 100 us to respond.
623f4cbf05Sopenharmony_ci     *
633f4cbf05Sopenharmony_ci     * @param name Indicates the name of the timer. It is used as the name
643f4cbf05Sopenharmony_ci	 * of the thread in the timer.
653f4cbf05Sopenharmony_ci     * @param timeoutMs Indicates the duration for which the timer will wait.
663f4cbf05Sopenharmony_ci     * The value is an integer in [-1, INT32MAX], but `-1` and `0` are not
673f4cbf05Sopenharmony_ci     * recommended. `-1` means to wait indefinitely (until the timed event is
683f4cbf05Sopenharmony_ci     * triggered). `0` means not to wait, which occupies too much CPU time.
693f4cbf05Sopenharmony_ci     */
703f4cbf05Sopenharmony_ci    explicit Timer(const std::string& name, int timeoutMs = 1000);
713f4cbf05Sopenharmony_ci    virtual ~Timer();
723f4cbf05Sopenharmony_ci
733f4cbf05Sopenharmony_ci    /**
743f4cbf05Sopenharmony_ci     * @brief Sets up a timer.
753f4cbf05Sopenharmony_ci     *
763f4cbf05Sopenharmony_ci     * Do not set up a timer before shutting down the existing one.
773f4cbf05Sopenharmony_ci     */
783f4cbf05Sopenharmony_ci    virtual uint32_t Setup();
793f4cbf05Sopenharmony_ci
803f4cbf05Sopenharmony_ci    /**
813f4cbf05Sopenharmony_ci     * @brief Shuts down this timer.
823f4cbf05Sopenharmony_ci     *
833f4cbf05Sopenharmony_ci     * A timer can be shut down in blocking or unblocking mode. In blocking
843f4cbf05Sopenharmony_ci     * mode, the timer will be shut down only after all running events
853f4cbf05Sopenharmony_ci     * in the timer have finished. If `timeoutMs` is set to `-1`, use
863f4cbf05Sopenharmony_ci     * unblocking mode to avoid deadloop.
873f4cbf05Sopenharmony_ci     *
883f4cbf05Sopenharmony_ci     * @param useJoin Specifies whether to use blocking mode. The value `true`
893f4cbf05Sopenharmony_ci     * means to use blocking mode, and `false` (not recommended) means
903f4cbf05Sopenharmony_ci     * the opposite.
913f4cbf05Sopenharmony_ci     */
923f4cbf05Sopenharmony_ci    virtual void Shutdown(bool useJoin = true);
933f4cbf05Sopenharmony_ci
943f4cbf05Sopenharmony_ci    /**
953f4cbf05Sopenharmony_ci     * @brief Registers timed events.
963f4cbf05Sopenharmony_ci     *
973f4cbf05Sopenharmony_ci     * @param callback Indicates the callback function of a timed event.
983f4cbf05Sopenharmony_ci     * @param interval Indicates the interval of a timed event, in ms.
993f4cbf05Sopenharmony_ci     * @param once Indicates whether the timed event is one-shot.
1003f4cbf05Sopenharmony_ci     * The value `true` means that the timed event is one-shot,
1013f4cbf05Sopenharmony_ci	 * and `false` means the opposite. The default value is `false`.
1023f4cbf05Sopenharmony_ci     * @return Returns the ID of a timed event. You can use it as the
1033f4cbf05Sopenharmony_ci     * parameter of Unregister().
1043f4cbf05Sopenharmony_ci     * @see Unregister
1053f4cbf05Sopenharmony_ci     */
1063f4cbf05Sopenharmony_ci    uint32_t Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once = false);
1073f4cbf05Sopenharmony_ci    /**
1083f4cbf05Sopenharmony_ci     * @brief Deletes a timed event.
1093f4cbf05Sopenharmony_ci     *
1103f4cbf05Sopenharmony_ci     * @param timerId Indicates the ID of the timed event to delete.
1113f4cbf05Sopenharmony_ci     * It can be obtained through Register().
1123f4cbf05Sopenharmony_ci     * @see Register
1133f4cbf05Sopenharmony_ci     */
1143f4cbf05Sopenharmony_ci    void Unregister(uint32_t timerId);
1153f4cbf05Sopenharmony_ci
1163f4cbf05Sopenharmony_ciprivate:
1173f4cbf05Sopenharmony_ci    void MainLoop();
1183f4cbf05Sopenharmony_ci    void OnTimer(int timerFd);
1193f4cbf05Sopenharmony_ci    virtual uint32_t DoRegister(const TimerListCallback& callback, uint32_t interval, bool once, int &timerFd);
1203f4cbf05Sopenharmony_ci    virtual void DoUnregister(uint32_t interval);
1213f4cbf05Sopenharmony_ci    void DoTimerListCallback(const TimerListCallback& callback, int timerFd);
1223f4cbf05Sopenharmony_ci    uint32_t GetValidId(uint32_t timerId) const;
1233f4cbf05Sopenharmony_ci    int GetTimerFd(uint32_t interval /* ms */);
1243f4cbf05Sopenharmony_ci    void EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds);
1253f4cbf05Sopenharmony_ci
1263f4cbf05Sopenharmony_ciprivate:
1273f4cbf05Sopenharmony_ci    struct TimerEntry {
1283f4cbf05Sopenharmony_ci        uint32_t       timerId;  // Unique ID.
1293f4cbf05Sopenharmony_ci        uint32_t       interval;  // million second
1303f4cbf05Sopenharmony_ci        TimerCallback  callback;
1313f4cbf05Sopenharmony_ci        bool           once;
1323f4cbf05Sopenharmony_ci        int            timerFd;
1333f4cbf05Sopenharmony_ci    };
1343f4cbf05Sopenharmony_ci
1353f4cbf05Sopenharmony_ci    using TimerEntryPtr = std::shared_ptr<TimerEntry>;
1363f4cbf05Sopenharmony_ci    using TimerEntryList = std::list<TimerEntryPtr>;
1373f4cbf05Sopenharmony_ci
1383f4cbf05Sopenharmony_ci    std::map<uint32_t, TimerEntryList> intervalToTimers_;  // interval to TimerEntryList
1393f4cbf05Sopenharmony_ci    std::map<uint32_t, TimerEntryPtr> timerToEntries_;  // timer_id to TimerEntry
1403f4cbf05Sopenharmony_ci
1413f4cbf05Sopenharmony_ci    std::string name_;
1423f4cbf05Sopenharmony_ci    int timeoutMs_;
1433f4cbf05Sopenharmony_ci    std::thread thread_;
1443f4cbf05Sopenharmony_ci    EventReactor *reactor_;
1453f4cbf05Sopenharmony_ci    std::map<uint32_t, uint32_t> timers_;  // timer_fd to interval
1463f4cbf05Sopenharmony_ci    std::mutex mutex_;
1473f4cbf05Sopenharmony_ci};
1483f4cbf05Sopenharmony_ci
1493f4cbf05Sopenharmony_ci} // namespace Utils
1503f4cbf05Sopenharmony_ci} // namespace OHOS
1513f4cbf05Sopenharmony_ci#endif
1523f4cbf05Sopenharmony_ci
153