13d0407baSopenharmony_ci/*
23d0407baSopenharmony_ci * Copyright (C) 2020 Rockchip Electronics Co., Ltd.
33d0407baSopenharmony_ci * Authors:
43d0407baSopenharmony_ci *  PutinLee <putin.lee@rock-chips.com>
53d0407baSopenharmony_ci *
63d0407baSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
73d0407baSopenharmony_ci * you may not use this file except in compliance with the License.
83d0407baSopenharmony_ci * You may obtain a copy of the License at
93d0407baSopenharmony_ci *
103d0407baSopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
113d0407baSopenharmony_ci *
123d0407baSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
133d0407baSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
143d0407baSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
153d0407baSopenharmony_ci * See the License for the specific language governing permissions and
163d0407baSopenharmony_ci * limitations under the License.
173d0407baSopenharmony_ci */
183d0407baSopenharmony_ci
193d0407baSopenharmony_ci
203d0407baSopenharmony_ci#ifndef _LIBS_RGA_MUTEX_H
213d0407baSopenharmony_ci#define _LIBS_RGA_MUTEX_H
223d0407baSopenharmony_ci
233d0407baSopenharmony_ci#include <stdint.h>
243d0407baSopenharmony_ci#include <sys/types.h>
253d0407baSopenharmony_ci#include <time.h>
263d0407baSopenharmony_ci
273d0407baSopenharmony_ci#include <pthread.h>
283d0407baSopenharmony_ci
293d0407baSopenharmony_ci
303d0407baSopenharmony_ci// Enable thread safety attributes only with clang.
313d0407baSopenharmony_ci// The attributes can be safely erased when compiling with other compilers.
323d0407baSopenharmony_ci#if defined(__clang__) && (!defined(SWIG))
333d0407baSopenharmony_ci#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
343d0407baSopenharmony_ci#else
353d0407baSopenharmony_ci#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
363d0407baSopenharmony_ci#endif
373d0407baSopenharmony_ci
383d0407baSopenharmony_ci#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
393d0407baSopenharmony_ci
403d0407baSopenharmony_ci#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
413d0407baSopenharmony_ci
423d0407baSopenharmony_ci#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
433d0407baSopenharmony_ci
443d0407baSopenharmony_ci#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
453d0407baSopenharmony_ci
463d0407baSopenharmony_ci#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
473d0407baSopenharmony_ci
483d0407baSopenharmony_ci#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
493d0407baSopenharmony_ci
503d0407baSopenharmony_ci#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
513d0407baSopenharmony_ci
523d0407baSopenharmony_ci#define REQUIRES_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
533d0407baSopenharmony_ci
543d0407baSopenharmony_ci#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
553d0407baSopenharmony_ci
563d0407baSopenharmony_ci#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
573d0407baSopenharmony_ci
583d0407baSopenharmony_ci#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
593d0407baSopenharmony_ci
603d0407baSopenharmony_ci#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
613d0407baSopenharmony_ci
623d0407baSopenharmony_ci#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
633d0407baSopenharmony_ci
643d0407baSopenharmony_ci#define TRY_ACQUIRE_SHARED(...) \
653d0407baSopenharmony_ci    THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
663d0407baSopenharmony_ci
673d0407baSopenharmony_ci#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
683d0407baSopenharmony_ci
693d0407baSopenharmony_ci#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
703d0407baSopenharmony_ci
713d0407baSopenharmony_ci#define ASSERT_SHARED_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
723d0407baSopenharmony_ci
733d0407baSopenharmony_ci#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
743d0407baSopenharmony_ci
753d0407baSopenharmony_ci#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
763d0407baSopenharmony_ci
773d0407baSopenharmony_ciclass Condition;
783d0407baSopenharmony_ci
793d0407baSopenharmony_ci/*
803d0407baSopenharmony_ci * NOTE: This class is for code that builds on Win32.  Its usage is
813d0407baSopenharmony_ci * deprecated for code which doesn't build for Win32.  New code which
823d0407baSopenharmony_ci * doesn't build for Win32 should use std::mutex and std::lock_guard instead.
833d0407baSopenharmony_ci *
843d0407baSopenharmony_ci * Simple mutex class.  The implementation is system-dependent.
853d0407baSopenharmony_ci *
863d0407baSopenharmony_ci * The mutex must be unlocked by the thread that locked it.  They are not
873d0407baSopenharmony_ci * recursive, i.e. the same thread can't lock it multiple times.
883d0407baSopenharmony_ci */
893d0407baSopenharmony_ciclass CAPABILITY("mutex") Mutex {
903d0407baSopenharmony_cipublic:
913d0407baSopenharmony_ci    enum {
923d0407baSopenharmony_ci        PRIVATE = 0,
933d0407baSopenharmony_ci        SHARED = 1
943d0407baSopenharmony_ci    };
953d0407baSopenharmony_ci
963d0407baSopenharmony_ci    Mutex();
973d0407baSopenharmony_ci    explicit Mutex(const char* name);
983d0407baSopenharmony_ci    explicit Mutex(int type, const char* name = nullptr);
993d0407baSopenharmony_ci    ~Mutex();
1003d0407baSopenharmony_ci
1013d0407baSopenharmony_ci    // lock or unlock the mutex
1023d0407baSopenharmony_ci    int32_t lock() ACQUIRE();
1033d0407baSopenharmony_ci    void unlock() RELEASE();
1043d0407baSopenharmony_ci
1053d0407baSopenharmony_ci    // lock if possible; returns 0 on success, error otherwise
1063d0407baSopenharmony_ci    int32_t tryLock() TRY_ACQUIRE(0);
1073d0407baSopenharmony_ci
1083d0407baSopenharmony_ci    int32_t timedLock(int64_t timeoutNs) TRY_ACQUIRE(0);
1093d0407baSopenharmony_ci
1103d0407baSopenharmony_ci    // Manages the mutex automatically. It'll be locked when Autolock is
1113d0407baSopenharmony_ci    // constructed and released when Autolock goes out of scope.
1123d0407baSopenharmony_ci    class SCOPED_CAPABILITY Autolock {
1133d0407baSopenharmony_ci    public:
1143d0407baSopenharmony_ci        inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex)
1153d0407baSopenharmony_ci        {
1163d0407baSopenharmony_ci            mLock.lock();
1173d0407baSopenharmony_ci        }
1183d0407baSopenharmony_ci        inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex)
1193d0407baSopenharmony_ci        {
1203d0407baSopenharmony_ci            mLock.lock();
1213d0407baSopenharmony_ci        }
1223d0407baSopenharmony_ci        inline ~Autolock() RELEASE()
1233d0407baSopenharmony_ci        {
1243d0407baSopenharmony_ci            mLock.unlock();
1253d0407baSopenharmony_ci        }
1263d0407baSopenharmony_ci
1273d0407baSopenharmony_ci    private:
1283d0407baSopenharmony_ci        Mutex& mLock;
1293d0407baSopenharmony_ci        // Cannot be copied or moved - declarations only
1303d0407baSopenharmony_ci        Autolock(const Autolock&);
1313d0407baSopenharmony_ci        Autolock& operator=(const Autolock&);
1323d0407baSopenharmony_ci    };
1333d0407baSopenharmony_ci
1343d0407baSopenharmony_ciprivate:
1353d0407baSopenharmony_ci    friend class Condition;
1363d0407baSopenharmony_ci
1373d0407baSopenharmony_ci    // A mutex cannot be copied
1383d0407baSopenharmony_ci    Mutex(const Mutex&);
1393d0407baSopenharmony_ci    Mutex& operator=(const Mutex&);
1403d0407baSopenharmony_ci
1413d0407baSopenharmony_ci    pthread_mutex_t mMutex;
1423d0407baSopenharmony_ci};
1433d0407baSopenharmony_ci
1443d0407baSopenharmony_ci// ---------------------------------------------------------------------------
1453d0407baSopenharmony_ciinline Mutex::Mutex()
1463d0407baSopenharmony_ci{
1473d0407baSopenharmony_ci    pthread_mutex_init(&mMutex, nullptr);
1483d0407baSopenharmony_ci}
1493d0407baSopenharmony_ciinline Mutex::Mutex(__attribute__((unused)) const char* name)
1503d0407baSopenharmony_ci{
1513d0407baSopenharmony_ci    pthread_mutex_init(&mMutex, nullptr);
1523d0407baSopenharmony_ci}
1533d0407baSopenharmony_ciinline Mutex::Mutex(int type, __attribute__((unused)) const char* name)
1543d0407baSopenharmony_ci{
1553d0407baSopenharmony_ci    if (type == SHARED) {
1563d0407baSopenharmony_ci        pthread_mutexattr_t attr;
1573d0407baSopenharmony_ci        pthread_mutexattr_init(&attr);
1583d0407baSopenharmony_ci        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1593d0407baSopenharmony_ci        pthread_mutex_init(&mMutex, &attr);
1603d0407baSopenharmony_ci        pthread_mutexattr_destroy(&attr);
1613d0407baSopenharmony_ci    } else {
1623d0407baSopenharmony_ci        pthread_mutex_init(&mMutex, nullptr);
1633d0407baSopenharmony_ci    }
1643d0407baSopenharmony_ci}
1653d0407baSopenharmony_ciinline Mutex::~Mutex()
1663d0407baSopenharmony_ci{
1673d0407baSopenharmony_ci    pthread_mutex_destroy(&mMutex);
1683d0407baSopenharmony_ci}
1693d0407baSopenharmony_ciinline int32_t Mutex::lock()
1703d0407baSopenharmony_ci{
1713d0407baSopenharmony_ci    return -pthread_mutex_lock(&mMutex);
1723d0407baSopenharmony_ci}
1733d0407baSopenharmony_ciinline void Mutex::unlock()
1743d0407baSopenharmony_ci{
1753d0407baSopenharmony_ci    pthread_mutex_unlock(&mMutex);
1763d0407baSopenharmony_ci}
1773d0407baSopenharmony_ciinline int32_t Mutex::tryLock()
1783d0407baSopenharmony_ci{
1793d0407baSopenharmony_ci    return -pthread_mutex_trylock(&mMutex);
1803d0407baSopenharmony_ci}
1813d0407baSopenharmony_ciinline int32_t Mutex::timedLock(int64_t timeoutNs)
1823d0407baSopenharmony_ci{
1833d0407baSopenharmony_ci    timespec now;
1843d0407baSopenharmony_ci    clock_gettime(CLOCK_REALTIME, &now);
1853d0407baSopenharmony_ci    timeoutNs += now.tv_sec * 1000000000 + now.tv_nsec; // 1000000000:unit conversion
1863d0407baSopenharmony_ci    const struct timespec ts = {
1873d0407baSopenharmony_ci        static_cast<time_t>(timeoutNs / 1000000000), // 1000000000:unit conversion
1883d0407baSopenharmony_ci        static_cast<long>(timeoutNs % 1000000000), // 1000000000:unit conversion
1893d0407baSopenharmony_ci    };
1903d0407baSopenharmony_ci    return -pthread_mutex_timedlock(&mMutex, &ts);
1913d0407baSopenharmony_ci}
1923d0407baSopenharmony_ci
1933d0407baSopenharmony_ci// ---------------------------------------------------------------------------
1943d0407baSopenharmony_ci
1953d0407baSopenharmony_ci/*
1963d0407baSopenharmony_ci * Automatic mutex.  Declare one of these at the top of a function.
1973d0407baSopenharmony_ci * When the function returns, it will go out of scope, and release the
1983d0407baSopenharmony_ci * mutex.
1993d0407baSopenharmony_ci */
2003d0407baSopenharmony_ci
2013d0407baSopenharmony_citypedef Mutex::Autolock AutoMutex;
2023d0407baSopenharmony_ci#endif // _LIBS_RGA_MUTEX_H
203