1 /*
2  * Copyright (c) 2021 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 #include "platform/threadpool/include/thread.h"
17 
18 #include <thread>
19 
20 #include "platform/time/include/time.h"
21 #include "platform/time/include/time_elapser.h"
22 #include "protocol/retcode_inner/aie_retcode_inner.h"
23 
24 namespace OHOS {
25 namespace AI {
IWorker()26 IWorker::IWorker() : counter_(0), thread_(nullptr), status_(IDLE)
27 {
28 }
29 
~IWorker()30 IWorker::~IWorker()
31 {
32     thread_ = nullptr;
33 }
34 
GetThreadId()35 unsigned long IWorker::GetThreadId()
36 {
37     CHK_RET(thread_ == nullptr, RETCODE_FAILURE);
38     return thread_->GetThreadId();
39 }
40 
Thread()41 Thread::Thread()
42     : running_(false), status_(STOPPED), stackSize_(THREAD_DEFAULT_STACK_SIZE), worker_(nullptr)
43 {
44     InitThread(thread_);
45 }
46 
~Thread()47 Thread::~Thread()
48 {
49     CHK_RET_NONE(worker_ == nullptr);
50 
51     worker_->SetThread(nullptr);
52     worker_ = nullptr;
53 }
54 
SetStackSize(const size_t size)55 void Thread::SetStackSize(const size_t size)
56 {
57     stackSize_ = size;
58 }
59 
Status() const60 Thread::ThreadStatus Thread::Status() const
61 {
62     return status_;
63 }
64 
GetWorker() const65 const IWorker *Thread::GetWorker() const
66 {
67     return worker_;
68 }
69 
SetWorker(IWorker * pWorker)70 void Thread::SetWorker(IWorker *pWorker)
71 {
72     if (worker_ != nullptr) {
73         worker_->SetThread(nullptr);
74     }
75 
76     worker_ = pWorker;
77     if (pWorker != nullptr) {
78         pWorker->SetThread(this);
79     }
80 }
81 
StartThread()82 bool Thread::StartThread()
83 {
84     if (status_ == RUNNING) {
85         return false;
86     }
87 
88     size_t stackSize = stackSize_;
89     if (worker_ != nullptr && worker_->GetStackSize() > 0) {
90         stackSize = worker_->GetStackSize();
91     }
92 
93     PthreadAttr attr;
94     PthreadAttr *pattr = nullptr;
95     if ((stackSize >= THREAD_MIN_STACK_SIZE) && (stackSize < THREAD_MAX_STACK_SIZE)) {
96         (void)InitThreadAttr(attr);
97         (void)SetThreadAttrStackSize(attr, stackSize);
98         pattr = &attr;
99     }
100 
101     status_ = PREPARED;
102 
103     int retCode = CreateOneThread(thread_, pattr, Thread::ThreadProc, this);
104     if (retCode != 0) {
105         status_ = STOPPED;
106         return false;
107     }
108 
109     while (status_ == PREPARED) {
110         (void)StepSleepMs(THREAD_SLEEP_MS);
111     }
112 
113     return true;
114 }
115 
StartThread(IWorker * pWorker)116 bool Thread::StartThread(IWorker *pWorker)
117 {
118     if (status_ == RUNNING) {
119         return false;
120     }
121     if (pWorker == nullptr) {
122         return false;
123     }
124     worker_ = pWorker;
125 
126     (void)pWorker->SetThread(this);
127 
128     return StartThread();
129 }
130 
StopThread()131 void Thread::StopThread()
132 {
133     if (!IsActive()) {
134         return;
135     }
136 
137     running_ = false;
138     while (status_ == RUNNING) {
139         (void)StepSleepMs(THREAD_SLEEP_MS);
140     }
141     WaitForEnd();
142 }
143 
StopThread(int timeOut)144 bool Thread::StopThread(int timeOut)
145 {
146     if (!IsActive()) {
147         return true;
148     }
149 
150     running_ = false;
151 
152     // if timeOut==0 means just set stop flag
153     if (timeOut == 0) {
154         return true;
155     }
156 
157     TimeElapser elapser;
158     while ((status_ == RUNNING) && (static_cast<int32_t>(elapser.ElapseMilli()) < timeOut)) {
159         (void)StepSleepMs(THREAD_SLEEP_MS);
160     }
161 
162     if (status_ == RUNNING) {
163         return false;
164     }
165 
166     WaitForEnd();
167     return true;
168 }
169 
Run()170 void Thread::Run()
171 {
172     if (worker_ == nullptr) {
173         return;
174     }
175 
176     IWorker *pWorker = worker_;
177     if (!pWorker->Initialize()) {
178         pWorker->Uninitialize();
179         return;
180     }
181 
182     while (running_) {
183         if (!pWorker->OneAction()) {
184             break;
185         }
186         ++worker_->counter_;
187     }
188     status_ = STOPPED;
189     pWorker->Uninitialize();
190 }
191 
IsActive() const192 bool Thread::IsActive() const
193 {
194     if (status_ == RUNNING) {
195         return IsThreadRunning(GetThreadId());
196     }
197 
198     return false;
199 }
200 
IsHung(time_t now) const201 bool Thread::IsHung(time_t now) const
202 {
203     if (worker_ != nullptr) {
204         return worker_->isHung(now);
205     }
206     return false;
207 }
208 
GetThreadId() const209 unsigned long Thread::GetThreadId() const
210 {
211     return GetThreadIdUnix(thread_);
212 }
213 
IsRunning() const214 bool Thread::IsRunning() const
215 {
216     return running_;
217 }
218 
Execute()219 void Thread::Execute()
220 {
221     running_ = true;
222     status_ = RUNNING;
223     Run();
224     status_ = STOPPED;
225 }
226 
WaitForEnd()227 void Thread::WaitForEnd()
228 {
229     (void)WaitThread(thread_);
230 }
231 
ThreadProc(void * pObj)232 void *Thread::ThreadProc(void *pObj)
233 {
234     auto *pThis = reinterpret_cast<Thread*>(pObj);
235     pThis->Execute();
236     auto retCode = RETCODE_SUCCESS;
237     return (void*)retCode;
238 }
239 } // namespace AI
240 } // namespace OHOS
241