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 "Thread"
17
18 #include "osal/task/thread.h"
19 #include "common/log.h"
20 #include "osal/task/autolock.h"
21
22 #include "qos.h"
23 #include "res_type.h"
24 #include "res_sched_client.h"
25
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "Thread" };
28 constexpr uint32_t RES_TYPE = OHOS::ResourceSchedule::ResType::RES_TYPE_THREAD_QOS_CHANGE;
29 constexpr int64_t RES_VALUE = 0;
30 }
31
32 namespace OHOS {
33 namespace Media {
Thread(ThreadPriority priority)34 Thread::Thread(ThreadPriority priority) noexcept : id_(), name_(), priority_(priority), state_()
35 {
36 }
37
Thread(Thread && other)38 Thread::Thread(Thread&& other) noexcept
39 {
40 *this = std::move(other);
41 }
42
operator =(Thread && other)43 Thread& Thread::operator=(Thread&& other) noexcept
44 {
45 if (this != &other) {
46 AutoLock lock(mutex_);
47 id_ = other.id_;
48 name_ = std::move(other.name_);
49 priority_ = other.priority_;
50 state_ = std::move(other.state_);
51 }
52 return *this;
53 }
54
~Thread()55 Thread::~Thread() noexcept
56 {
57 if (isExistThread_.load()) {
58 pthread_join(id_, nullptr);
59 }
60 }
61
HasThread() const62 bool Thread::HasThread() const noexcept
63 {
64 AutoLock lock(mutex_);
65 return state_ != nullptr;
66 }
67
SetName(const std::string & name)68 void Thread::SetName(const std::string& name)
69 {
70 name_ = name;
71 }
72
CreateThread(const std::function<void ()> & func)73 bool Thread::CreateThread(const std::function<void()>& func)
74 {
75 {
76 AutoLock lock(mutex_);
77 state_ = std::make_unique<State>();
78 state_->func = func;
79 state_->name = name_;
80 }
81 pthread_attr_t attr;
82 pthread_attr_init(&attr);
83 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
84 #ifdef OHOS_LITE
85 // Only OHOS_LITE can set inheritsched and schedpolicy.
86 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
87 pthread_attr_setschedpolicy(&attr, SCHED_RR);
88 #endif
89 struct sched_param sched = {static_cast<int>(priority_)};
90 pthread_attr_setschedparam(&attr, &sched);
91 #if defined(THREAD_STACK_SIZE) and THREAD_STACK_SIZE > 0
92 pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
93 MEDIA_LOG_I("thread stack size set to " PUBLIC_LOG_D32, THREAD_STACK_SIZE);
94 #endif
95 int rtv = pthread_create(&id_, &attr, Thread::Run, this);
96 if (rtv == 0) {
97 MEDIA_LOG_I("thread " PUBLIC_LOG_S " create success", name_.c_str());
98 isExistThread_.store(true);
99 SetNameInternal();
100 } else {
101 AutoLock lock(mutex_);
102 if (state_ != nullptr) {
103 state_.reset();
104 }
105 MEDIA_LOG_E("thread create failed, name: " PUBLIC_LOG_S ", rtv: " PUBLIC_LOG_D32, name_.c_str(), rtv);
106 }
107 return rtv == 0;
108 }
109
IsRunningInSelf()110 bool Thread::IsRunningInSelf()
111 {
112 pthread_t tid = pthread_self();
113 AutoLock lock(mutex_);
114 return tid == id_;
115 }
116
SetNameInternal()117 void Thread::SetNameInternal()
118 {
119 AutoLock lock(mutex_);
120 if (state_ && !name_.empty()) {
121 constexpr int threadNameMaxSize = 15;
122 if (name_.size() > threadNameMaxSize) {
123 MEDIA_LOG_W("task name " PUBLIC_LOG_S " exceed max size: " PUBLIC_LOG_D32,
124 name_.c_str(), threadNameMaxSize);
125 name_ = name_.substr(0, threadNameMaxSize);
126 }
127 pthread_setname_np(id_, name_.c_str());
128 }
129 }
130
UpdateThreadPriority(const uint32_t newPriority,const std::string & strBundleName)131 void Thread::UpdateThreadPriority(const uint32_t newPriority, const std::string &strBundleName)
132 {
133 MEDIA_LOG_I("winddraw update priority %{public}u %{public}s", newPriority, std::to_string(gettid()).c_str());
134 std::unordered_map<std::string, std::string> mapPayload;
135 mapPayload["bundleName"] = strBundleName;
136 mapPayload["pid"] = std::to_string(getpid());
137 mapPayload[std::to_string(gettid())] = std::to_string(newPriority);
138 OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(RES_TYPE, RES_VALUE, mapPayload);
139 }
140
141
Run(void * arg)142 void* Thread::Run(void* arg) // NOLINT: void*
143 {
144 std::function<void()> func;
145 std::string name;
146 {
147 auto currentThread = static_cast<Thread *>(arg);
148 AutoLock lock(currentThread->mutex_);
149 auto state = currentThread->state_.get();
150 if (state == nullptr) {
151 return nullptr;
152 }
153 func = state->func;
154 name = state->name;
155 }
156 func();
157 {
158 auto currentThread = static_cast<Thread *>(arg);
159 AutoLock lock(currentThread->mutex_);
160 currentThread->state_ = nullptr;
161 }
162 MEDIA_LOG_W("Thread " PUBLIC_LOG_S " exited...", name.c_str());
163 return nullptr;
164 }
165 } // namespace Media
166 } // namespace OHOS
167