1e0e9324cSopenharmony_ci/*
2e0e9324cSopenharmony_ci * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3e0e9324cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e0e9324cSopenharmony_ci * you may not use this file except in compliance with the License.
5e0e9324cSopenharmony_ci * You may obtain a copy of the License at
6e0e9324cSopenharmony_ci *
7e0e9324cSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e0e9324cSopenharmony_ci *
9e0e9324cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e0e9324cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e0e9324cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e0e9324cSopenharmony_ci * See the License for the specific language governing permissions and
13e0e9324cSopenharmony_ci * limitations under the License.
14e0e9324cSopenharmony_ci */
15e0e9324cSopenharmony_ci
16e0e9324cSopenharmony_ci#include "timeout_timer.h"
17e0e9324cSopenharmony_ci#include <chrono>
18e0e9324cSopenharmony_ci#include <condition_variable>
19e0e9324cSopenharmony_ci#include <cstdio>
20e0e9324cSopenharmony_ci#include <cstring>
21e0e9324cSopenharmony_ci#include <sys/time.h>
22e0e9324cSopenharmony_ci#include "common/media_log.h"
23e0e9324cSopenharmony_cinamespace OHOS {
24e0e9324cSopenharmony_cinamespace Sharing {
25e0e9324cSopenharmony_ci
26e0e9324cSopenharmony_ci#define TIMER_TIMEOUT 2
27e0e9324cSopenharmony_ciTimeoutTimer::TimeoutTimer(std::string info)
28e0e9324cSopenharmony_ci{
29e0e9324cSopenharmony_ci    SHARING_LOGD("trace.");
30e0e9324cSopenharmony_ci    thread_ = std::make_unique<std::thread>(&TimeoutTimer::MainLoop, this);
31e0e9324cSopenharmony_ci    pthread_setname_np(thread_->native_handle(), info.c_str());
32e0e9324cSopenharmony_ci}
33e0e9324cSopenharmony_ci
34e0e9324cSopenharmony_ciTimeoutTimer::~TimeoutTimer()
35e0e9324cSopenharmony_ci{
36e0e9324cSopenharmony_ci    SHARING_LOGD("dtor in %{public}d.", state_);
37e0e9324cSopenharmony_ci    {
38e0e9324cSopenharmony_ci        std::unique_lock<std::mutex> taskLock(taskMutex_);
39e0e9324cSopenharmony_ci        if (state_ == State::WAITING) {
40e0e9324cSopenharmony_ci            state_ = State::EXITED;
41e0e9324cSopenharmony_ci            taskSignal_.notify_all();
42e0e9324cSopenharmony_ci        } else if (state_ == State::WORKING) {
43e0e9324cSopenharmony_ci            state_ = State::EXITED;
44e0e9324cSopenharmony_ci            cancelSignal_.notify_all();
45e0e9324cSopenharmony_ci        } else {
46e0e9324cSopenharmony_ci            state_ = State::EXITED;
47e0e9324cSopenharmony_ci        }
48e0e9324cSopenharmony_ci    }
49e0e9324cSopenharmony_ci
50e0e9324cSopenharmony_ci    SHARING_LOGD("thread join %{public}d.", state_);
51e0e9324cSopenharmony_ci    if (thread_->joinable()) {
52e0e9324cSopenharmony_ci        thread_->join();
53e0e9324cSopenharmony_ci    }
54e0e9324cSopenharmony_ci    SHARING_LOGD("dtor out %{public}d.", state_);
55e0e9324cSopenharmony_ci}
56e0e9324cSopenharmony_ci
57e0e9324cSopenharmony_civoid TimeoutTimer::StartTimer(int timeout, std::string info, std::function<void()> callback, bool reuse)
58e0e9324cSopenharmony_ci{
59e0e9324cSopenharmony_ci    SHARING_LOGD("add timeout timer (%{public}s).", info.c_str());
60e0e9324cSopenharmony_ci    std::lock_guard<std::mutex> lock(taskMutex_);
61e0e9324cSopenharmony_ci    reuse_ = reuse;
62e0e9324cSopenharmony_ci    timeout_ = timeout;
63e0e9324cSopenharmony_ci    if (state_ == State::WORKING) {
64e0e9324cSopenharmony_ci        SHARING_LOGD("cancel timeout timer (%{public}s).", taskName_.c_str());
65e0e9324cSopenharmony_ci        state_ = State::CANCELLED;
66e0e9324cSopenharmony_ci        cancelSignal_.notify_all();
67e0e9324cSopenharmony_ci
68e0e9324cSopenharmony_ci        std::unique_lock<std::mutex> waitLock(waitMutex_);
69e0e9324cSopenharmony_ci        waitSignal_.wait_for(waitLock, std::chrono::milliseconds(TIMER_TIMEOUT));
70e0e9324cSopenharmony_ci    }
71e0e9324cSopenharmony_ci    taskName_ = std::move(info);
72e0e9324cSopenharmony_ci    if (callback) {
73e0e9324cSopenharmony_ci        callback_ = std::move(callback);
74e0e9324cSopenharmony_ci    }
75e0e9324cSopenharmony_ci    taskSignal_.notify_all();
76e0e9324cSopenharmony_ci    SHARING_LOGD("start timeout timer (%{public}s) leave.", info.c_str());
77e0e9324cSopenharmony_ci}
78e0e9324cSopenharmony_ci
79e0e9324cSopenharmony_civoid TimeoutTimer::StopTimer()
80e0e9324cSopenharmony_ci{
81e0e9324cSopenharmony_ci    SHARING_LOGD("cancel timeout timer (%{public}s).", taskName_.c_str());
82e0e9324cSopenharmony_ci    std::lock_guard<std::mutex> lock(taskMutex_);
83e0e9324cSopenharmony_ci
84e0e9324cSopenharmony_ci    if (state_ == State::WORKING) {
85e0e9324cSopenharmony_ci        state_ = State::CANCELLED;
86e0e9324cSopenharmony_ci        cancelSignal_.notify_all();
87e0e9324cSopenharmony_ci        std::unique_lock<std::mutex> waitLock(waitMutex_);
88e0e9324cSopenharmony_ci        waitSignal_.wait_for(waitLock, std::chrono::milliseconds(TIMER_TIMEOUT));
89e0e9324cSopenharmony_ci    }
90e0e9324cSopenharmony_ci    SHARING_LOGD("cancel timeout timer (%{public}s) leave.", taskName_.c_str());
91e0e9324cSopenharmony_ci}
92e0e9324cSopenharmony_ci
93e0e9324cSopenharmony_civoid TimeoutTimer::MainLoop()
94e0e9324cSopenharmony_ci{
95e0e9324cSopenharmony_ci    SHARING_LOGD("trace.");
96e0e9324cSopenharmony_ci    while (state_ != State::EXITED) {
97e0e9324cSopenharmony_ci        std::unique_lock<std::mutex> taskLock(taskMutex_);
98e0e9324cSopenharmony_ci        if (state_ == State::EXITED) {
99e0e9324cSopenharmony_ci            break;
100e0e9324cSopenharmony_ci        }
101e0e9324cSopenharmony_ci
102e0e9324cSopenharmony_ci        state_ = State::WAITING;
103e0e9324cSopenharmony_ci        waitSignal_.notify_all();
104e0e9324cSopenharmony_ci        if (!reuse_) {
105e0e9324cSopenharmony_ci            taskSignal_.wait(taskLock);
106e0e9324cSopenharmony_ci        }
107e0e9324cSopenharmony_ci
108e0e9324cSopenharmony_ci        if (state_ == State::EXITED) {
109e0e9324cSopenharmony_ci            break;
110e0e9324cSopenharmony_ci        }
111e0e9324cSopenharmony_ci
112e0e9324cSopenharmony_ci        state_ = State::WORKING;
113e0e9324cSopenharmony_ci        SHARING_LOGI("start timeout timer(%{public}s).", taskName_.c_str());
114e0e9324cSopenharmony_ci        cancelSignal_.wait_for(taskLock, std::chrono::seconds(timeout_));
115e0e9324cSopenharmony_ci        if (state_ == State::WORKING && callback_) {
116e0e9324cSopenharmony_ci            SHARING_LOGI("invoke timeout timer(%{public}s) callback.", taskName_.c_str());
117e0e9324cSopenharmony_ci            callback_();
118e0e9324cSopenharmony_ci        }
119e0e9324cSopenharmony_ci        SHARING_LOGI("end timeout timer(%{public}s).", taskName_.c_str());
120e0e9324cSopenharmony_ci    }
121e0e9324cSopenharmony_ci    SHARING_LOGD("exit.");
122e0e9324cSopenharmony_ci}
123e0e9324cSopenharmony_ci
124e0e9324cSopenharmony_civoid TimeoutTimer::SetTimeoutCallback(std::function<void()> callback)
125e0e9324cSopenharmony_ci{
126e0e9324cSopenharmony_ci    callback_ = std::move(callback);
127e0e9324cSopenharmony_ci}
128e0e9324cSopenharmony_ci} // namespace Sharing
129e0e9324cSopenharmony_ci} // namespace OHOS