• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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