blob: 1e9ba9abab7a40f2a074e988c5de79c95c120a90 [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)),
fei.dengb9a1a572023-09-13 01:33:57 +000030 mLock("Thread::mLock"),
fei.dengf7a0cd32023-08-29 09:36:37 +000031 mStatus(0),
32 mExitPending(false),
33 mRunning(false),
34 mPriority(0)
35{
36}
37
38Thread::~Thread()
39{
40}
41
42void Thread::setThreadPriority(int priority)
43{
44 mPriority = priority;
45}
46
47void Thread::readyToRun()
48{
49
50}
51
52void Thread::readyToExit()
53{
54
55}
56
57int Thread::run(const char* name)
58{
fei.dengb9a1a572023-09-13 01:33:57 +000059 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +000060 if (mRunning) {
61 // thread already started
62 return -1;
63 }
64
fei.dengb9a1a572023-09-13 01:33:57 +000065 // reset status and exitPending to their default value, so we can
66 // try again after an error happened (either below, or in readyToRun())
fei.dengf7a0cd32023-08-29 09:36:37 +000067 mStatus = 0;
68 mExitPending = false;
69 mThread = pthread_t(-1);
70 memset(mThreadName, '\0', sizeof(mThreadName));
71 if (name) {
72 if (strlen(name) <= sizeof(mThreadName)-1) {
73 strcpy(mThreadName, name);
74 } else {
75 strncpy(mThreadName, name, sizeof(mThreadName)-1);
76 }
77 } else {
78 strcpy(mThreadName, "unknown");
79 }
80
81 //set running at this ,if request exit immediately when invoking run
82 //this will let requestExitAndWait block until thread running
83 mRunning = true;
84
85 int res;
86 res = _createThread(_threadLoop);
87 if (res != 0) {
88 mStatus = -1; // something happened!
89 mRunning = false;
90 mThread = pthread_t(-1);
fei.dengb9a1a572023-09-13 01:33:57 +000091 mCondition.broadcast();
fei.dengf7a0cd32023-08-29 09:36:37 +000092 return -1;
93 }
fei.dengb9a1a572023-09-13 01:33:57 +000094
fei.dengf7a0cd32023-08-29 09:36:37 +000095 return 0;
96}
97
98int Thread::_createThread(pthread_entry_func entryFunction)
99{
100 pthread_attr_t attr;
101 pthread_attr_init(&attr);
102 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
103
104 errno = 0;
105 int result = pthread_create(&mThread, &attr,
106 (pthread_entry_func)entryFunction, (void *)this);
107 pthread_attr_destroy(&attr);
108 if (result != 0) {
109 return -1;
110 }
111
112 return 0;
113}
114
115void* Thread::_threadLoop(void* user)
116{
117 Thread* const self = static_cast<Thread*>(user);
118 struct sched_param schedParam;
119 int maxPriority,miniPriority;
120
121 self->mRunning = true;
122 if (self->mPriority > 0) {
123 maxPriority = sched_get_priority_max(SCHED_FIFO);
124 miniPriority = sched_get_priority_min(SCHED_FIFO);
125 schedParam.sched_priority = self->mPriority;
126 if (self->mPriority > maxPriority) {
127 schedParam.sched_priority = maxPriority;
128 } else if (self->mPriority < miniPriority) {
129 schedParam.sched_priority = miniPriority;
130 }
131 pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam );
132 }
133 pthread_setname_np(pthread_self(), self->mThreadName);
134
135 self->readyToRun();
136
137 //maybe readyToRun will do something that take a long time,
138 //so we need to check exit thread status
139 if (self->mExitPending) {
140 goto exit;
141 }
142
143 do {
144 bool result = true;
145
146 result = self->threadLoop();
147 if (result == false || self->mExitPending) {
148 break;
149 }
150 } while(self->mRunning);
151
152exit:
153 //must call readyToExit before set mRunning to false
154 self->readyToExit();
fei.dengb9a1a572023-09-13 01:33:57 +0000155 Tls::Mutex::Autolock _l(self->mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000156 self->mExitPending = true;
157 // clear thread ID so that requestExitAndWait() does not exit if
158 // called by a new thread using the same thread ID as this one.
159 self->mThread = pthread_t(-1);
160 self->mRunning = false;
161 // note that interested observers blocked in requestExitAndWait are
162 // awoken by broadcast, but blocked on mLock until break exits scope
fei.dengb9a1a572023-09-13 01:33:57 +0000163 self->mCondition.broadcast();
164
fei.dengf7a0cd32023-08-29 09:36:37 +0000165 return 0;
166}
167
168void Thread::requestExit()
169{
fei.dengb9a1a572023-09-13 01:33:57 +0000170 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000171 mExitPending = true;
172}
173
174int Thread::requestExitAndWait()
175{
fei.dengb9a1a572023-09-13 01:33:57 +0000176 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000177 if (mThread == getThreadId()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000178
fei.dengf7a0cd32023-08-29 09:36:37 +0000179 return -1;
180 }
181
182 mExitPending = true;
183
184 while (mRunning == true) {
fei.dengb9a1a572023-09-13 01:33:57 +0000185 mCondition.wait(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000186 }
fei.dengb9a1a572023-09-13 01:33:57 +0000187
fei.dengf7a0cd32023-08-29 09:36:37 +0000188 mExitPending = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000189
fei.dengf7a0cd32023-08-29 09:36:37 +0000190 return mStatus;
191}
192
193int Thread::join()
194{
fei.dengb9a1a572023-09-13 01:33:57 +0000195 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000196 if (mThread == getThreadId()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000197
fei.dengf7a0cd32023-08-29 09:36:37 +0000198 return -1;
199 }
200
201 while (mRunning == true) {
fei.dengb9a1a572023-09-13 01:33:57 +0000202 mCondition.wait(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000203 }
fei.dengb9a1a572023-09-13 01:33:57 +0000204
fei.dengf7a0cd32023-08-29 09:36:37 +0000205 return mStatus;
206}
207
208bool Thread::isRunning() const {
fei.dengb9a1a572023-09-13 01:33:57 +0000209 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000210 return mRunning;
211}
212
213bool Thread::isExitPending() const
214{
fei.dengb9a1a572023-09-13 01:33:57 +0000215 Tls::Mutex::Autolock _l(mLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000216 return mExitPending;
217}
218}