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