1 /*
2  * Copyright (C) 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 #include "task_thread.h"
17 #include "avcodec_log.h"
18 
19 namespace {
20     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "TaskThread"};
21     constexpr uint8_t LOGD_FREQUENCY = 100;
22 }
23 namespace OHOS {
24 namespace MediaAVCodec {
TaskThread(std::string_view name)25 TaskThread::TaskThread(std::string_view name) : name_(name), runningState_(RunningState::STOPPED), loop_(nullptr)
26 {
27     AVCODEC_LOGD("task %{public}s ctor called", name_.data());
28 }
29 
TaskThread(std::string_view name,std::function<void ()> handler)30 TaskThread::TaskThread(std::string_view name, std::function<void()> handler) : TaskThread(name)
31 {
32     handler_ = std::move(handler);
33     loop_ = std::make_unique<std::thread>(&TaskThread::Run, this);
34 }
35 
~TaskThread()36 TaskThread::~TaskThread()
37 {
38     AVCODEC_LOGD("task %{public}s dtor called", name_.data());
39     runningState_ = RunningState::STOPPED;
40     syncCond_.notify_all();
41 
42     if (loop_ != nullptr) {
43         if (loop_->joinable()) {
44             loop_->join();
45         }
46         loop_ = nullptr;
47     }
48 }
49 
Start()50 void TaskThread::Start()
51 {
52     std::unique_lock lock(stateMutex_);
53     if (runningState_.load() == RunningState::STOPPING) {
54         syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
55     }
56     if (runningState_.load() == RunningState::STOPPED) {
57         if (loop_ != nullptr) {
58             if (loop_->joinable()) {
59                 loop_->join();
60             }
61             loop_ = nullptr;
62         }
63     }
64 
65     runningState_ = RunningState::STARTED;
66 
67     if (!loop_) { // thread not exist
68         loop_ = std::make_unique<std::thread>(&TaskThread::Run, this);
69     }
70     syncCond_.notify_all();
71     AVCODEC_LOGD("task %{public}s start called", name_.data());
72 }
73 
Stop()74 void TaskThread::Stop()
75 {
76     AVCODEC_LOGD("task %{public}s stop entered, current state: %{public}d", name_.data(), runningState_.load());
77     std::unique_lock lock(stateMutex_);
78     if (runningState_.load() != RunningState::STOPPED) {
79         runningState_ = RunningState::STOPPING;
80         syncCond_.notify_all();
81         syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
82         if (loop_ != nullptr) {
83             if (loop_->joinable()) {
84                 loop_->join();
85             }
86             loop_ = nullptr;
87         }
88     }
89     AVCODEC_LOGD("task %{public}s stop exited", name_.data());
90 }
91 
StopAsync()92 void TaskThread::StopAsync()
93 {
94     AVCODEC_LOGD("task %{public}s StopAsync called", name_.data());
95     std::unique_lock lock(stateMutex_);
96     if (runningState_.load() != RunningState::STOPPING && runningState_.load() != RunningState::STOPPED) {
97         runningState_ = RunningState::STOPPING;
98         syncCond_.notify_all();
99     }
100 }
101 
Pause()102 void TaskThread::Pause()
103 {
104     AVCODEC_LOGD("task %{public}s Pause called", name_.data());
105     std::unique_lock lock(stateMutex_);
106     switch (runningState_.load()) {
107         case RunningState::STARTED: {
108             runningState_ = RunningState::PAUSING;
109             syncCond_.wait(lock, [this] {
110                 return runningState_.load() == RunningState::PAUSED || runningState_.load() == RunningState::STOPPED;
111             });
112             break;
113         }
114         case RunningState::STOPPING: {
115             syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
116             break;
117         }
118         case RunningState::PAUSING: {
119             syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::PAUSED; });
120             break;
121         }
122         default:
123             break;
124     }
125     AVCODEC_LOGD("task %{public}s Pause done.", name_.data());
126 }
127 
PauseAsync()128 void TaskThread::PauseAsync()
129 {
130     AVCODEC_LOGD("task %{public}s PauseAsync called", name_.data());
131     std::unique_lock lock(stateMutex_);
132     if (runningState_.load() == RunningState::STARTED) {
133         runningState_ = RunningState::PAUSING;
134     }
135 }
136 
RegisterHandler(std::function<void ()> handler)137 void TaskThread::RegisterHandler(std::function<void()> handler)
138 {
139     AVCODEC_LOGD("task %{public}s RegisterHandler called", name_.data());
140     handler_ = std::move(handler);
141 }
142 
doTask()143 void TaskThread::doTask()
144 {
145     AVCODEC_LOGD("task %{public}s not override DoTask...", name_.data());
146 }
147 
Run()148 void TaskThread::Run()
149 {
150     // The max length for a thread name is 16.
151     auto ret = pthread_setname_np(pthread_self(), name_.data());
152     if (ret != 0) {
153         AVCODEC_LOGE("task %{public}s set name failed", name_.data());
154     }
155     for (;;) {
156         AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "task %{public}s is running on state : %{public}d",
157             name_.data(), runningState_.load());
158         if (runningState_.load() == RunningState::STARTED) {
159             handler_();
160         }
161         std::unique_lock lock(stateMutex_);
162         if (runningState_.load() == RunningState::PAUSING || runningState_.load() == RunningState::PAUSED) {
163             runningState_ = RunningState::PAUSED;
164             syncCond_.notify_all();
165             constexpr int timeoutMs = 500;
166             syncCond_.wait_for(lock, std::chrono::milliseconds(timeoutMs),
167                                [this] { return runningState_.load() != RunningState::PAUSED; });
168         }
169         if (runningState_.load() == RunningState::STOPPING || runningState_.load() == RunningState::STOPPED) {
170             runningState_ = RunningState::STOPPED;
171             syncCond_.notify_all();
172             break;
173         }
174     }
175 }
176 } // namespace MediaAVCodec
177 } // namespace OHOS