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