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