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