blob: b472a80bc89fad42ae42fb1bc6a0ff5df905c8a7 [file] [log] [blame]
fei.dengf7a0cd32023-08-29 09:36:37 +00001/*
2 * Copyright (C) 2021 Amlogic Corporation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <assert.h>
17#include <sys/resource.h>
18#include <sys/prctl.h>
19#include <string.h>
20#include <errno.h>
21#include "Thread.h"
22namespace Tls {
23pthread_t getThreadId()
24{
25 return (pthread_t)pthread_self();
26}
27
28Thread::Thread()
29 :mThread(pthread_t(-1)),
30 mStatus(0),
31 mExitPending(false),
32 mRunning(false),
33 mPriority(0)
34{
35}
36
37Thread::~Thread()
38{
39}
40
41void Thread::setThreadPriority(int priority)
42{
43 mPriority = priority;
44}
45
46void Thread::readyToRun()
47{
48
49}
50
51void Thread::readyToExit()
52{
53
54}
55
56int Thread::run(const char* name)
57{
58 std::unique_lock<std::mutex> lck(mMutex);
59 if (mRunning) {
60 // thread already started
61 return -1;
62 }
63
64 mStatus = 0;
65 mExitPending = false;
66 mThread = pthread_t(-1);
67 memset(mThreadName, '\0', sizeof(mThreadName));
68 if (name) {
69 if (strlen(name) <= sizeof(mThreadName)-1) {
70 strcpy(mThreadName, name);
71 } else {
72 strncpy(mThreadName, name, sizeof(mThreadName)-1);
73 }
74 } else {
75 strcpy(mThreadName, "unknown");
76 }
77
78 //set running at this ,if request exit immediately when invoking run
79 //this will let requestExitAndWait block until thread running
80 mRunning = true;
81
82 int res;
83 res = _createThread(_threadLoop);
84 if (res != 0) {
85 mStatus = -1; // something happened!
86 mRunning = false;
87 mThread = pthread_t(-1);
88 mCond.notify_all();
89 return -1;
90 }
91 return 0;
92}
93
94int Thread::_createThread(pthread_entry_func entryFunction)
95{
96 pthread_attr_t attr;
97 pthread_attr_init(&attr);
98 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
99
100 errno = 0;
101 int result = pthread_create(&mThread, &attr,
102 (pthread_entry_func)entryFunction, (void *)this);
103 pthread_attr_destroy(&attr);
104 if (result != 0) {
105 return -1;
106 }
107
108 return 0;
109}
110
111void* Thread::_threadLoop(void* user)
112{
113 Thread* const self = static_cast<Thread*>(user);
114 struct sched_param schedParam;
115 int maxPriority,miniPriority;
116
117 self->mRunning = true;
118 if (self->mPriority > 0) {
119 maxPriority = sched_get_priority_max(SCHED_FIFO);
120 miniPriority = sched_get_priority_min(SCHED_FIFO);
121 schedParam.sched_priority = self->mPriority;
122 if (self->mPriority > maxPriority) {
123 schedParam.sched_priority = maxPriority;
124 } else if (self->mPriority < miniPriority) {
125 schedParam.sched_priority = miniPriority;
126 }
127 pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam );
128 }
129 pthread_setname_np(pthread_self(), self->mThreadName);
130
131 self->readyToRun();
132
133 //maybe readyToRun will do something that take a long time,
134 //so we need to check exit thread status
135 if (self->mExitPending) {
136 goto exit;
137 }
138
139 do {
140 bool result = true;
141
142 result = self->threadLoop();
143 if (result == false || self->mExitPending) {
144 break;
145 }
146 } while(self->mRunning);
147
148exit:
149 //must call readyToExit before set mRunning to false
150 self->readyToExit();
151 std::unique_lock<std::mutex> lck(self->mMutex);
152 self->mExitPending = true;
153 // clear thread ID so that requestExitAndWait() does not exit if
154 // called by a new thread using the same thread ID as this one.
155 self->mThread = pthread_t(-1);
156 self->mRunning = false;
157 // note that interested observers blocked in requestExitAndWait are
158 // awoken by broadcast, but blocked on mLock until break exits scope
159 self->mCond.notify_all();
160 return 0;
161}
162
163void Thread::requestExit()
164{
165 std::lock_guard<std::mutex> lck(mMutex);
166 mExitPending = true;
167}
168
169int Thread::requestExitAndWait()
170{
171 std::unique_lock<std::mutex> lck(mMutex);
172 if (mThread == getThreadId()) {
173 return -1;
174 }
175
176 mExitPending = true;
177
178 while (mRunning == true) {
179 mCond.wait(lck);
180 }
181 // This next line is probably not needed any more, but is being left for
182 // historical reference. Note that each interested party will clear flag.
183 mExitPending = false;
184 return mStatus;
185}
186
187int Thread::join()
188{
189 std::unique_lock<std::mutex> lck(mMutex);
190 if (mThread == getThreadId()) {
191 return -1;
192 }
193
194 while (mRunning == true) {
195 mCond.wait(lck);
196 }
197 return mStatus;
198}
199
200bool Thread::isRunning() const {
201 std::lock_guard<std::mutex> lck(mMutex);
202 return mRunning;
203}
204
205bool Thread::isExitPending() const
206{
207 std::lock_guard<std::mutex> lck(mMutex);
208 return mExitPending;
209}
210}