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 */ 32int 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 49typedef void *(*MppThreadFunc)(void *); 50 51typedef 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 * for shorter type name and function name 64 */ 65class Mutex { 66public: 67 Mutex(); 68 ~Mutex(); 69 70 void lock(); 71 void unlock(); 72 int trylock(); 73 74 class Autolock { 75 public: 76 inline Autolock(Mutex *mutex, unsigned int enable = 1) : mEnabled(enable), mLock(*mutex) 77 { 78 if (mEnabled) { 79 mLock.lock(); 80 } 81 } 82 inline ~Autolock() 83 { 84 if (mEnabled) { 85 mLock.unlock(); 86 } 87 } 88 89 private: 90 signed int mEnabled; 91 Mutex &mLock; 92 }; 93 94private: 95 friend class Condition; 96 97 pthread_mutex_t mMutex; 98 99 Mutex(const Mutex &); 100 Mutex &operator=(const Mutex &); 101}; 102 103inline Mutex::Mutex() 104{ 105 pthread_mutexattr_t attr; 106 pthread_mutexattr_init(&attr); 107 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 108 pthread_mutex_init(&mMutex, &attr); 109 pthread_mutexattr_destroy(&attr); 110} 111inline Mutex::~Mutex() 112{ 113 pthread_mutex_destroy(&mMutex); 114} 115inline void Mutex::lock() 116{ 117 pthread_mutex_lock(&mMutex); 118} 119inline void Mutex::unlock() 120{ 121 pthread_mutex_unlock(&mMutex); 122} 123inline int Mutex::trylock() 124{ 125 return pthread_mutex_trylock(&mMutex); 126} 127 128typedef Mutex::Autolock AutoMutex; 129 130/* 131 * for shorter type name and function name 132 */ 133class Condition { 134public: 135 Condition(); 136 Condition(int type); 137 ~Condition(); 138 signed int wait(Mutex &mutex); 139 signed int wait(Mutex *mutex); 140 signed int timedwait(Mutex &mutex, RK_S64 timeout); 141 signed int timedwait(Mutex *mutex, RK_S64 timeout); 142 signed int signal(); 143 signed int broadcast(); 144 145private: 146 pthread_cond_t mCond; 147}; 148 149inline Condition::Condition() 150{ 151 pthread_cond_init(&mCond, NULL); 152} 153inline Condition::~Condition() 154{ 155 pthread_cond_destroy(&mCond); 156} 157inline signed int Condition::wait(Mutex &mutex) 158{ 159 return pthread_cond_wait(&mCond, &mutex.mMutex); 160} 161inline signed int Condition::wait(Mutex *mutex) 162{ 163 return pthread_cond_wait(&mCond, &mutex->mMutex); 164} 165inline signed int Condition::timedwait(Mutex &mutex, RK_S64 timeout) 166{ 167 return timedwait(&mutex, timeout); 168} 169inline signed int 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} 183inline signed int Condition::signal() 184{ 185 return pthread_cond_signal(&mCond); 186} 187inline signed int Condition::broadcast() 188{ 189 return pthread_cond_broadcast(&mCond); 190} 191 192class MppMutexCond { 193public: 194 MppMutexCond() {}; 195 ~MppMutexCond() {}; 196 197 void lock() 198 { 199 mLock.lock(); 200 } 201 void unlock() 202 { 203 mLock.unlock(); 204 } 205 void trylock() 206 { 207 mLock.trylock(); 208 } 209 void wait() 210 { 211 mCondition.wait(mLock); 212 } 213 signed int wait(RK_S64 timeout) 214 { 215 return mCondition.timedwait(mLock, timeout); 216 } 217 void signal() 218 { 219 mCondition.signal(); 220 } 221 void broadcast() 222 { 223 mCondition.broadcast(); 224 } 225 Mutex *mutex() 226 { 227 return &mLock; 228 } 229 230private: 231 Mutex mLock; 232 Condition mCondition; 233}; 234 235// Thread lock / signal is distinguished by its source 236typedef 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 247class MppThread { 248public: 249 MppThread(MppThreadFunc func, void *ctx, const char *name = NULL); 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 285 void signal(MppThreadSignal id = THREAD_WORK) 286 { 287 mpp_assert(id < THREAD_SIGNAL_BUTT); 288 mMutexCond[id].signal(); 289 } 290 291 Mutex *mutex(MppThreadSignal id = THREAD_WORK) 292 { 293 mpp_assert(id < THREAD_SIGNAL_BUTT); 294 return mMutexCond[id].mutex(); 295 } 296 297private: 298 pthread_t mThread; 299 MppMutexCond mMutexCond[THREAD_SIGNAL_BUTT]; 300 MppThreadStatus mStatus[THREAD_SIGNAL_BUTT]; 301 302 MppThreadFunc mFunction; 303 char mName[THREAD_NAME_LEN]; 304 void *mContext; 305 306 MppThread(); 307 MppThread(const MppThread &); 308 MppThread &operator=(const MppThread &); 309}; 310 311#endif 312 313#endif /* __MPP_THREAD_H__ */ 314