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 19namespace { 20 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "TaskThread"}; 21 constexpr uint8_t LOGD_FREQUENCY = 100; 22} 23namespace OHOS { 24namespace MediaAVCodec { 25TaskThread::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 30TaskThread::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 36TaskThread::~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 50void 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 74void 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 92void 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 102void 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 128void 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 137void TaskThread::RegisterHandler(std::function<void()> handler) 138{ 139 AVCODEC_LOGD("task %{public}s RegisterHandler called", name_.data()); 140 handler_ = std::move(handler); 141} 142 143void TaskThread::doTask() 144{ 145 AVCODEC_LOGD("task %{public}s not override DoTask...", name_.data()); 146} 147 148void 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