1/*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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#include "timeout_timer.h"
17#include <chrono>
18#include <condition_variable>
19#include <cstdio>
20#include <cstring>
21#include <sys/time.h>
22#include "common/media_log.h"
23namespace OHOS {
24namespace Sharing {
25
26#define TIMER_TIMEOUT 2
27TimeoutTimer::TimeoutTimer(std::string info)
28{
29    SHARING_LOGD("trace.");
30    thread_ = std::make_unique<std::thread>(&TimeoutTimer::MainLoop, this);
31    pthread_setname_np(thread_->native_handle(), info.c_str());
32}
33
34TimeoutTimer::~TimeoutTimer()
35{
36    SHARING_LOGD("dtor in %{public}d.", state_);
37    {
38        std::unique_lock<std::mutex> taskLock(taskMutex_);
39        if (state_ == State::WAITING) {
40            state_ = State::EXITED;
41            taskSignal_.notify_all();
42        } else if (state_ == State::WORKING) {
43            state_ = State::EXITED;
44            cancelSignal_.notify_all();
45        } else {
46            state_ = State::EXITED;
47        }
48    }
49
50    SHARING_LOGD("thread join %{public}d.", state_);
51    if (thread_->joinable()) {
52        thread_->join();
53    }
54    SHARING_LOGD("dtor out %{public}d.", state_);
55}
56
57void TimeoutTimer::StartTimer(int timeout, std::string info, std::function<void()> callback, bool reuse)
58{
59    SHARING_LOGD("add timeout timer (%{public}s).", info.c_str());
60    std::lock_guard<std::mutex> lock(taskMutex_);
61    reuse_ = reuse;
62    timeout_ = timeout;
63    if (state_ == State::WORKING) {
64        SHARING_LOGD("cancel timeout timer (%{public}s).", taskName_.c_str());
65        state_ = State::CANCELLED;
66        cancelSignal_.notify_all();
67
68        std::unique_lock<std::mutex> waitLock(waitMutex_);
69        waitSignal_.wait_for(waitLock, std::chrono::milliseconds(TIMER_TIMEOUT));
70    }
71    taskName_ = std::move(info);
72    if (callback) {
73        callback_ = std::move(callback);
74    }
75    taskSignal_.notify_all();
76    SHARING_LOGD("start timeout timer (%{public}s) leave.", info.c_str());
77}
78
79void TimeoutTimer::StopTimer()
80{
81    SHARING_LOGD("cancel timeout timer (%{public}s).", taskName_.c_str());
82    std::lock_guard<std::mutex> lock(taskMutex_);
83
84    if (state_ == State::WORKING) {
85        state_ = State::CANCELLED;
86        cancelSignal_.notify_all();
87        std::unique_lock<std::mutex> waitLock(waitMutex_);
88        waitSignal_.wait_for(waitLock, std::chrono::milliseconds(TIMER_TIMEOUT));
89    }
90    SHARING_LOGD("cancel timeout timer (%{public}s) leave.", taskName_.c_str());
91}
92
93void TimeoutTimer::MainLoop()
94{
95    SHARING_LOGD("trace.");
96    while (state_ != State::EXITED) {
97        std::unique_lock<std::mutex> taskLock(taskMutex_);
98        if (state_ == State::EXITED) {
99            break;
100        }
101
102        state_ = State::WAITING;
103        waitSignal_.notify_all();
104        if (!reuse_) {
105            taskSignal_.wait(taskLock);
106        }
107
108        if (state_ == State::EXITED) {
109            break;
110        }
111
112        state_ = State::WORKING;
113        SHARING_LOGI("start timeout timer(%{public}s).", taskName_.c_str());
114        cancelSignal_.wait_for(taskLock, std::chrono::seconds(timeout_));
115        if (state_ == State::WORKING && callback_) {
116            SHARING_LOGI("invoke timeout timer(%{public}s) callback.", taskName_.c_str());
117            callback_();
118        }
119        SHARING_LOGI("end timeout timer(%{public}s).", taskName_.c_str());
120    }
121    SHARING_LOGD("exit.");
122}
123
124void TimeoutTimer::SetTimeoutCallback(std::function<void()> callback)
125{
126    callback_ = std::move(callback);
127}
128} // namespace Sharing
129} // namespace OHOS