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
22namespace {
23constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "Thread" };
24}
25
26namespace OHOS {
27namespace Media {
28Thread::Thread(ThreadPriority priority) noexcept : id_(), name_(), priority_(priority), state_()
29{
30}
31
32Thread::Thread(Thread&& other) noexcept
33{
34    *this = std::move(other);
35}
36
37Thread& 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
49Thread::~Thread() noexcept
50{
51    if (isExistThread_.load()) {
52        pthread_join(id_, nullptr);
53    }
54}
55
56bool Thread::HasThread() const noexcept
57{
58    AutoLock lock(mutex_);
59    return state_ != nullptr;
60}
61
62void Thread::SetName(const std::string& name)
63{
64    name_ = name;
65}
66
67bool 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_D("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
104bool Thread::IsRunningInSelf()
105{
106    pthread_t tid = pthread_self();
107    AutoLock lock(mutex_);
108    return tid == id_;
109}
110
111void 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
125void* 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