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