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