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 "common/log.h"
20
21namespace {
22constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "Task" };
23}
24
25namespace OHOS {
26namespace Media {
27// ffrt::qos priority sorting:qos_utility < qos_default < qos_user_initiated <
28// qos_deadline_request < qos_user_interactive
29ffrt::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
45Task::Task(std::string name, TaskPriority priority)
46    : name_(std::move(name)), priority_(priority), runningState_(RunningState::STOPPED)
47{
48    MEDIA_LOG_I("task " PUBLIC_LOG_S " ctor called", name_.c_str());
49}
50
51Task::Task(std::string name, std::function<void()> job, TaskPriority priority)
52    : Task(std::move(name), priority)
53{
54    MEDIA_LOG_I("task " PUBLIC_LOG_S " ctor called", name_.c_str());
55    job_ = std::move(job);
56}
57
58Task::~Task()
59{
60    MEDIA_LOG_I("task " PUBLIC_LOG_S " dtor called", name_.c_str());
61    runningState_ = RunningState::STOPPED;
62    syncCond_.NotifyAll();
63}
64
65void 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
80void 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
99void 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
108void 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
135void 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
144void 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
150void Task::DoTask()
151{
152    MEDIA_LOG_D("task " PUBLIC_LOG_S " not override DoTask...", name_.c_str());
153}
154
155void 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