• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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