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_ci/*
633d0407baSopenharmony_ci * for shorter type name and function name
643d0407baSopenharmony_ci */
653d0407baSopenharmony_ciclass Mutex {
663d0407baSopenharmony_cipublic:
673d0407baSopenharmony_ci    Mutex();
683d0407baSopenharmony_ci    ~Mutex();
693d0407baSopenharmony_ci
703d0407baSopenharmony_ci    void lock();
713d0407baSopenharmony_ci    void unlock();
723d0407baSopenharmony_ci    int trylock();
733d0407baSopenharmony_ci
743d0407baSopenharmony_ci    class Autolock {
753d0407baSopenharmony_ci    public:
763d0407baSopenharmony_ci        inline Autolock(Mutex *mutex, unsigned int enable = 1) : mEnabled(enable), mLock(*mutex)
773d0407baSopenharmony_ci        {
783d0407baSopenharmony_ci            if (mEnabled) {
793d0407baSopenharmony_ci                mLock.lock();
803d0407baSopenharmony_ci            }
813d0407baSopenharmony_ci        }
823d0407baSopenharmony_ci        inline ~Autolock()
833d0407baSopenharmony_ci        {
843d0407baSopenharmony_ci            if (mEnabled) {
853d0407baSopenharmony_ci                mLock.unlock();
863d0407baSopenharmony_ci            }
873d0407baSopenharmony_ci        }
883d0407baSopenharmony_ci
893d0407baSopenharmony_ci    private:
903d0407baSopenharmony_ci        signed int mEnabled;
913d0407baSopenharmony_ci        Mutex &mLock;
923d0407baSopenharmony_ci    };
933d0407baSopenharmony_ci
943d0407baSopenharmony_ciprivate:
953d0407baSopenharmony_ci    friend class Condition;
963d0407baSopenharmony_ci
973d0407baSopenharmony_ci    pthread_mutex_t mMutex;
983d0407baSopenharmony_ci
993d0407baSopenharmony_ci    Mutex(const Mutex &);
1003d0407baSopenharmony_ci    Mutex &operator=(const Mutex &);
1013d0407baSopenharmony_ci};
1023d0407baSopenharmony_ci
1033d0407baSopenharmony_ciinline Mutex::Mutex()
1043d0407baSopenharmony_ci{
1053d0407baSopenharmony_ci    pthread_mutexattr_t attr;
1063d0407baSopenharmony_ci    pthread_mutexattr_init(&attr);
1073d0407baSopenharmony_ci    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1083d0407baSopenharmony_ci    pthread_mutex_init(&mMutex, &attr);
1093d0407baSopenharmony_ci    pthread_mutexattr_destroy(&attr);
1103d0407baSopenharmony_ci}
1113d0407baSopenharmony_ciinline Mutex::~Mutex()
1123d0407baSopenharmony_ci{
1133d0407baSopenharmony_ci    pthread_mutex_destroy(&mMutex);
1143d0407baSopenharmony_ci}
1153d0407baSopenharmony_ciinline void Mutex::lock()
1163d0407baSopenharmony_ci{
1173d0407baSopenharmony_ci    pthread_mutex_lock(&mMutex);
1183d0407baSopenharmony_ci}
1193d0407baSopenharmony_ciinline void Mutex::unlock()
1203d0407baSopenharmony_ci{
1213d0407baSopenharmony_ci    pthread_mutex_unlock(&mMutex);
1223d0407baSopenharmony_ci}
1233d0407baSopenharmony_ciinline int Mutex::trylock()
1243d0407baSopenharmony_ci{
1253d0407baSopenharmony_ci    return pthread_mutex_trylock(&mMutex);
1263d0407baSopenharmony_ci}
1273d0407baSopenharmony_ci
1283d0407baSopenharmony_citypedef Mutex::Autolock AutoMutex;
1293d0407baSopenharmony_ci
1303d0407baSopenharmony_ci/*
1313d0407baSopenharmony_ci * for shorter type name and function name
1323d0407baSopenharmony_ci */
1333d0407baSopenharmony_ciclass Condition {
1343d0407baSopenharmony_cipublic:
1353d0407baSopenharmony_ci    Condition();
1363d0407baSopenharmony_ci    Condition(int type);
1373d0407baSopenharmony_ci    ~Condition();
1383d0407baSopenharmony_ci    signed int wait(Mutex &mutex);
1393d0407baSopenharmony_ci    signed int wait(Mutex *mutex);
1403d0407baSopenharmony_ci    signed int timedwait(Mutex &mutex, RK_S64 timeout);
1413d0407baSopenharmony_ci    signed int timedwait(Mutex *mutex, RK_S64 timeout);
1423d0407baSopenharmony_ci    signed int signal();
1433d0407baSopenharmony_ci    signed int broadcast();
1443d0407baSopenharmony_ci
1453d0407baSopenharmony_ciprivate:
1463d0407baSopenharmony_ci    pthread_cond_t mCond;
1473d0407baSopenharmony_ci};
1483d0407baSopenharmony_ci
1493d0407baSopenharmony_ciinline Condition::Condition()
1503d0407baSopenharmony_ci{
1513d0407baSopenharmony_ci    pthread_cond_init(&mCond, NULL);
1523d0407baSopenharmony_ci}
1533d0407baSopenharmony_ciinline Condition::~Condition()
1543d0407baSopenharmony_ci{
1553d0407baSopenharmony_ci    pthread_cond_destroy(&mCond);
1563d0407baSopenharmony_ci}
1573d0407baSopenharmony_ciinline signed int Condition::wait(Mutex &mutex)
1583d0407baSopenharmony_ci{
1593d0407baSopenharmony_ci    return pthread_cond_wait(&mCond, &mutex.mMutex);
1603d0407baSopenharmony_ci}
1613d0407baSopenharmony_ciinline signed int Condition::wait(Mutex *mutex)
1623d0407baSopenharmony_ci{
1633d0407baSopenharmony_ci    return pthread_cond_wait(&mCond, &mutex->mMutex);
1643d0407baSopenharmony_ci}
1653d0407baSopenharmony_ciinline signed int Condition::timedwait(Mutex &mutex, RK_S64 timeout)
1663d0407baSopenharmony_ci{
1673d0407baSopenharmony_ci    return timedwait(&mutex, timeout);
1683d0407baSopenharmony_ci}
1693d0407baSopenharmony_ciinline signed int Condition::timedwait(Mutex *mutex, RK_S64 timeout)
1703d0407baSopenharmony_ci{
1713d0407baSopenharmony_ci    struct timespec ts;
1723d0407baSopenharmony_ci
1733d0407baSopenharmony_ci    clock_gettime(CLOCK_REALTIME_COARSE, &ts);
1743d0407baSopenharmony_ci
1753d0407baSopenharmony_ci    ts.tv_sec += timeout / 1000;              // 1000:Get milliseconds
1763d0407baSopenharmony_ci    ts.tv_nsec += (timeout % 1000) * 1000000; // 1000:Get milliseconds // 1000000:Get seconds
1773d0407baSopenharmony_ci    /* Prevent the out of range at nanoseconds field */
1783d0407baSopenharmony_ci    ts.tv_sec += ts.tv_nsec / 1000000000; // 1000000000:Get seconds
1793d0407baSopenharmony_ci    ts.tv_nsec %= 1000000000;             // 1000000000:Get Get nanoseconds
1803d0407baSopenharmony_ci
1813d0407baSopenharmony_ci    return pthread_cond_timedwait(&mCond, &mutex->mMutex, &ts);
1823d0407baSopenharmony_ci}
1833d0407baSopenharmony_ciinline signed int Condition::signal()
1843d0407baSopenharmony_ci{
1853d0407baSopenharmony_ci    return pthread_cond_signal(&mCond);
1863d0407baSopenharmony_ci}
1873d0407baSopenharmony_ciinline signed int Condition::broadcast()
1883d0407baSopenharmony_ci{
1893d0407baSopenharmony_ci    return pthread_cond_broadcast(&mCond);
1903d0407baSopenharmony_ci}
1913d0407baSopenharmony_ci
1923d0407baSopenharmony_ciclass MppMutexCond {
1933d0407baSopenharmony_cipublic:
1943d0407baSopenharmony_ci    MppMutexCond() {};
1953d0407baSopenharmony_ci    ~MppMutexCond() {};
1963d0407baSopenharmony_ci
1973d0407baSopenharmony_ci    void lock()
1983d0407baSopenharmony_ci    {
1993d0407baSopenharmony_ci        mLock.lock();
2003d0407baSopenharmony_ci    }
2013d0407baSopenharmony_ci    void unlock()
2023d0407baSopenharmony_ci    {
2033d0407baSopenharmony_ci        mLock.unlock();
2043d0407baSopenharmony_ci    }
2053d0407baSopenharmony_ci    void trylock()
2063d0407baSopenharmony_ci    {
2073d0407baSopenharmony_ci        mLock.trylock();
2083d0407baSopenharmony_ci    }
2093d0407baSopenharmony_ci    void wait()
2103d0407baSopenharmony_ci    {
2113d0407baSopenharmony_ci        mCondition.wait(mLock);
2123d0407baSopenharmony_ci    }
2133d0407baSopenharmony_ci    signed int wait(RK_S64 timeout)
2143d0407baSopenharmony_ci    {
2153d0407baSopenharmony_ci        return mCondition.timedwait(mLock, timeout);
2163d0407baSopenharmony_ci    }
2173d0407baSopenharmony_ci    void signal()
2183d0407baSopenharmony_ci    {
2193d0407baSopenharmony_ci        mCondition.signal();
2203d0407baSopenharmony_ci    }
2213d0407baSopenharmony_ci    void broadcast()
2223d0407baSopenharmony_ci    {
2233d0407baSopenharmony_ci        mCondition.broadcast();
2243d0407baSopenharmony_ci    }
2253d0407baSopenharmony_ci    Mutex *mutex()
2263d0407baSopenharmony_ci    {
2273d0407baSopenharmony_ci        return &mLock;
2283d0407baSopenharmony_ci    }
2293d0407baSopenharmony_ci
2303d0407baSopenharmony_ciprivate:
2313d0407baSopenharmony_ci    Mutex mLock;
2323d0407baSopenharmony_ci    Condition mCondition;
2333d0407baSopenharmony_ci};
2343d0407baSopenharmony_ci
2353d0407baSopenharmony_ci// Thread lock / signal is distinguished by its source
2363d0407baSopenharmony_citypedef enum MppThreadSignal_e {
2373d0407baSopenharmony_ci    THREAD_WORK,    // for working loop
2383d0407baSopenharmony_ci    THREAD_INPUT,   // for thread input
2393d0407baSopenharmony_ci    THREAD_OUTPUT,  // for thread output
2403d0407baSopenharmony_ci    THREAD_CONTROL, // for thread async control (reset)
2413d0407baSopenharmony_ci    THREAD_SIGNAL_BUTT,
2423d0407baSopenharmony_ci} MppThreadSignal;
2433d0407baSopenharmony_ci
2443d0407baSopenharmony_ci#define THREAD_NORMAL 0
2453d0407baSopenharmony_ci#define THRE 0
2463d0407baSopenharmony_ci
2473d0407baSopenharmony_ciclass MppThread {
2483d0407baSopenharmony_cipublic:
2493d0407baSopenharmony_ci    MppThread(MppThreadFunc func, void *ctx, const char *name = NULL);
2503d0407baSopenharmony_ci    ~MppThread() {};
2513d0407baSopenharmony_ci
2523d0407baSopenharmony_ci    MppThreadStatus get_status(MppThreadSignal id = THREAD_WORK);
2533d0407baSopenharmony_ci    void set_status(MppThreadStatus status, MppThreadSignal id = THREAD_WORK);
2543d0407baSopenharmony_ci    void dump_status();
2553d0407baSopenharmony_ci
2563d0407baSopenharmony_ci    void start();
2573d0407baSopenharmony_ci    void stop();
2583d0407baSopenharmony_ci
2593d0407baSopenharmony_ci    void lock(MppThreadSignal id = THREAD_WORK)
2603d0407baSopenharmony_ci    {
2613d0407baSopenharmony_ci        mpp_assert(id < THREAD_SIGNAL_BUTT);
2623d0407baSopenharmony_ci        mMutexCond[id].lock();
2633d0407baSopenharmony_ci    }
2643d0407baSopenharmony_ci
2653d0407baSopenharmony_ci    void unlock(MppThreadSignal id = THREAD_WORK)
2663d0407baSopenharmony_ci    {
2673d0407baSopenharmony_ci        mpp_assert(id < THREAD_SIGNAL_BUTT);
2683d0407baSopenharmony_ci        mMutexCond[id].unlock();
2693d0407baSopenharmony_ci    }
2703d0407baSopenharmony_ci
2713d0407baSopenharmony_ci    void wait(MppThreadSignal id = THREAD_WORK)
2723d0407baSopenharmony_ci    {
2733d0407baSopenharmony_ci        mpp_assert(id < THREAD_SIGNAL_BUTT);
2743d0407baSopenharmony_ci        MppThreadStatus status = mStatus[id];
2753d0407baSopenharmony_ci
2763d0407baSopenharmony_ci        mStatus[id] = MPP_THREAD_WAITING;
2773d0407baSopenharmony_ci        mMutexCond[id].wait();
2783d0407baSopenharmony_ci
2793d0407baSopenharmony_ci        // check the status is not changed then restore status
2803d0407baSopenharmony_ci        if (mStatus[id] == MPP_THREAD_WAITING) {
2813d0407baSopenharmony_ci            mStatus[id] = status;
2823d0407baSopenharmony_ci        }
2833d0407baSopenharmony_ci    }
2843d0407baSopenharmony_ci
2853d0407baSopenharmony_ci    void signal(MppThreadSignal id = THREAD_WORK)
2863d0407baSopenharmony_ci    {
2873d0407baSopenharmony_ci        mpp_assert(id < THREAD_SIGNAL_BUTT);
2883d0407baSopenharmony_ci        mMutexCond[id].signal();
2893d0407baSopenharmony_ci    }
2903d0407baSopenharmony_ci
2913d0407baSopenharmony_ci    Mutex *mutex(MppThreadSignal id = THREAD_WORK)
2923d0407baSopenharmony_ci    {
2933d0407baSopenharmony_ci        mpp_assert(id < THREAD_SIGNAL_BUTT);
2943d0407baSopenharmony_ci        return mMutexCond[id].mutex();
2953d0407baSopenharmony_ci    }
2963d0407baSopenharmony_ci
2973d0407baSopenharmony_ciprivate:
2983d0407baSopenharmony_ci    pthread_t mThread;
2993d0407baSopenharmony_ci    MppMutexCond mMutexCond[THREAD_SIGNAL_BUTT];
3003d0407baSopenharmony_ci    MppThreadStatus mStatus[THREAD_SIGNAL_BUTT];
3013d0407baSopenharmony_ci
3023d0407baSopenharmony_ci    MppThreadFunc mFunction;
3033d0407baSopenharmony_ci    char mName[THREAD_NAME_LEN];
3043d0407baSopenharmony_ci    void *mContext;
3053d0407baSopenharmony_ci
3063d0407baSopenharmony_ci    MppThread();
3073d0407baSopenharmony_ci    MppThread(const MppThread &);
3083d0407baSopenharmony_ci    MppThread &operator=(const MppThread &);
3093d0407baSopenharmony_ci};
3103d0407baSopenharmony_ci
3113d0407baSopenharmony_ci#endif
3123d0407baSopenharmony_ci
3133d0407baSopenharmony_ci#endif /* __MPP_THREAD_H__ */
314