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