1484543d1Sopenharmony_ci/*
2484543d1Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3484543d1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4484543d1Sopenharmony_ci * you may not use this file except in compliance with the License.
5484543d1Sopenharmony_ci * You may obtain a copy of the License at
6484543d1Sopenharmony_ci *
7484543d1Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8484543d1Sopenharmony_ci *
9484543d1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10484543d1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11484543d1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12484543d1Sopenharmony_ci * See the License for the specific language governing permissions and
13484543d1Sopenharmony_ci * limitations under the License.
14484543d1Sopenharmony_ci */
15484543d1Sopenharmony_ci
16484543d1Sopenharmony_ci#ifndef FFRT_WORKER_THREAD_HPP
17484543d1Sopenharmony_ci#define FFRT_WORKER_THREAD_HPP
18484543d1Sopenharmony_ci
19484543d1Sopenharmony_ci#include <atomic>
20484543d1Sopenharmony_ci#include <unistd.h>
21484543d1Sopenharmony_ci#ifdef FFRT_PTHREAD_ENABLE
22484543d1Sopenharmony_ci#include <pthread.h>
23484543d1Sopenharmony_ci#endif
24484543d1Sopenharmony_ci#include <thread>
25484543d1Sopenharmony_ci#ifdef OHOS_THREAD_STACK_DUMP
26484543d1Sopenharmony_ci#include <sstream>
27484543d1Sopenharmony_ci#include "dfx_dump_catcher.h"
28484543d1Sopenharmony_ci#endif
29484543d1Sopenharmony_ci
30484543d1Sopenharmony_ci#include "qos.h"
31484543d1Sopenharmony_ci#include "tm/cpu_task.h"
32484543d1Sopenharmony_ci#include "dfx/log/ffrt_log_api.h"
33484543d1Sopenharmony_ci
34484543d1Sopenharmony_cinamespace ffrt {
35484543d1Sopenharmony_ciconstexpr int PTHREAD_CREATE_NO_MEM_CODE = 11;
36484543d1Sopenharmony_ciconstexpr int FFRT_RETRY_MAX_COUNT = 12;
37484543d1Sopenharmony_ciconst std::vector<uint64_t> FFRT_RETRY_CYCLE_LIST = {
38484543d1Sopenharmony_ci    10 * 1000, 50 * 1000, 100 * 1000, 200 * 1000, 500 * 1000, 1000 * 1000, 2 * 1000 * 1000,
39484543d1Sopenharmony_ci    5 * 1000 * 1000, 10 * 1000 * 1000, 50 * 1000 * 1000, 100 * 1000 * 1000, 500 * 1000 * 1000
40484543d1Sopenharmony_ci};
41484543d1Sopenharmony_ci
42484543d1Sopenharmony_ciclass WorkerThread {
43484543d1Sopenharmony_cipublic:
44484543d1Sopenharmony_ci    CPUEUTask* curTask = nullptr;
45484543d1Sopenharmony_ci
46484543d1Sopenharmony_ci    uintptr_t curTaskType_ = ffrt_invalid_task;
47484543d1Sopenharmony_ci    std::string curTaskLabel_ = "";
48484543d1Sopenharmony_ci    uint64_t curTaskGid_ = UINT64_MAX; //仅当TaskType为normal task或者queue task时,label和gid才能正常读取
49484543d1Sopenharmony_ci    explicit WorkerThread(const QoS& qos);
50484543d1Sopenharmony_ci
51484543d1Sopenharmony_ci    virtual ~WorkerThread()
52484543d1Sopenharmony_ci    {
53484543d1Sopenharmony_ci        if (!exited) {
54484543d1Sopenharmony_ci#ifdef OHOS_THREAD_STACK_DUMP
55484543d1Sopenharmony_ci            FFRT_LOGW("WorkerThread enter destruction but not exited");
56484543d1Sopenharmony_ci            OHOS::HiviewDFX::DfxDumpCatcher dumplog;
57484543d1Sopenharmony_ci            std::string msg = "";
58484543d1Sopenharmony_ci            bool result = dumplog.DumpCatch(getpid(), gettid(), msg);
59484543d1Sopenharmony_ci            if (result) {
60484543d1Sopenharmony_ci                std::vector<std::string> out;
61484543d1Sopenharmony_ci                std::stringstream ss(msg);
62484543d1Sopenharmony_ci                std::string s;
63484543d1Sopenharmony_ci                while (std::getline(ss, s, '\n')) {
64484543d1Sopenharmony_ci                    out.push_back(s);
65484543d1Sopenharmony_ci                }
66484543d1Sopenharmony_ci                for (auto const& line: out) {
67484543d1Sopenharmony_ci                    FFRT_LOGE("ffrt callstack %s", line.c_str());
68484543d1Sopenharmony_ci                }
69484543d1Sopenharmony_ci            }
70484543d1Sopenharmony_ci#endif
71484543d1Sopenharmony_ci        }
72484543d1Sopenharmony_ci        FFRT_LOGW("WorkerThread enter destruction");
73484543d1Sopenharmony_ci        Detach();
74484543d1Sopenharmony_ci    }
75484543d1Sopenharmony_ci
76484543d1Sopenharmony_ci    bool Idle() const
77484543d1Sopenharmony_ci    {
78484543d1Sopenharmony_ci        return idle;
79484543d1Sopenharmony_ci    }
80484543d1Sopenharmony_ci
81484543d1Sopenharmony_ci    void SetIdle(bool var)
82484543d1Sopenharmony_ci    {
83484543d1Sopenharmony_ci        this->idle = var;
84484543d1Sopenharmony_ci    }
85484543d1Sopenharmony_ci
86484543d1Sopenharmony_ci    bool Exited() const
87484543d1Sopenharmony_ci    {
88484543d1Sopenharmony_ci        return exited;
89484543d1Sopenharmony_ci    }
90484543d1Sopenharmony_ci
91484543d1Sopenharmony_ci    void SetExited(bool var)
92484543d1Sopenharmony_ci    {
93484543d1Sopenharmony_ci        this->exited = var;
94484543d1Sopenharmony_ci    }
95484543d1Sopenharmony_ci
96484543d1Sopenharmony_ci    pid_t Id() const
97484543d1Sopenharmony_ci    {
98484543d1Sopenharmony_ci        while (!exited && tid < 0) {
99484543d1Sopenharmony_ci        }
100484543d1Sopenharmony_ci        return tid;
101484543d1Sopenharmony_ci    }
102484543d1Sopenharmony_ci
103484543d1Sopenharmony_ci    const QoS& GetQos() const
104484543d1Sopenharmony_ci    {
105484543d1Sopenharmony_ci        return qos;
106484543d1Sopenharmony_ci    }
107484543d1Sopenharmony_ci#ifdef FFRT_WORKERS_DYNAMIC_SCALING
108484543d1Sopenharmony_ci    unsigned int GetDomainId() const
109484543d1Sopenharmony_ci    {
110484543d1Sopenharmony_ci        return domain_id;
111484543d1Sopenharmony_ci    }
112484543d1Sopenharmony_ci#endif
113484543d1Sopenharmony_ci
114484543d1Sopenharmony_ci#ifdef FFRT_PTHREAD_ENABLE
115484543d1Sopenharmony_ci    void Start(void*(*ThreadFunc)(void*), void* args)
116484543d1Sopenharmony_ci    {
117484543d1Sopenharmony_ci        int ret = pthread_create(&thread_, &attr_, ThreadFunc, args);
118484543d1Sopenharmony_ci        if (ret == PTHREAD_CREATE_NO_MEM_CODE) {
119484543d1Sopenharmony_ci            int count = 0;
120484543d1Sopenharmony_ci            while (ret == PTHREAD_CREATE_NO_MEM_CODE && count < FFRT_RETRY_MAX_COUNT) {
121484543d1Sopenharmony_ci                usleep(FFRT_RETRY_CYCLE_LIST[count]);
122484543d1Sopenharmony_ci                count++;
123484543d1Sopenharmony_ci                FFRT_LOGW("pthread_create failed due to shortage of system memory, FFRT retry %d times...", count);
124484543d1Sopenharmony_ci                ret = pthread_create(&thread_, &attr_, ThreadFunc, args);
125484543d1Sopenharmony_ci            }
126484543d1Sopenharmony_ci        }
127484543d1Sopenharmony_ci        if (ret != 0) {
128484543d1Sopenharmony_ci            FFRT_LOGE("pthread_create failed, ret = %d", ret);
129484543d1Sopenharmony_ci            exited = true;
130484543d1Sopenharmony_ci        }
131484543d1Sopenharmony_ci        pthread_attr_destroy(&attr_);
132484543d1Sopenharmony_ci    }
133484543d1Sopenharmony_ci
134484543d1Sopenharmony_ci    void Join()
135484543d1Sopenharmony_ci    {
136484543d1Sopenharmony_ci        if (tid > 0) {
137484543d1Sopenharmony_ci            pthread_join(thread_, nullptr);
138484543d1Sopenharmony_ci        }
139484543d1Sopenharmony_ci        tid = -1;
140484543d1Sopenharmony_ci    }
141484543d1Sopenharmony_ci
142484543d1Sopenharmony_ci    void Detach()
143484543d1Sopenharmony_ci    {
144484543d1Sopenharmony_ci        if (tid > 0) {
145484543d1Sopenharmony_ci            pthread_detach(thread_);
146484543d1Sopenharmony_ci        } else {
147484543d1Sopenharmony_ci            FFRT_LOGD("qos %d thread not joinable.", qos());
148484543d1Sopenharmony_ci        }
149484543d1Sopenharmony_ci        tid = -1;
150484543d1Sopenharmony_ci    }
151484543d1Sopenharmony_ci
152484543d1Sopenharmony_ci    pthread_t& GetThread()
153484543d1Sopenharmony_ci    {
154484543d1Sopenharmony_ci        return this->thread_;
155484543d1Sopenharmony_ci    }
156484543d1Sopenharmony_ci#else
157484543d1Sopenharmony_ci    template <typename F, typename... Args>
158484543d1Sopenharmony_ci    void Start(F&& f, Args&&... args)
159484543d1Sopenharmony_ci    {
160484543d1Sopenharmony_ci        auto wrap = [&](Args&&... args) {
161484543d1Sopenharmony_ci            NativeConfig();
162484543d1Sopenharmony_ci            return f(args...);
163484543d1Sopenharmony_ci        };
164484543d1Sopenharmony_ci        thread = std::thread(wrap, args...);
165484543d1Sopenharmony_ci    }
166484543d1Sopenharmony_ci
167484543d1Sopenharmony_ci    void Join()
168484543d1Sopenharmony_ci    {
169484543d1Sopenharmony_ci        if (thread.joinable()) {
170484543d1Sopenharmony_ci            thread.join();
171484543d1Sopenharmony_ci        }
172484543d1Sopenharmony_ci        tid = -1;
173484543d1Sopenharmony_ci    }
174484543d1Sopenharmony_ci
175484543d1Sopenharmony_ci    void Detach()
176484543d1Sopenharmony_ci    {
177484543d1Sopenharmony_ci        if (thread.joinable()) {
178484543d1Sopenharmony_ci            thread.detach();
179484543d1Sopenharmony_ci        } else {
180484543d1Sopenharmony_ci            FFRT_LOGD("qos %d thread not joinable\n", qos());
181484543d1Sopenharmony_ci        }
182484543d1Sopenharmony_ci        tid = -1;
183484543d1Sopenharmony_ci    }
184484543d1Sopenharmony_ci
185484543d1Sopenharmony_ci    pthread_t GetThread()
186484543d1Sopenharmony_ci    {
187484543d1Sopenharmony_ci        return this->thread.native_handle();
188484543d1Sopenharmony_ci    }
189484543d1Sopenharmony_ci#endif
190484543d1Sopenharmony_ci
191484543d1Sopenharmony_ci    void WorkerSetup(WorkerThread* wthread);
192484543d1Sopenharmony_ci    void NativeConfig();
193484543d1Sopenharmony_ci
194484543d1Sopenharmony_ciprivate:
195484543d1Sopenharmony_ci    std::atomic_bool exited;
196484543d1Sopenharmony_ci    std::atomic_bool idle;
197484543d1Sopenharmony_ci
198484543d1Sopenharmony_ci    std::atomic<pid_t> tid;
199484543d1Sopenharmony_ci
200484543d1Sopenharmony_ci    QoS qos;
201484543d1Sopenharmony_ci#ifdef FFRT_PTHREAD_ENABLE
202484543d1Sopenharmony_ci    pthread_t thread_{0};
203484543d1Sopenharmony_ci    pthread_attr_t attr_;
204484543d1Sopenharmony_ci#else
205484543d1Sopenharmony_ci    std::thread thread;
206484543d1Sopenharmony_ci#endif
207484543d1Sopenharmony_ci#ifdef FFRT_WORKERS_DYNAMIC_SCALING
208484543d1Sopenharmony_ci    unsigned int domain_id;
209484543d1Sopenharmony_ci#endif
210484543d1Sopenharmony_ci};
211484543d1Sopenharmony_civoid SetThreadAttr(WorkerThread* thread, const QoS& qos);
212484543d1Sopenharmony_ci} // namespace ffrt
213484543d1Sopenharmony_ci#endif
214