13f4cbf05Sopenharmony_ci/* 23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License. 53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at 63f4cbf05Sopenharmony_ci * 73f4cbf05Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83f4cbf05Sopenharmony_ci * 93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and 133f4cbf05Sopenharmony_ci * limitations under the License. 143f4cbf05Sopenharmony_ci */ 153f4cbf05Sopenharmony_ci 163f4cbf05Sopenharmony_ci#include "thread_ex.h" 173f4cbf05Sopenharmony_ci#include <sys/resource.h> 183f4cbf05Sopenharmony_ci#include <sys/prctl.h> 193f4cbf05Sopenharmony_ci#include <iostream> 203f4cbf05Sopenharmony_ci#include "utils_log.h" 213f4cbf05Sopenharmony_ci 223f4cbf05Sopenharmony_cinamespace OHOS { 233f4cbf05Sopenharmony_ciusing ThreadFunc = int (*)(void*); 243f4cbf05Sopenharmony_ciusing PThreadRoutine = void* (*) (void*); 253f4cbf05Sopenharmony_ci 263f4cbf05Sopenharmony_cistruct ThreadParam { 273f4cbf05Sopenharmony_ci ThreadFunc startRoutine; 283f4cbf05Sopenharmony_ci void* args; 293f4cbf05Sopenharmony_ci int priority; 303f4cbf05Sopenharmony_ci std::string name; 313f4cbf05Sopenharmony_ci 323f4cbf05Sopenharmony_ci // prctl only support set the name of the calling process. 333f4cbf05Sopenharmony_ci static int Proxy(const ThreadParam* t) 343f4cbf05Sopenharmony_ci { 353f4cbf05Sopenharmony_ci if (t == nullptr) { 363f4cbf05Sopenharmony_ci UTILS_LOGD("invalid param."); 373f4cbf05Sopenharmony_ci return -1; 383f4cbf05Sopenharmony_ci } 393f4cbf05Sopenharmony_ci ThreadFunc f = t->startRoutine; 403f4cbf05Sopenharmony_ci void* userData = t->args; 413f4cbf05Sopenharmony_ci int prio = t->priority; 423f4cbf05Sopenharmony_ci std::string threadName = t->name; 433f4cbf05Sopenharmony_ci 443f4cbf05Sopenharmony_ci delete t; 453f4cbf05Sopenharmony_ci 463f4cbf05Sopenharmony_ci // set thread priority 473f4cbf05Sopenharmony_ci (void)setpriority(PRIO_PROCESS, 0, prio); 483f4cbf05Sopenharmony_ci 493f4cbf05Sopenharmony_ci // set thread name 503f4cbf05Sopenharmony_ci if (!threadName.empty()) { 513f4cbf05Sopenharmony_ci prctl(PR_SET_NAME, threadName.substr(0, MAX_THREAD_NAME_LEN).c_str(), 0, 0, 0); 523f4cbf05Sopenharmony_ci } 533f4cbf05Sopenharmony_ci 543f4cbf05Sopenharmony_ci return f(userData); 553f4cbf05Sopenharmony_ci } 563f4cbf05Sopenharmony_ci}; 573f4cbf05Sopenharmony_ci 583f4cbf05Sopenharmony_cibool CreatePThread(ThreadParam& para, size_t stackSize, pthread_t *threadId) 593f4cbf05Sopenharmony_ci 603f4cbf05Sopenharmony_ci{ 613f4cbf05Sopenharmony_ci pthread_attr_t attr; 623f4cbf05Sopenharmony_ci pthread_attr_init(&attr); 633f4cbf05Sopenharmony_ci 643f4cbf05Sopenharmony_ci // create thread as "detached", so it cleans up after itself. 653f4cbf05Sopenharmony_ci pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 663f4cbf05Sopenharmony_ci 673f4cbf05Sopenharmony_ci auto t = new ThreadParam; // t would be delete in ThreadParam::Proxy 683f4cbf05Sopenharmony_ci t->startRoutine = para.startRoutine; 693f4cbf05Sopenharmony_ci t->args = para.args; 703f4cbf05Sopenharmony_ci t->priority = para.priority; 713f4cbf05Sopenharmony_ci t->name = para.name; 723f4cbf05Sopenharmony_ci 733f4cbf05Sopenharmony_ci para.startRoutine = reinterpret_cast<ThreadFunc>(&ThreadParam::Proxy); 743f4cbf05Sopenharmony_ci para.args = t; 753f4cbf05Sopenharmony_ci 763f4cbf05Sopenharmony_ci if (stackSize) { 773f4cbf05Sopenharmony_ci pthread_attr_setstacksize(&attr, stackSize); 783f4cbf05Sopenharmony_ci } 793f4cbf05Sopenharmony_ci 803f4cbf05Sopenharmony_ci errno = 0; 813f4cbf05Sopenharmony_ci pthread_t thread; 823f4cbf05Sopenharmony_ci int result = pthread_create(&thread, &attr, reinterpret_cast<PThreadRoutine>(para.startRoutine), para.args); 833f4cbf05Sopenharmony_ci pthread_attr_destroy(&attr); 843f4cbf05Sopenharmony_ci para.args = nullptr; 853f4cbf05Sopenharmony_ci 863f4cbf05Sopenharmony_ci if (result != 0) { 873f4cbf05Sopenharmony_ci return false; 883f4cbf05Sopenharmony_ci } 893f4cbf05Sopenharmony_ci 903f4cbf05Sopenharmony_ci if (threadId != nullptr) { 913f4cbf05Sopenharmony_ci *threadId = thread; 923f4cbf05Sopenharmony_ci } 933f4cbf05Sopenharmony_ci 943f4cbf05Sopenharmony_ci return true; 953f4cbf05Sopenharmony_ci} 963f4cbf05Sopenharmony_ci 973f4cbf05Sopenharmony_ciThread::Thread() 983f4cbf05Sopenharmony_ci : thread_(INVALID_PTHREAD_T), status_(ThreadStatus::OK), exitPending_(false), running_(false) 993f4cbf05Sopenharmony_ci{ 1003f4cbf05Sopenharmony_ci} 1013f4cbf05Sopenharmony_ci 1023f4cbf05Sopenharmony_ciThread::~Thread() 1033f4cbf05Sopenharmony_ci{ 1043f4cbf05Sopenharmony_ci} 1053f4cbf05Sopenharmony_ci 1063f4cbf05Sopenharmony_ciThreadStatus Thread::Start(const std::string& name, int32_t priority, size_t stack) 1073f4cbf05Sopenharmony_ci{ 1083f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lk(lock_); 1093f4cbf05Sopenharmony_ci if (running_) { 1103f4cbf05Sopenharmony_ci // already started 1113f4cbf05Sopenharmony_ci return ThreadStatus::INVALID_OPERATION; 1123f4cbf05Sopenharmony_ci } 1133f4cbf05Sopenharmony_ci 1143f4cbf05Sopenharmony_ci status_ = ThreadStatus::OK; 1153f4cbf05Sopenharmony_ci exitPending_ = false; 1163f4cbf05Sopenharmony_ci thread_ = INVALID_PTHREAD_T; 1173f4cbf05Sopenharmony_ci running_ = true; 1183f4cbf05Sopenharmony_ci 1193f4cbf05Sopenharmony_ci ThreadParam para; 1203f4cbf05Sopenharmony_ci para.startRoutine = ThreadStart; 1213f4cbf05Sopenharmony_ci para.args = this; 1223f4cbf05Sopenharmony_ci para.name = name; 1233f4cbf05Sopenharmony_ci para.priority = priority; 1243f4cbf05Sopenharmony_ci 1253f4cbf05Sopenharmony_ci bool res = CreatePThread(para, stack, &thread_); 1263f4cbf05Sopenharmony_ci if (!res) { 1273f4cbf05Sopenharmony_ci status_ = ThreadStatus::UNKNOWN_ERROR; // something happened! 1283f4cbf05Sopenharmony_ci running_ = false; 1293f4cbf05Sopenharmony_ci thread_ = INVALID_PTHREAD_T; 1303f4cbf05Sopenharmony_ci return ThreadStatus::UNKNOWN_ERROR; 1313f4cbf05Sopenharmony_ci } 1323f4cbf05Sopenharmony_ci 1333f4cbf05Sopenharmony_ci return ThreadStatus::OK; 1343f4cbf05Sopenharmony_ci} 1353f4cbf05Sopenharmony_ci 1363f4cbf05Sopenharmony_ciThreadStatus Thread::NotifyExitSync() 1373f4cbf05Sopenharmony_ci{ 1383f4cbf05Sopenharmony_ci // If the two thread IDs are equal, pthread_equal() returns a non-zero value; otherwise, it returns 0. 1393f4cbf05Sopenharmony_ci if (pthread_equal(thread_, pthread_self()) != 0) { 1403f4cbf05Sopenharmony_ci // don't call NotifyExitSync() from this !; 1413f4cbf05Sopenharmony_ci return ThreadStatus::WOULD_BLOCK; 1423f4cbf05Sopenharmony_ci } 1433f4cbf05Sopenharmony_ci 1443f4cbf05Sopenharmony_ci std::unique_lock<std::mutex> lk(lock_); 1453f4cbf05Sopenharmony_ci exitPending_ = true; 1463f4cbf05Sopenharmony_ci 1473f4cbf05Sopenharmony_ci while (running_) { 1483f4cbf05Sopenharmony_ci cvThreadExited_.wait(lk); 1493f4cbf05Sopenharmony_ci } 1503f4cbf05Sopenharmony_ci 1513f4cbf05Sopenharmony_ci exitPending_ = false; 1523f4cbf05Sopenharmony_ci 1533f4cbf05Sopenharmony_ci return status_; 1543f4cbf05Sopenharmony_ci} 1553f4cbf05Sopenharmony_ci 1563f4cbf05Sopenharmony_civoid Thread::NotifyExitAsync() 1573f4cbf05Sopenharmony_ci{ 1583f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lk(lock_); 1593f4cbf05Sopenharmony_ci exitPending_ = true; 1603f4cbf05Sopenharmony_ci} 1613f4cbf05Sopenharmony_ci 1623f4cbf05Sopenharmony_cibool Thread::ReadyToWork() 1633f4cbf05Sopenharmony_ci{ 1643f4cbf05Sopenharmony_ci return true; 1653f4cbf05Sopenharmony_ci} 1663f4cbf05Sopenharmony_ci 1673f4cbf05Sopenharmony_cibool Thread::IsExitPending() const 1683f4cbf05Sopenharmony_ci{ 1693f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lk(lock_); 1703f4cbf05Sopenharmony_ci return exitPending_; 1713f4cbf05Sopenharmony_ci} 1723f4cbf05Sopenharmony_ci 1733f4cbf05Sopenharmony_cibool Thread::IsRunning() const 1743f4cbf05Sopenharmony_ci{ 1753f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lk(lock_); 1763f4cbf05Sopenharmony_ci return running_; 1773f4cbf05Sopenharmony_ci} 1783f4cbf05Sopenharmony_ci 1793f4cbf05Sopenharmony_ciint Thread::ThreadStart(void* args) 1803f4cbf05Sopenharmony_ci{ 1813f4cbf05Sopenharmony_ci Thread* const self = static_cast<Thread*>(args); 1823f4cbf05Sopenharmony_ci bool first = true; 1833f4cbf05Sopenharmony_ci 1843f4cbf05Sopenharmony_ci do { 1853f4cbf05Sopenharmony_ci bool result = false; 1863f4cbf05Sopenharmony_ci if (first) { 1873f4cbf05Sopenharmony_ci first = false; 1883f4cbf05Sopenharmony_ci if (self->ReadyToWork() && !self->IsExitPending()) { 1893f4cbf05Sopenharmony_ci result = self->Run(); 1903f4cbf05Sopenharmony_ci } 1913f4cbf05Sopenharmony_ci } else { 1923f4cbf05Sopenharmony_ci result = self->Run(); 1933f4cbf05Sopenharmony_ci } 1943f4cbf05Sopenharmony_ci 1953f4cbf05Sopenharmony_ci { 1963f4cbf05Sopenharmony_ci std::unique_lock<std::mutex> lk(self->lock_); 1973f4cbf05Sopenharmony_ci if ((!result) || self->exitPending_) { 1983f4cbf05Sopenharmony_ci self->exitPending_ = true; 1993f4cbf05Sopenharmony_ci self->running_ = false; 2003f4cbf05Sopenharmony_ci self->thread_ = INVALID_PTHREAD_T; 2013f4cbf05Sopenharmony_ci self->cvThreadExited_.notify_all(); 2023f4cbf05Sopenharmony_ci break; 2033f4cbf05Sopenharmony_ci } 2043f4cbf05Sopenharmony_ci } 2053f4cbf05Sopenharmony_ci } while (true); 2063f4cbf05Sopenharmony_ci 2073f4cbf05Sopenharmony_ci return 0; 2083f4cbf05Sopenharmony_ci} 2093f4cbf05Sopenharmony_ci 2103f4cbf05Sopenharmony_ci} // namespace OHOS 211