HelenOS sources

root/uspace/lib/cpp/include/__bits/thread/shared_mutex.hpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. try_lock_for
  2. try_lock_until
  3. try_lock_shared_for
  4. try_lock_shared_until
  5. lock
  6. try_lock
  7. try_lock_for
  8. try_lock_until
  9. unlock
  10. swap
  11. release
  12. owns_lock
  13. swap

/*
 * Copyright (c) 2018 Jaroslav Jindrak
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef LIBCPP_THREAD_SHARED_MUTEX
#define LIBCPP_THREAD_SHARED_MUTEX

#include <__bits/thread/threading.hpp>
#include <chrono>
#include <mutex>

namespace std
{
    /**
     * 30.4.1.4.1, class shared_timed_mutex:
     */

    class shared_timed_mutex
    {
        public:
            shared_timed_mutex() noexcept;
            ~shared_timed_mutex();

            shared_timed_mutex(const shared_timed_mutex&) = delete;
            shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;

            void lock();
            bool try_lock();
            void unlock();

            template<class Rep, class Period>
            bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
            {
                auto time = aux::threading::time::convert(rel_time);

                return aux::threading::shared_mutex::try_lock_for(time);
            }

            template<class Clock, class Duration>
            bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
            {
                auto dur = (abs_time - Clock::now());
                auto time = aux::threading::time::convert(dur);

                return aux::threading::shared_mutex::try_lock_for(time);
            }

            void lock_shared();
            bool try_lock_shared();
            void unlock_shared();

            template<class Rep, class Period>
            bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
            {
                auto time = aux::threading::time::convert(rel_time);

                return aux::threading::shared_mutex::try_lock_shared_for(time);
            }

            template<class Clock, class Duration>
            bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
            {
                auto dur = (abs_time - Clock::now());
                auto time = aux::threading::time::convert(dur);

                return aux::threading::shared_mutex::try_lock_shared_for(time);
            }

            using native_handle_type = aux::shared_mutex_t*;
            native_handle_type native_handle();

        private:
            aux::shared_mutex_t mtx_;
    };

    /**
     * 30.4.2.3, class template shared_lock:
     */

    template<class Mutex>
    class shared_lock
    {
        public:
            using mutex_type = Mutex;

            /**
             * 30.4.2.2.1, construction/copy/destroy:
             */

            shared_lock() noexcept
                : mtx_{nullptr}, owns_{false}
            { /* DUMMY BODY */ }

            explicit shared_lock(mutex_type& mtx)
                : mtx_{&mtx}, owns_{true}
            {
                mtx_->lock_shared();
            }

            shared_lock(mutex_type& mtx, defer_lock_t) noexcept
                : mtx_{&mtx}, owns_{false}
            { /* DUMMY BODY */ }

            shared_lock(mutex_type& mtx, try_to_lock_t)
                : mtx_{&mtx}, owns_{}
            {
                owns_ = mtx_->try_lock_shared();
            }

            shared_lock(mutex_type& mtx, adopt_lock_t)
                : mtx_{&mtx}, owns_{true}
            { /* DUMMY BODY */ }

            template<class Clock, class Duration>
            shared_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
                : mtx_{&mtx}, owns_{}
            {
                owns_ = mtx_->try_lock_shared_until(abs_time);
            }

            template<class Rep, class Period>
            shared_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
                : mtx_{&mtx}, owns_{}
            {
                owns_ = mtx_->try_lock_shared_for(rel_time);
            }

            ~shared_lock()
            {
                if (owns_)
                    mtx_->unlock_shared();
            }

            shared_lock(const shared_lock&) = delete;
            shared_lock& operator=(const shared_lock&) = delete;

            shared_lock(shared_lock&& other) noexcept
                : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
            {
                other.mtx_ = nullptr;
                other.owns_ = false;
            }

            shared_lock& operator=(shared_lock&& other)
            {
                if (owns_)
                    mtx_->unlock_shared();

                mtx_ = move(other.mtx_);
                owns_ = move(other.owns_);

                other.mtx_ = nullptr;
                other.owns_ = false;
            }

            /**
             * 30.4.2.2.2, locking:
             */

            void lock()
            {
                /**
                 * TODO:
                 * throw system_error operation_not_permitted if mtx_ == nullptr
                 * throw system_error resource_deadlock_would_occur if owns_ == true
                 */

                mtx_->lock_shared();
                owns_ = true;
            }

            bool try_lock()
            {
                /**
                 * TODO:
                 * throw system_error operation_not_permitted if mtx_ == nullptr
                 * throw system_error resource_deadlock_would_occur if owns_ == true
                 */

                owns_ = mtx_->try_lock_shared();

                return owns_;
            }

            template<class Rep, class Period>
            bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
            {
                /**
                 * TODO:
                 * throw system_error operation_not_permitted if mtx_ == nullptr
                 * throw system_error resource_deadlock_would_occur if owns_ == true
                 */

                owns_ = mtx_->try_lock_shared_for(rel_time);

                return owns_;
            }

            template<class Clock, class Duration>
            bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
            {
                /**
                 * TODO:
                 * throw system_error operation_not_permitted if mtx_ == nullptr
                 * throw system_error resource_deadlock_would_occur if owns_ == true
                 */

                owns_ = mtx_->try_lock_shared_until(abs_time);

                return owns_;
            }

            void unlock()
            {
                /**
                 * TODO:
                 * throw system_error operation_not_permitted if owns_ == false
                 */

                mtx_->unlock_shared();
            }

            /**
             * 30.4.2.2.3, modifiers:
             */

            void swap(shared_lock& other) noexcept
            {
                std::swap(mtx_, other.mtx_);
                std::swap(owns_, other.owns_);
            }

            mutex_type* release() noexcept
            {
                auto ret = mtx_;
                mtx_ = nullptr;
                owns_ = false;

                return ret;
            }

            /**
             * 30.4.2.2.4, observers:
             */

            bool owns_lock() const noexcept
            {
                return owns_;
            }

            explicit operator bool() const noexcept
            {
                return owns_;
            }

            mutex_type* mutex() const noexcept
            {
                return mtx_;
            }

        private:
            mutex_type* mtx_;
            bool owns_;
    };

    template<class Mutex>
    void swap(shared_lock<Mutex>& lhs, shared_lock<Mutex>& rhs) noexcept
    {
        lhs.swap(rhs);
    }
}

#endif

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub