| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 | #pragma once#if __cplusplus < 201103L#error "C++ version lower than C++11"#endif//#if defined(RT_USING_PTHREADS)#include <pthread.h>#include <system_error>#include <chrono>#include <utility>#include <functional>#include "__utils.h"#define rt_cpp_mutex_t  pthread_mutex_tnamespace std {    // Base class on which to build std::mutex and std::timed_mutex    class __mutex_base    {        protected:            typedef rt_cpp_mutex_t  __native_type;            __native_type _m_mutex = PTHREAD_MUTEX_INITIALIZER;            constexpr __mutex_base() noexcept = default;            __mutex_base(const __mutex_base&) = delete;            __mutex_base& operator=(const __mutex_base&) = delete;    };        class mutex : private __mutex_base    {        public:            constexpr mutex() = default;            ~mutex() = default;            mutex(const mutex&) = delete;            mutex& operator=(const mutex&) = delete;            void lock()            {                int err  = pthread_mutex_lock(&_m_mutex);                if (err)                {                    throw_system_error(err, "mutex:lock failed.");                }            }            bool try_lock() noexcept            {                return !pthread_mutex_trylock(&_m_mutex);            }            void unlock() noexcept            {                pthread_mutex_unlock(&_m_mutex);            }            typedef __native_type* native_handle_type;            native_handle_type native_handle()             {                return &_m_mutex;            };    };    inline int __rt_cpp_recursive_mutex_init(rt_cpp_mutex_t* m)    {        pthread_mutexattr_t attr;        int res;        res = pthread_mutexattr_init(&attr);        if (res)            return res;        res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);        if (res)            goto attr_cleanup;        res = pthread_mutex_init(m, &attr);        attr_cleanup:            int err = pthread_mutexattr_destroy(&attr);            return res ? res : err;    }    class __recursive_mutex_base    {        protected:            typedef rt_cpp_mutex_t __native_type;            __native_type _m_recursive_mutex;            __recursive_mutex_base(const __recursive_mutex_base&) = delete;            __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;            __recursive_mutex_base()            {                int err = __rt_cpp_recursive_mutex_init(&_m_recursive_mutex);                if (err)                    throw_system_error(err, "Recursive mutex failed to construct");            }            ~__recursive_mutex_base()            {                pthread_mutex_destroy(&_m_recursive_mutex);            }    };    class recursive_mutex : private __recursive_mutex_base    {        public:            typedef __native_type* native_handle_type;             recursive_mutex() = default;            ~recursive_mutex() = default;            recursive_mutex(const recursive_mutex&) = delete;            recursive_mutex& operator=(const recursive_mutex&) = delete;            void lock()            {                int err = pthread_mutex_lock(&_m_recursive_mutex);                if (err)                    throw_system_error(err, "recursive_mutex::lock failed");            }            bool try_lock() noexcept            {                return !pthread_mutex_trylock(&_m_recursive_mutex);            }            void unlock() noexcept            {                pthread_mutex_unlock(&_m_recursive_mutex);            }            native_handle_type native_handle()            { return &_m_recursive_mutex; }    };#ifdef RT_PTHREAD_TIMED_MUTEX    class timed_mutex;    class recursive_timed_mutex;#endif // RT_PTHREAD_TIMED_MUTEX        struct defer_lock_t {};    struct try_to_lock_t {};    struct adopt_lock_t {}; // take ownership of a locked mtuex    constexpr defer_lock_t defer_lock { };    constexpr try_to_lock_t try_to_lock { };    constexpr adopt_lock_t adopt_lock { };    template <class Mutex>     class lock_guard    {        public:            typedef Mutex mutex_type;            explicit lock_guard(mutex_type& m) : pm(m) { pm.lock(); }            lock_guard(mutex_type& m, adopt_lock_t) noexcept : pm(m)            { }            ~lock_guard()             { pm.unlock(); }            lock_guard(lock_guard const&) = delete;            lock_guard& operator=(lock_guard const&) = delete;        private:            mutex_type& pm;    };    template <class Mutex>    class unique_lock    {        public:            typedef Mutex mutex_type;            unique_lock() noexcept : pm(nullptr), owns(false) { }                        explicit unique_lock(mutex_type& m)                 : pm(std::addressof(m)), owns(false)            {                lock();                owns = true;            }            unique_lock(mutex_type& m, defer_lock_t) noexcept                 : pm(std::addressof(m)), owns(false)            { }            unique_lock(mutex_type& m, try_to_lock_t) noexcept                : pm(std::addressof(m)), owns(pm->try_lock())            { }            unique_lock(mutex_type& m, adopt_lock_t) noexcept                : pm(std::addressof(m)), owns(true)            { }            // any lock-involving timed mutex API is currently only for custom implementations            // the standard ones are not available            template <class Clock, class Duration>            unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time) noexcept                : pm(std::addressof(m)), owns(pm->try_lock_until(abs_time))            { }            template <class Rep, class Period>            unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time) noexcept                : pm(std::addressof(m)), owns(pm->try_lock_for(rel_time))            { }                        ~unique_lock()            {                if (owns)                    unlock();            }                        unique_lock(unique_lock const&) = delete;            unique_lock& operator=(unique_lock const&) = delete;            unique_lock(unique_lock&& u) noexcept                : pm(u.pm), owns(u.owns)            {                u.pm = nullptr;                u.owns = false;            }            unique_lock& operator=(unique_lock&& u) noexcept                            {                if (owns)                    unlock();                                unique_lock(std::move(u)).swap(*this);                u.pm = nullptr;                u.owns = false;                return *this;            }            void lock()            {                if (!pm)                    throw_system_error(int(errc::operation_not_permitted),                                         "unique_lock::lock: references null mutex");                else if (owns)                    throw_system_error(int(errc::resource_deadlock_would_occur),                                        "unique_lock::lock: already locked" );                else {                    pm->lock();                    owns = true;                }            }            bool try_lock()            {                if (!pm)                    throw_system_error(int(errc::operation_not_permitted),                                         "unique_lock::try_lock: references null mutex");                else if (owns)                    throw_system_error(int(errc::resource_deadlock_would_occur),                                        "unique_lock::try_lock: already locked" );                else {                    owns = pm->try_lock();                }                return owns;            }            template <class Rep, class Period>            bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)            {                if (!pm)                    throw_system_error(int(errc::operation_not_permitted),                                        "unique_lock::try_lock_for: references null mutex");                else if (owns)                    throw_system_error(int(errc::resource_deadlock_would_occur),                                        "unique_lock::try_lock_for: already locked");                else {                    owns = pm->try_lock_for(rel_time);                }                return owns;            }                        template <class Clock, class Duration>            bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)            {                if (!pm)                    throw_system_error(int(errc::operation_not_permitted),                                        "unique_lock::try_lock_until: references null mutex");                else if (owns)                    throw_system_error(int(errc::resource_deadlock_would_occur),                                        "unique_lock::try_lock_until: already locked");                else {                    owns = pm->try_lock_until(abs_time);                }                return owns;            }                        void unlock()            {                if (!owns)                    throw_system_error(int(errc::operation_not_permitted),                                         "unique_lock::unlock: not locked");                else {                    pm->unlock();                    owns = false;                }            }            void swap(unique_lock& u) noexcept            {                std::swap(pm, u.pm);                std::swap(owns, u.owns);            }            mutex_type *release() noexcept            {                mutex_type* ret_mutex = pm;                pm = nullptr;                owns = false;                                return ret_mutex;            }            bool owns_lock() const noexcept            { return owns; }            explicit operator bool() const noexcept            { return owns_lock(); }            mutex_type* mutex() const noexcept            { return pm; }                                private:            mutex_type *pm;             bool owns;    };    template <class Mutex>    void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)    {        x.swap(y);    }    template <class L0, class L1>    int try_lock(L0& l0, L1& l1)    {        unique_lock<L0> u0(l0, try_to_lock); // try to lock the first Lockable        // using unique_lock since we don't want to unlock l0 manually if l1 fails to lock        if (u0.owns_lock())        {            if (l1.try_lock()) // lock the second one            {                u0.release(); // do not let RAII of a unique_lock unlock l0                return -1;            }            else                return 1;         }        return 0;    }         template <class L0, class L1, class L2, class... L3>    int try_lock(L0& l0, L1& l1, L2& l2, L3&... l3)    {        int r = 0;        unique_lock<L0> u0(l0, try_to_lock);        // automatically unlock is done through RAII of unique_lock        if (u0.owns_lock())        {            r = try_lock(l1, l2, l3...);            if (r == -1)                u0.release();            else                ++r;        }        return r;    }    template <class L0, class L1, class L2, class ...L3>    void    __lock_first(int i, L0& l0, L1& l1, L2& l2, L3&... l3)    {        while (true)        {            // we first lock the one that is the most difficult to lock             switch (i)             {            case 0:                {                    unique_lock<L0> u0(l0);                    i = try_lock(l1, l2, l3...);                    if (i == -1)                    {                        u0.release();                        return;                    }                }                ++i;                sched_yield();                break;            case 1:                {                    unique_lock<L1> u1(l1);                    i = try_lock(l2, l3..., l0);                    if (i == -1)                    {                        u1.release();                        return;                    }                }                if (i == sizeof...(L3) + 1) // all except l0 are locked                    i = 0;                else                    i += 2; // since i was two-based above                sched_yield();                break;            default:                __lock_first(i - 2, l2, l3..., l0, l1);                return;            }        }    }    template <class L0, class L1>    void lock(L0& l0, L1& l1)    {        while (true)        {            {                unique_lock<L0> u0(l0);                if (l1.try_lock())                {                    u0.release();                    break;                }            }            sched_yield();            // wait and try the other way            {                unique_lock<L1> u1(l1);                if (l0.try_lock())                {                    u1.release();                    break;                }            }            sched_yield();        }    }    template <class L0, class L1, class... L2>    void lock(L0& l0, L1& l1, L2&... l2)    {        __lock_first(0, l0, l1, l2...);    }    struct once_flag     {        constexpr once_flag() noexcept = default;        once_flag(const once_flag&) = delete;        once_flag& operator=(const once_flag&) = delete;        template <class Callable, class... Args>        friend void call_once(once_flag& flag, Callable&& func, Args&&... args);        private:            pthread_once_t _m_once = PTHREAD_ONCE_INIT;    };    mutex& get_once_mutex();    extern function<void()> once_functor;    extern void set_once_functor_lock_ptr(unique_lock<mutex>*);    extern "C" void once_proxy(); // passed into pthread_once    template <class Callable, class... Args>    void call_once(once_flag& flag, Callable&& func, Args&&... args)    {        // use a lock to ensure the call to the functor        // is exclusive to only the first calling thread        unique_lock<mutex> functor_lock(get_once_mutex());         auto call_wrapper = std::bind(std::forward<Callable>(func), std::forward<Args>(args)...);        once_functor = [&]() { call_wrapper(); };        set_once_functor_lock_ptr(&functor_lock); // so as to unlock when actually calling        int err = pthread_once(&flag._m_once, &once_proxy);        if (functor_lock)            set_once_functor_lock_ptr(nullptr);        if (err)            throw_system_error(err, "call_once failed");    }}//#endif //(RT_USING_PTHREADS)
 |