13d0407baSopenharmony_ci/* 23d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co., Ltd. 33d0407baSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43d0407baSopenharmony_ci * you may not use this file except in compliance with the License. 53d0407baSopenharmony_ci * You may obtain a copy of the License at 63d0407baSopenharmony_ci * 73d0407baSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83d0407baSopenharmony_ci * 93d0407baSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103d0407baSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113d0407baSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123d0407baSopenharmony_ci * See the License for the specific language governing permissions and 133d0407baSopenharmony_ci * limitations under the License. 143d0407baSopenharmony_ci */ 153d0407baSopenharmony_ci 163d0407baSopenharmony_ci#ifndef __MPP_THREAD_H__ 173d0407baSopenharmony_ci#define __MPP_THREAD_H__ 183d0407baSopenharmony_ci 193d0407baSopenharmony_ci#if defined(_WIN32) && !defined(__MINGW32CE__) 203d0407baSopenharmony_ci 213d0407baSopenharmony_ci/* 223d0407baSopenharmony_ci * NOTE: POSIX Threads for Win32 233d0407baSopenharmony_ci * Downloaded from http://www.sourceware.org/pthreads-win32/ 243d0407baSopenharmony_ci */ 253d0407baSopenharmony_ci#include "semaphore.h" 263d0407baSopenharmony_ci#include "pthread.h" 273d0407baSopenharmony_ci#pragma comment(lib, "pthreadVC2.lib") 283d0407baSopenharmony_ci 293d0407baSopenharmony_ci/* 303d0407baSopenharmony_ci * add pthread_setname_np for windows 313d0407baSopenharmony_ci */ 323d0407baSopenharmony_ciint pthread_setname_np(pthread_t thread, const char *name); 333d0407baSopenharmony_ci 343d0407baSopenharmony_ci#else 353d0407baSopenharmony_ci 363d0407baSopenharmony_ci#include <unistd.h> 373d0407baSopenharmony_ci#include <semaphore.h> 383d0407baSopenharmony_ci#include <pthread.h> 393d0407baSopenharmony_ci#include <sys/time.h> 403d0407baSopenharmony_ci 413d0407baSopenharmony_ci#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 423d0407baSopenharmony_ci#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER 433d0407baSopenharmony_ci#endif 443d0407baSopenharmony_ci 453d0407baSopenharmony_ci#endif 463d0407baSopenharmony_ci 473d0407baSopenharmony_ci#define THREAD_NAME_LEN 16 483d0407baSopenharmony_ci 493d0407baSopenharmony_citypedef void *(*MppThreadFunc)(void *); 503d0407baSopenharmony_ci 513d0407baSopenharmony_citypedef enum { 523d0407baSopenharmony_ci MPP_THREAD_UNINITED, 533d0407baSopenharmony_ci MPP_THREAD_RUNNING, 543d0407baSopenharmony_ci MPP_THREAD_WAITING, 553d0407baSopenharmony_ci MPP_THREAD_STOPPING, 563d0407baSopenharmony_ci} MppThreadStatus; 573d0407baSopenharmony_ci 583d0407baSopenharmony_ci#ifdef __cplusplus 593d0407baSopenharmony_ci 603d0407baSopenharmony_ci#include "mpp_log.h" 613d0407baSopenharmony_ci 623d0407baSopenharmony_ciclass Mutex; 633d0407baSopenharmony_ciclass Condition; 643d0407baSopenharmony_ci 653d0407baSopenharmony_ci/* 663d0407baSopenharmony_ci * for shorter type name and function name 673d0407baSopenharmony_ci */ 683d0407baSopenharmony_ciclass Mutex { 693d0407baSopenharmony_cipublic: 703d0407baSopenharmony_ci Mutex(); 713d0407baSopenharmony_ci ~Mutex(); 723d0407baSopenharmony_ci 733d0407baSopenharmony_ci void lock(); 743d0407baSopenharmony_ci void unlock(); 753d0407baSopenharmony_ci int trylock(); 763d0407baSopenharmony_ci 773d0407baSopenharmony_ci class Autolock { 783d0407baSopenharmony_ci public: 793d0407baSopenharmony_ci inline Autolock(Mutex* mutex, RK_U32 enable = 1) 803d0407baSopenharmony_ci : mEnabled(enable), mLock(*mutex) 813d0407baSopenharmony_ci { 823d0407baSopenharmony_ci if (mEnabled) 833d0407baSopenharmony_ci mLock.lock(); 843d0407baSopenharmony_ci } 853d0407baSopenharmony_ci inline ~Autolock() 863d0407baSopenharmony_ci { 873d0407baSopenharmony_ci if (mEnabled) 883d0407baSopenharmony_ci mLock.unlock(); 893d0407baSopenharmony_ci } 903d0407baSopenharmony_ci private: 913d0407baSopenharmony_ci RK_S32 mEnabled; 923d0407baSopenharmony_ci Mutex& mLock; 933d0407baSopenharmony_ci }; 943d0407baSopenharmony_ci 953d0407baSopenharmony_ciprivate: 963d0407baSopenharmony_ci friend class Condition; 973d0407baSopenharmony_ci 983d0407baSopenharmony_ci pthread_mutex_t mMutex; 993d0407baSopenharmony_ci 1003d0407baSopenharmony_ci Mutex(const Mutex &); 1013d0407baSopenharmony_ci Mutex &operator = (const Mutex&); 1023d0407baSopenharmony_ci}; 1033d0407baSopenharmony_ci 1043d0407baSopenharmony_ciinline Mutex::Mutex() 1053d0407baSopenharmony_ci{ 1063d0407baSopenharmony_ci pthread_mutexattr_t attr; 1073d0407baSopenharmony_ci pthread_mutexattr_init(&attr); 1083d0407baSopenharmony_ci pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 1093d0407baSopenharmony_ci pthread_mutex_init(&mMutex, &attr); 1103d0407baSopenharmony_ci pthread_mutexattr_destroy(&attr); 1113d0407baSopenharmony_ci} 1123d0407baSopenharmony_ciinline Mutex::~Mutex() 1133d0407baSopenharmony_ci{ 1143d0407baSopenharmony_ci pthread_mutex_destroy(&mMutex); 1153d0407baSopenharmony_ci} 1163d0407baSopenharmony_ciinline void Mutex::lock() 1173d0407baSopenharmony_ci{ 1183d0407baSopenharmony_ci pthread_mutex_lock(&mMutex); 1193d0407baSopenharmony_ci} 1203d0407baSopenharmony_ciinline void Mutex::unlock() 1213d0407baSopenharmony_ci{ 1223d0407baSopenharmony_ci pthread_mutex_unlock(&mMutex); 1233d0407baSopenharmony_ci} 1243d0407baSopenharmony_ciinline int Mutex::trylock() 1253d0407baSopenharmony_ci{ 1263d0407baSopenharmony_ci return pthread_mutex_trylock(&mMutex); 1273d0407baSopenharmony_ci} 1283d0407baSopenharmony_ci 1293d0407baSopenharmony_citypedef Mutex::Autolock AutoMutex; 1303d0407baSopenharmony_ci 1313d0407baSopenharmony_ci 1323d0407baSopenharmony_ci/* 1333d0407baSopenharmony_ci * for shorter type name and function name 1343d0407baSopenharmony_ci */ 1353d0407baSopenharmony_ciclass Condition { 1363d0407baSopenharmony_cipublic: 1373d0407baSopenharmony_ci Condition(); 1383d0407baSopenharmony_ci Condition(int type); 1393d0407baSopenharmony_ci ~Condition(); 1403d0407baSopenharmony_ci RK_S32 wait(Mutex& mutex); 1413d0407baSopenharmony_ci RK_S32 wait(Mutex* mutex); 1423d0407baSopenharmony_ci RK_S32 timedwait(Mutex& mutex, RK_S64 timeout); 1433d0407baSopenharmony_ci RK_S32 timedwait(Mutex* mutex, RK_S64 timeout); 1443d0407baSopenharmony_ci RK_S32 signal(); 1453d0407baSopenharmony_ci RK_S32 broadcast(); 1463d0407baSopenharmony_ci 1473d0407baSopenharmony_ciprivate: 1483d0407baSopenharmony_ci pthread_cond_t mCond; 1493d0407baSopenharmony_ci}; 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ciinline Condition::Condition() 1523d0407baSopenharmony_ci{ 1533d0407baSopenharmony_ci pthread_cond_init(&mCond, NULL); 1543d0407baSopenharmony_ci} 1553d0407baSopenharmony_ciinline Condition::~Condition() 1563d0407baSopenharmony_ci{ 1573d0407baSopenharmony_ci pthread_cond_destroy(&mCond); 1583d0407baSopenharmony_ci} 1593d0407baSopenharmony_ciinline RK_S32 Condition::wait(Mutex& mutex) 1603d0407baSopenharmony_ci{ 1613d0407baSopenharmony_ci return pthread_cond_wait(&mCond, &mutex.mMutex); 1623d0407baSopenharmony_ci} 1633d0407baSopenharmony_ciinline RK_S32 Condition::wait(Mutex* mutex) 1643d0407baSopenharmony_ci{ 1653d0407baSopenharmony_ci return pthread_cond_wait(&mCond, &mutex->mMutex); 1663d0407baSopenharmony_ci} 1673d0407baSopenharmony_ciinline RK_S32 Condition::timedwait(Mutex& mutex, RK_S64 timeout) 1683d0407baSopenharmony_ci{ 1693d0407baSopenharmony_ci return timedwait(&mutex, timeout); 1703d0407baSopenharmony_ci} 1713d0407baSopenharmony_ciinline RK_S32 Condition::timedwait(Mutex* mutex, RK_S64 timeout) 1723d0407baSopenharmony_ci{ 1733d0407baSopenharmony_ci struct timespec ts; 1743d0407baSopenharmony_ci 1753d0407baSopenharmony_ci clock_gettime(CLOCK_REALTIME_COARSE, &ts); 1763d0407baSopenharmony_ci 1773d0407baSopenharmony_ci ts.tv_sec += timeout / 1000; // 1000:Get milliseconds 1783d0407baSopenharmony_ci ts.tv_nsec += (timeout % 1000) * 1000000; // 1000:Get milliseconds // 1000000:Get seconds 1793d0407baSopenharmony_ci /* Prevent the out of range at nanoseconds field */ 1803d0407baSopenharmony_ci ts.tv_sec += ts.tv_nsec / 1000000000; // 1000000000:Get seconds 1813d0407baSopenharmony_ci ts.tv_nsec %= 1000000000; // 1000000000:Get Get nanoseconds 1823d0407baSopenharmony_ci 1833d0407baSopenharmony_ci return pthread_cond_timedwait(&mCond, &mutex->mMutex, &ts); 1843d0407baSopenharmony_ci} 1853d0407baSopenharmony_ciinline RK_S32 Condition::signal() 1863d0407baSopenharmony_ci{ 1873d0407baSopenharmony_ci return pthread_cond_signal(&mCond); 1883d0407baSopenharmony_ci} 1893d0407baSopenharmony_ciinline RK_S32 Condition::broadcast() 1903d0407baSopenharmony_ci{ 1913d0407baSopenharmony_ci return pthread_cond_broadcast(&mCond); 1923d0407baSopenharmony_ci} 1933d0407baSopenharmony_ci 1943d0407baSopenharmony_ciclass MppMutexCond { 1953d0407baSopenharmony_cipublic: 1963d0407baSopenharmony_ci MppMutexCond() {}; 1973d0407baSopenharmony_ci ~MppMutexCond() {}; 1983d0407baSopenharmony_ci 1993d0407baSopenharmony_ci void lock() 2003d0407baSopenharmony_ci { 2013d0407baSopenharmony_ci mLock.lock(); 2023d0407baSopenharmony_ci } 2033d0407baSopenharmony_ci void unlock() 2043d0407baSopenharmony_ci { 2053d0407baSopenharmony_ci mLock.unlock(); 2063d0407baSopenharmony_ci } 2073d0407baSopenharmony_ci void trylock() 2083d0407baSopenharmony_ci { 2093d0407baSopenharmony_ci mLock.trylock(); 2103d0407baSopenharmony_ci } 2113d0407baSopenharmony_ci void wait() 2123d0407baSopenharmony_ci { 2133d0407baSopenharmony_ci mCondition.wait(mLock); 2143d0407baSopenharmony_ci } 2153d0407baSopenharmony_ci RK_S32 wait(RK_S64 timeout) 2163d0407baSopenharmony_ci { 2173d0407baSopenharmony_ci return mCondition.timedwait(mLock, timeout); 2183d0407baSopenharmony_ci } 2193d0407baSopenharmony_ci void signal() 2203d0407baSopenharmony_ci { 2213d0407baSopenharmony_ci mCondition.signal(); 2223d0407baSopenharmony_ci } 2233d0407baSopenharmony_ci void broadcast() 2243d0407baSopenharmony_ci { 2253d0407baSopenharmony_ci mCondition.broadcast(); 2263d0407baSopenharmony_ci } 2273d0407baSopenharmony_ci Mutex *mutex() 2283d0407baSopenharmony_ci { 2293d0407baSopenharmony_ci return &mLock; 2303d0407baSopenharmony_ci } 2313d0407baSopenharmony_ci 2323d0407baSopenharmony_ciprivate: 2333d0407baSopenharmony_ci Mutex mLock; 2343d0407baSopenharmony_ci Condition mCondition; 2353d0407baSopenharmony_ci}; 2363d0407baSopenharmony_ci 2373d0407baSopenharmony_ci// Thread lock / signal is distinguished by its source 2383d0407baSopenharmony_citypedef enum MppThreadSignal_e { 2393d0407baSopenharmony_ci THREAD_WORK, // for working loop 2403d0407baSopenharmony_ci THREAD_INPUT, // for thread input 2413d0407baSopenharmony_ci THREAD_OUTPUT, // for thread output 2423d0407baSopenharmony_ci THREAD_CONTROL, // for thread async control (reset) 2433d0407baSopenharmony_ci THREAD_SIGNAL_BUTT, 2443d0407baSopenharmony_ci} MppThreadSignal; 2453d0407baSopenharmony_ci 2463d0407baSopenharmony_ci#define THREAD_NORMAL 0 2473d0407baSopenharmony_ci#define THRE 0 2483d0407baSopenharmony_ci 2493d0407baSopenharmony_ciclass MppThread { 2503d0407baSopenharmony_cipublic: 2513d0407baSopenharmony_ci MppThread(MppThreadFunc func, void *ctx, const char *name = NULL); 2523d0407baSopenharmony_ci ~MppThread() {}; 2533d0407baSopenharmony_ci 2543d0407baSopenharmony_ci MppThreadStatus get_status(MppThreadSignal id = THREAD_WORK); 2553d0407baSopenharmony_ci void set_status(MppThreadStatus status, MppThreadSignal id = THREAD_WORK); 2563d0407baSopenharmony_ci void dump_status(); 2573d0407baSopenharmony_ci 2583d0407baSopenharmony_ci void start(); 2593d0407baSopenharmony_ci void stop(); 2603d0407baSopenharmony_ci 2613d0407baSopenharmony_ci void lock(MppThreadSignal id = THREAD_WORK) 2623d0407baSopenharmony_ci { 2633d0407baSopenharmony_ci mpp_assert(id < THREAD_SIGNAL_BUTT); 2643d0407baSopenharmony_ci mMutexCond[id].lock(); 2653d0407baSopenharmony_ci } 2663d0407baSopenharmony_ci 2673d0407baSopenharmony_ci void unlock(MppThreadSignal id = THREAD_WORK) 2683d0407baSopenharmony_ci { 2693d0407baSopenharmony_ci mpp_assert(id < THREAD_SIGNAL_BUTT); 2703d0407baSopenharmony_ci mMutexCond[id].unlock(); 2713d0407baSopenharmony_ci } 2723d0407baSopenharmony_ci 2733d0407baSopenharmony_ci void wait(MppThreadSignal id = THREAD_WORK) 2743d0407baSopenharmony_ci { 2753d0407baSopenharmony_ci mpp_assert(id < THREAD_SIGNAL_BUTT); 2763d0407baSopenharmony_ci MppThreadStatus status = mStatus[id]; 2773d0407baSopenharmony_ci 2783d0407baSopenharmony_ci mStatus[id] = MPP_THREAD_WAITING; 2793d0407baSopenharmony_ci mMutexCond[id].wait(); 2803d0407baSopenharmony_ci 2813d0407baSopenharmony_ci // check the status is not changed then restore status 2823d0407baSopenharmony_ci if (mStatus[id] == MPP_THREAD_WAITING) 2833d0407baSopenharmony_ci mStatus[id] = status; 2843d0407baSopenharmony_ci } 2853d0407baSopenharmony_ci 2863d0407baSopenharmony_ci void signal(MppThreadSignal id = THREAD_WORK) 2873d0407baSopenharmony_ci { 2883d0407baSopenharmony_ci mpp_assert(id < THREAD_SIGNAL_BUTT); 2893d0407baSopenharmony_ci mMutexCond[id].signal(); 2903d0407baSopenharmony_ci } 2913d0407baSopenharmony_ci 2923d0407baSopenharmony_ci Mutex *mutex(MppThreadSignal id = THREAD_WORK) 2933d0407baSopenharmony_ci { 2943d0407baSopenharmony_ci mpp_assert(id < THREAD_SIGNAL_BUTT); 2953d0407baSopenharmony_ci return mMutexCond[id].mutex(); 2963d0407baSopenharmony_ci } 2973d0407baSopenharmony_ci 2983d0407baSopenharmony_ciprivate: 2993d0407baSopenharmony_ci pthread_t mThread; 3003d0407baSopenharmony_ci MppMutexCond mMutexCond[THREAD_SIGNAL_BUTT]; 3013d0407baSopenharmony_ci MppThreadStatus mStatus[THREAD_SIGNAL_BUTT]; 3023d0407baSopenharmony_ci 3033d0407baSopenharmony_ci MppThreadFunc mFunction; 3043d0407baSopenharmony_ci char mName[THREAD_NAME_LEN]; 3053d0407baSopenharmony_ci void *mContext; 3063d0407baSopenharmony_ci 3073d0407baSopenharmony_ci MppThread(); 3083d0407baSopenharmony_ci MppThread(const MppThread &); 3093d0407baSopenharmony_ci MppThread &operator=(const MppThread &); 3103d0407baSopenharmony_ci}; 3113d0407baSopenharmony_ci 3123d0407baSopenharmony_ci#endif 3133d0407baSopenharmony_ci 3143d0407baSopenharmony_ci#endif /* __MPP_THREAD_H__ */ 315