1 /*
2 * Copyright (c) 2021 Rockchip Electronics 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 #ifndef __MPP_THREAD_H__
17 #define __MPP_THREAD_H__
18
19 #if defined(_WIN32) && !defined(__MINGW32CE__)
20
21 /*
22 * NOTE: POSIX Threads for Win32
23 * Downloaded from http://www.sourceware.org/pthreads-win32/
24 */
25 #include "semaphore.h"
26 #include "pthread.h"
27 #pragma comment(lib, "pthreadVC2.lib")
28
29 /*
30 * add pthread_setname_np for windows
31 */
32 int pthread_setname_np(pthread_t thread, const char *name);
33
34 #else
35
36 #include <unistd.h>
37 #include <semaphore.h>
38 #include <pthread.h>
39 #include <sys/time.h>
40
41 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
42 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
43 #endif
44
45 #endif
46
47 #define THREAD_NAME_LEN 16
48
49 typedef void *(*MppThreadFunc)(void *);
50
51 typedef enum {
52 MPP_THREAD_UNINITED,
53 MPP_THREAD_RUNNING,
54 MPP_THREAD_WAITING,
55 MPP_THREAD_STOPPING,
56 } MppThreadStatus;
57
58 #ifdef __cplusplus
59
60 #include "mpp_log.h"
61
62
63 /*
64 * for shorter type name and function name
65 */
66 class Mutex {
67 public:
68 Mutex();
69 ~Mutex();
70
71 void lock();
72 void unlock();
73 int trylock();
74
75 class Autolock {
76 public:
77 inline Autolock(Mutex* mutex, RK_U32 enable = 1)
mEnabled(enable)78 : mEnabled(enable), mLock(*mutex)
79 {
80 if (mEnabled)
81 mLock.lock();
82 }
~Autolock()83 inline ~Autolock()
84 {
85 if (mEnabled)
86 mLock.unlock();
87 }
88 private:
89 RK_S32 mEnabled;
90 Mutex& mLock;
91 };
92
93 private:
94 friend class Condition;
95
96 pthread_mutex_t mMutex;
97
98 Mutex(const Mutex &);
99 Mutex &operator = (const Mutex&);
100 };
101
Mutex()102 inline Mutex::Mutex()
103 {
104 pthread_mutexattr_t attr;
105 pthread_mutexattr_init(&attr);
106 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
107 pthread_mutex_init(&mMutex, &attr);
108 pthread_mutexattr_destroy(&attr);
109 }
~Mutex()110 inline Mutex::~Mutex()
111 {
112 pthread_mutex_destroy(&mMutex);
113 }
lock()114 inline void Mutex::lock()
115 {
116 pthread_mutex_lock(&mMutex);
117 }
unlock()118 inline void Mutex::unlock()
119 {
120 pthread_mutex_unlock(&mMutex);
121 }
trylock()122 inline int Mutex::trylock()
123 {
124 return pthread_mutex_trylock(&mMutex);
125 }
126
127 typedef Mutex::Autolock AutoMutex;
128
129
130 /*
131 * for shorter type name and function name
132 */
133 class Condition {
134 public:
135 Condition();
136 Condition(int type);
137 ~Condition();
138 RK_S32 wait(Mutex& mutex);
139 RK_S32 wait(Mutex* mutex);
140 RK_S32 timedwait(Mutex& mutex, RK_S64 timeout);
141 RK_S32 timedwait(Mutex* mutex, RK_S64 timeout);
142 RK_S32 signal();
143 RK_S32 broadcast();
144
145 private:
146 pthread_cond_t mCond;
147 };
148
Condition()149 inline Condition::Condition()
150 {
151 pthread_cond_init(&mCond, NULL);
152 }
~Condition()153 inline Condition::~Condition()
154 {
155 pthread_cond_destroy(&mCond);
156 }
wait(Mutex & mutex)157 inline RK_S32 Condition::wait(Mutex& mutex)
158 {
159 return pthread_cond_wait(&mCond, &mutex.mMutex);
160 }
wait(Mutex * mutex)161 inline RK_S32 Condition::wait(Mutex* mutex)
162 {
163 return pthread_cond_wait(&mCond, &mutex->mMutex);
164 }
timedwait(Mutex & mutex,RK_S64 timeout)165 inline RK_S32 Condition::timedwait(Mutex& mutex, RK_S64 timeout)
166 {
167 return timedwait(&mutex, timeout);
168 }
timedwait(Mutex * mutex,RK_S64 timeout)169 inline RK_S32 Condition::timedwait(Mutex* mutex, RK_S64 timeout)
170 {
171 struct timespec ts;
172
173 clock_gettime(CLOCK_REALTIME_COARSE, &ts);
174
175 ts.tv_sec += timeout / 1000; // 1000:Get milliseconds
176 ts.tv_nsec += (timeout % 1000) * 1000000; // 1000:Get milliseconds // 1000000:Get seconds
177 /* Prevent the out of range at nanoseconds field */
178 ts.tv_sec += ts.tv_nsec / 1000000000; // 1000000000:Get seconds
179 ts.tv_nsec %= 1000000000; // 1000000000:Get Get nanoseconds
180
181 return pthread_cond_timedwait(&mCond, &mutex->mMutex, &ts);
182 }
signal()183 inline RK_S32 Condition::signal()
184 {
185 return pthread_cond_signal(&mCond);
186 }
broadcast()187 inline RK_S32 Condition::broadcast()
188 {
189 return pthread_cond_broadcast(&mCond);
190 }
191
192 class MppMutexCond {
193 public:
MppMutexCond()194 MppMutexCond() {};
~MppMutexCond()195 ~MppMutexCond() {};
196
lock()197 void lock()
198 {
199 mLock.lock();
200 }
unlock()201 void unlock()
202 {
203 mLock.unlock();
204 }
trylock()205 void trylock()
206 {
207 mLock.trylock();
208 }
wait()209 void wait()
210 {
211 mCondition.wait(mLock);
212 }
wait(RK_S64 timeout)213 RK_S32 wait(RK_S64 timeout)
214 {
215 return mCondition.timedwait(mLock, timeout);
216 }
signal()217 void signal()
218 {
219 mCondition.signal();
220 }
broadcast()221 void broadcast()
222 {
223 mCondition.broadcast();
224 }
mutex()225 Mutex *mutex()
226 {
227 return &mLock;
228 }
229
230 private:
231 Mutex mLock;
232 Condition mCondition;
233 };
234
235 // Thread lock / signal is distinguished by its source
236 typedef enum MppThreadSignal_e {
237 THREAD_WORK, // for working loop
238 THREAD_INPUT, // for thread input
239 THREAD_OUTPUT, // for thread output
240 THREAD_CONTROL, // for thread async control (reset)
241 THREAD_SIGNAL_BUTT,
242 } MppThreadSignal;
243
244 #define THREAD_NORMAL 0
245 #define THRE 0
246
247 class MppThread {
248 public:
249 MppThread(MppThreadFunc func, void *ctx, const char *name = NULL);
~MppThread()250 ~MppThread() {};
251
252 MppThreadStatus get_status(MppThreadSignal id = THREAD_WORK);
253 void set_status(MppThreadStatus status, MppThreadSignal id = THREAD_WORK);
254 void dump_status();
255
256 void start();
257 void stop();
258
259 void lock(MppThreadSignal id = THREAD_WORK)
260 {
261 mpp_assert(id < THREAD_SIGNAL_BUTT);
262 mMutexCond[id].lock();
263 }
264
265 void unlock(MppThreadSignal id = THREAD_WORK)
266 {
267 mpp_assert(id < THREAD_SIGNAL_BUTT);
268 mMutexCond[id].unlock();
269 }
270
271 void wait(MppThreadSignal id = THREAD_WORK)
272 {
273 mpp_assert(id < THREAD_SIGNAL_BUTT);
274 MppThreadStatus status = mStatus[id];
275
276 mStatus[id] = MPP_THREAD_WAITING;
277 mMutexCond[id].wait();
278
279 // check the status is not changed then restore status
280 if (mStatus[id] == MPP_THREAD_WAITING)
281 mStatus[id] = status;
282 }
283
284 void signal(MppThreadSignal id = THREAD_WORK)
285 {
286 mpp_assert(id < THREAD_SIGNAL_BUTT);
287 mMutexCond[id].signal();
288 }
289
290 Mutex *mutex(MppThreadSignal id = THREAD_WORK)
291 {
292 mpp_assert(id < THREAD_SIGNAL_BUTT);
293 return mMutexCond[id].mutex();
294 }
295
296 private:
297 pthread_t mThread;
298 MppMutexCond mMutexCond[THREAD_SIGNAL_BUTT];
299 MppThreadStatus mStatus[THREAD_SIGNAL_BUTT];
300
301 MppThreadFunc mFunction;
302 char mName[THREAD_NAME_LEN];
303 void *mContext;
304
305 MppThread();
306 MppThread(const MppThread &);
307 MppThread &operator=(const MppThread &);
308 };
309
310 #endif
311
312 #endif /* __MPP_THREAD_H__ */
313