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