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 #define HST_LOG_TAG "Task"
16 #include "osal/task/task.h"
17 #include "cpp_ext/memory_ext.h"
18 #include "common/log.h"
19
20 namespace OHOS {
21 namespace Media {
ConvertPriorityType(TaskPriority priority)22 ThreadPriority ConvertPriorityType(TaskPriority priority)
23 {
24 switch (priority) {
25 case TaskPriority::LOW:
26 return ThreadPriority::LOW;
27 case TaskPriority::NORMAL:
28 return ThreadPriority::NORMAL;
29 case TaskPriority::MIDDLE:
30 return ThreadPriority::MIDDLE;
31 case TaskPriority::HIGHEST:
32 return ThreadPriority::HIGHEST;
33 default:
34 return ThreadPriority::HIGH;
35 }
36 }
37
Task(std::string name,TaskPriority priority)38 Task::Task(std::string name, TaskPriority priority)
39 : name_(std::move(name)), priority_(priority), runningState_(RunningState::STOPPED)
40 {
41 MEDIA_LOG_D("task " PUBLIC_LOG_S " ctor called", name_.c_str());
42 loop_ = CppExt::make_unique<Thread>(ConvertPriorityType(priority));
43 loop_->SetName(name_);
44 }
45
Task(std::string name,std::function<void ()> job,TaskPriority priority)46 Task::Task(std::string name, std::function<void()> job, TaskPriority priority)
47 : Task(std::move(name), priority)
48 {
49 MEDIA_LOG_D("task " PUBLIC_LOG_S " ctor called", name_.c_str());
50 job_ = std::move(job);
51 }
52
~Task()53 Task::~Task()
54 {
55 MEDIA_LOG_I("task " PUBLIC_LOG_S " dtor called", name_.c_str());
56 {
57 AutoLock lock(stateMutex_);
58 runningState_ = RunningState::STOPPED;
59 }
60 syncCond_.NotifyAll();
61 }
62
Start()63 void Task::Start()
64 {
65 MEDIA_LOG_I("task " PUBLIC_LOG_S " Start called", name_.c_str());
66 AutoLock lock(stateMutex_);
67 if (loop_ && loop_->HasThread()) {
68 MEDIA_LOG_W("task " PUBLIC_LOG_S " has created, current state: " PUBLIC_LOG_D32,
69 name_.c_str(), runningState_.load());
70 runningState_ = RunningState::STARTED;
71 syncCond_.NotifyAll();
72 return;
73 }
74
75 if (!loop_) { // thread not exist
76 loop_ = CppExt::make_unique<Thread>(ConvertPriorityType(priority_));
77 loop_->SetName(name_);
78 }
79
80 if (loop_->CreateThread([this] { Run(); })) {
81 MEDIA_LOG_I("task " PUBLIC_LOG_S " create success", name_.c_str());
82 runningState_ = RunningState::STARTED;
83 syncCond_.NotifyAll();
84 } else {
85 MEDIA_LOG_E("task " PUBLIC_LOG_S " create failed", name_.c_str());
86 }
87 }
88
Stop()89 void Task::Stop()
90 {
91 AutoLock lock(stateMutex_);
92 MEDIA_LOG_W("task " PUBLIC_LOG_S " Stop entered, current state: " PUBLIC_LOG_D32,
93 name_.c_str(), runningState_.load());
94 if (runningState_.load() != RunningState::STOPPED) {
95 runningState_ = RunningState::STOPPING;
96 if (loop_ && !(loop_->IsRunningInSelf())) {
97 // There is no need to perform notification in task's self thread, as no call would wait for STOPPING state.
98 // Perform notification to accelerate stopping when the task is already in PAUSED state.
99 syncCond_.NotifyAll();
100 syncCond_.Wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
101 if (loop_->HasThread()) {
102 loop_ = nullptr;
103 }
104 MEDIA_LOG_W("task " PUBLIC_LOG_S " Stop done", name_.c_str());
105 } else {
106 MEDIA_LOG_W("task " PUBLIC_LOG_S " can't use Task::Stop in self task, now replaced by Task::StopAsync",
107 name_.c_str());
108 }
109 }
110 }
111
StopAsync()112 void Task::StopAsync()
113 {
114 {
115 AutoLock lock(stateMutex_);
116 MEDIA_LOG_W("task " PUBLIC_LOG_S " StopAsync called, current state: " PUBLIC_LOG_D32,
117 name_.c_str(), runningState_.load());
118 if (runningState_.load() != RunningState::STOPPED) {
119 runningState_ = RunningState::STOPPING;
120 }
121 }
122 // Perform notification to accelerate stopping when the task is already in PAUSED state.
123 syncCond_.NotifyAll();
124 }
125
Pause()126 void Task::Pause()
127 {
128 AutoLock lock(stateMutex_);
129 RunningState state = runningState_.load();
130 MEDIA_LOG_I("task " PUBLIC_LOG_S " Pause called, current state: " PUBLIC_LOG_D32, name_.c_str(), state);
131 if (loop_ && loop_->IsRunningInSelf()) {
132 if (state == RunningState::STARTED) {
133 runningState_ = RunningState::PAUSING;
134 }
135 MEDIA_LOG_W("task " PUBLIC_LOG_S " can't use Task::Pause in self task, now replaced by Task::PauseAsync",
136 name_.c_str());
137 return;
138 }
139 switch (state) {
140 case RunningState::STARTED: {
141 runningState_ = RunningState::PAUSING;
142 syncCond_.Wait(lock, [this] {
143 return runningState_.load() == RunningState::PAUSED || runningState_.load() == RunningState::STOPPED;
144 });
145 break;
146 }
147 case RunningState::STOPPING: {
148 syncCond_.Wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
149 break;
150 }
151 case RunningState::PAUSING: {
152 syncCond_.Wait(lock, [this] {
153 return runningState_.load() == RunningState::PAUSED || runningState_.load() == RunningState::STOPPED;
154 });
155 break;
156 }
157 default:
158 break;
159 }
160 MEDIA_LOG_I("task " PUBLIC_LOG_S " Pause done.", name_.c_str());
161 }
162
163
164 // There is no need to perform notification, as no call would wait for PAUSING state.
165 // If perform notification may cause unnecessasy running when the task is already in PAUSED state.
PauseAsync()166 void Task::PauseAsync()
167 {
168 MEDIA_LOG_I("task " PUBLIC_LOG_S " PauseAsync called", name_.c_str());
169 AutoLock lock(stateMutex_);
170 if (runningState_.load() == RunningState::STARTED) {
171 runningState_ = RunningState::PAUSING;
172 }
173 }
174
RegisterJob(std::function<void ()> job)175 void Task::RegisterJob(std::function<void()> job)
176 {
177 MEDIA_LOG_I("task " PUBLIC_LOG_S " RegisterHandler called", name_.c_str());
178 job_ = std::move(job);
179 }
180
DoTask()181 void Task::DoTask()
182 {
183 MEDIA_LOG_D("task " PUBLIC_LOG_S " not override DoTask...", name_.c_str());
184 }
185
Run()186 void Task::Run()
187 {
188 for (;;) {
189 MEDIA_LOG_DD("task " PUBLIC_LOG_S " is running on state: " PUBLIC_LOG_D32,
190 name_.c_str(), runningState_.load());
191 if (runningState_.load() == RunningState::STARTED) {
192 job_();
193 }
194 AutoLock lock(stateMutex_);
195 if (runningState_.load() == RunningState::PAUSING || runningState_.load() == RunningState::PAUSED) {
196 runningState_ = RunningState::PAUSED;
197 syncCond_.NotifyAll();
198 constexpr int timeoutMs = 500;
199 syncCond_.WaitFor(lock, timeoutMs, [this] { return runningState_.load() != RunningState::PAUSED; });
200 }
201 if (runningState_.load() == RunningState::STOPPING || runningState_.load() == RunningState::STOPPED) {
202 MEDIA_LOG_I("task " PUBLIC_LOG_S " is stopped", name_.c_str());
203 runningState_ = RunningState::STOPPED;
204 syncCond_.NotifyAll();
205 break;
206 }
207 }
208 }
209 } // namespace Media
210 } // namespace OHOS
211