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 
16 #define HST_LOG_TAG "Task"
17 
18 #include "osal/task/task.h"
19 #include "inner_api/common/log.h"
20 
21 namespace {
22 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "Task" };
23 }
24 
25 namespace OHOS {
26 namespace Media {
27 // ffrt::qos priority sorting:qos_utility < qos_default < qos_user_initiated <
28 // qos_deadline_request < qos_user_interactive
ConvertPriorityType(TaskPriority priority)29 ffrt::qos ConvertPriorityType(TaskPriority priority)
30 {
31     switch (priority) {
32         case TaskPriority::LOW:
33             return ffrt::qos_utility;
34         case TaskPriority::NORMAL:
35             return ffrt::qos_default;
36         case TaskPriority::MIDDLE:
37             return ffrt::qos_user_initiated;
38         case TaskPriority::HIGHEST:
39             return ffrt::qos_user_interactive;
40         default:
41             return ffrt::qos_deadline_request;
42     }
43 }
44 
Task(std::string name,TaskPriority priority)45 Task::Task(std::string name, TaskPriority priority)
46     : name_(std::move(name)), priority_(priority), runningState_(RunningState::STOPPED)
47 {
48     MEDIA_LOG_D("task " PUBLIC_LOG_S " ctor called", name_.c_str());
49 }
50 
Task(std::string name,std::function<void ()> job,TaskPriority priority)51 Task::Task(std::string name, std::function<void()> job, TaskPriority priority)
52     : Task(std::move(name), priority)
53 {
54     MEDIA_LOG_D("task " PUBLIC_LOG_S " ctor called", name_.c_str());
55     job_ = std::move(job);
56 }
57 
~Task()58 Task::~Task()
59 {
60     MEDIA_LOG_I("task " PUBLIC_LOG_S " dtor called", name_.c_str());
61     runningState_ = RunningState::STOPPED;
62     syncCond_.NotifyAll();
63 }
64 
Start()65 void Task::Start()
66 {
67     MEDIA_LOG_I("task " PUBLIC_LOG_S " start called", name_.c_str());
68     AutoLock lock(stateMutex_);
69     runningState_ = RunningState::STARTED;
70     if (!loop_) {
71         loop_ = std::make_unique<ffrt::thread>(name_.c_str(), ConvertPriorityType(priority_), [this] { Run(); });
72     }
73     if (!loop_) {
74         MEDIA_LOG_E("task " PUBLIC_LOG_S " create failed", name_.c_str());
75     } else {
76         syncCond_.NotifyAll();
77     }
78 }
79 
Stop()80 void Task::Stop()
81 {
82     MEDIA_LOG_W("task " PUBLIC_LOG_S " stop entered, current state: " PUBLIC_LOG_D32,
83                 name_.c_str(), runningState_.load());
84     AutoLock lock(stateMutex_);
85     if (runningState_.load() != RunningState::STOPPED) {
86         runningState_ = RunningState::STOPPING;
87         syncCond_.NotifyAll();
88         syncCond_.Wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
89         if (loop_) {
90             if (loop_->joinable()) {
91                 loop_->join();
92             }
93             loop_ = nullptr;
94         }
95     }
96     MEDIA_LOG_W("task " PUBLIC_LOG_S " stop exited", name_.c_str());
97 }
98 
StopAsync()99 void Task::StopAsync()
100 {
101     MEDIA_LOG_D("task " PUBLIC_LOG_S " StopAsync called", name_.c_str());
102     AutoLock lock(stateMutex_);
103     if (runningState_.load() != RunningState::STOPPED) {
104         runningState_ = RunningState::STOPPING;
105     }
106 }
107 
Pause()108 void Task::Pause()
109 {
110     AutoLock lock(stateMutex_);
111     RunningState state = runningState_.load();
112     MEDIA_LOG_I("task " PUBLIC_LOG_S " Pause called, running state = " PUBLIC_LOG_D32, name_.c_str(), state);
113     switch (state) {
114         case RunningState::STARTED: {
115             runningState_ = RunningState::PAUSING;
116             syncCond_.Wait(lock, [this] {
117                 return runningState_.load() == RunningState::PAUSED || runningState_.load() == RunningState::STOPPED;
118             });
119             break;
120         }
121         case RunningState::STOPPING: {
122             syncCond_.Wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; });
123             break;
124         }
125         case RunningState::PAUSING: {
126             syncCond_.Wait(lock, [this] { return runningState_.load() == RunningState::PAUSED; });
127             break;
128         }
129         default:
130             break;
131     }
132     MEDIA_LOG_I("task " PUBLIC_LOG_S " Pause done.", name_.c_str());
133 }
134 
PauseAsync()135 void Task::PauseAsync()
136 {
137     MEDIA_LOG_I("task " PUBLIC_LOG_S " PauseAsync called", name_.c_str());
138     AutoLock lock(stateMutex_);
139     if (runningState_.load() == RunningState::STARTED) {
140         runningState_ = RunningState::PAUSING;
141     }
142 }
143 
RegisterJob(std::function<void ()> job)144 void Task::RegisterJob(std::function<void()> job)
145 {
146     MEDIA_LOG_D("task " PUBLIC_LOG_S " RegisterJob called", name_.c_str());
147     job_ = std::move(job);
148 }
149 
DoTask()150 void Task::DoTask()
151 {
152     MEDIA_LOG_D("task " PUBLIC_LOG_S " not override DoTask...", name_.c_str());
153 }
154 
Run()155 void Task::Run()
156 {
157     for (;;) {
158         MEDIA_LOG_DD("task " PUBLIC_LOG_S " is running on state : " PUBLIC_LOG_D32,
159                      name_.c_str(), runningState_.load());
160         if (runningState_.load() == RunningState::STARTED) {
161             job_();
162         }
163         AutoLock lock(stateMutex_);
164         if (runningState_.load() == RunningState::PAUSING || runningState_.load() == RunningState::PAUSED) {
165             runningState_ = RunningState::PAUSED;
166             syncCond_.NotifyAll();
167             constexpr int timeoutMs = 500;
168             syncCond_.WaitFor(lock, timeoutMs, [this] { return runningState_.load() != RunningState::PAUSED; });
169         }
170         if (runningState_.load() == RunningState::STOPPING || runningState_.load() == RunningState::STOPPED) {
171             MEDIA_LOG_I("task " PUBLIC_LOG_S " is stopped", name_.c_str());
172             runningState_ = RunningState::STOPPED;
173             syncCond_.NotifyAll();
174             break;
175         }
176     }
177 }
178 } // namespace Media
179 } // namespace OHOS
180