1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_SOFT_MUTEX_HPP 11 #define BOOST_BEAST_WEBSOCKET_DETAIL_SOFT_MUTEX_HPP 12 13 #include <boost/assert.hpp> 14 15 namespace boost { 16 namespace beast { 17 namespace websocket { 18 namespace detail { 19 20 // used to order reads, writes in websocket streams 21 22 class soft_mutex 23 { 24 int id_ = 0; 25 26 public: 27 soft_mutex() = default; 28 soft_mutex(soft_mutex const&) = delete; 29 soft_mutex& operator=(soft_mutex const&) = delete; 30 soft_mutex(soft_mutex && other)31 soft_mutex(soft_mutex&& other) noexcept 32 : id_(boost::exchange(other.id_, 0)) 33 { 34 } 35 operator =(soft_mutex && other)36 soft_mutex& operator=(soft_mutex&& other) noexcept 37 { 38 id_ = other.id_; 39 other.id_ = 0; 40 return *this; 41 } 42 43 // VFALCO I'm not too happy that this function is needed 44 void reset()45 reset() 46 { 47 id_ = 0; 48 } 49 50 bool is_locked() const51 is_locked() const noexcept 52 { 53 return id_ != 0; 54 } 55 56 template<class T> 57 bool is_locked(T const *) const58 is_locked(T const*) const noexcept 59 { 60 return id_ == T::id; 61 } 62 63 template<class T> 64 void lock(T const *)65 lock(T const*) 66 { 67 BOOST_ASSERT(id_ == 0); 68 id_ = T::id; 69 } 70 71 template<class T> 72 void unlock(T const *)73 unlock(T const*) 74 { 75 BOOST_ASSERT(id_ == T::id); 76 id_ = 0; 77 } 78 79 template<class T> 80 bool try_lock(T const *)81 try_lock(T const*) 82 { 83 // If this assert goes off it means you are attempting to 84 // simultaneously initiate more than one of same asynchronous 85 // operation, which is not allowed. For example, you must wait 86 // for an async_read to complete before performing another 87 // async_read. 88 // 89 BOOST_ASSERT(id_ != T::id); 90 if(id_ != 0) 91 return false; 92 id_ = T::id; 93 return true; 94 } 95 96 template<class T> 97 bool try_unlock(T const *)98 try_unlock(T const*) noexcept 99 { 100 if(id_ != T::id) 101 return false; 102 id_ = 0; 103 return true; 104 } 105 }; 106 107 } // detail 108 } // websocket 109 } // beast 110 } // boost 111 112 #endif 113