1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB__rtm_mutex_impl_H 18 #define __TBB__rtm_mutex_impl_H 19 20 #include "_assert.h" 21 #include "_utils.h" 22 #include "../spin_mutex.h" 23 24 #include "../profiling.h" 25 26 namespace tbb { 27 namespace detail { 28 namespace r1 { 29 struct rtm_mutex_impl; 30 } 31 namespace d1 { 32 33 #if _MSC_VER && !defined(__INTEL_COMPILER) 34 // Suppress warning: structure was padded due to alignment specifier 35 #pragma warning (push) 36 #pragma warning (disable: 4324) 37 #endif 38 39 /** A rtm_mutex is an speculation-enabled spin mutex. 40 It should be used for locking short critical sections where the lock is 41 contended but the data it protects are not. If zero-initialized, the 42 mutex is considered unheld. 43 @ingroup synchronization */ 44 class alignas(max_nfs_size) rtm_mutex : private spin_mutex { 45 private: 46 enum class rtm_state { 47 rtm_none, 48 rtm_transacting, 49 rtm_real 50 }; 51 public: 52 //! Constructors 53 rtm_mutex() noexcept { 54 create_itt_sync(this, "tbb::speculative_spin_mutex", ""); 55 } 56 57 //! Destructor 58 ~rtm_mutex() = default; 59 60 //! Represents acquisition of a mutex. 61 class scoped_lock { 62 public: 63 friend class rtm_mutex; 64 //! Construct lock that has not acquired a mutex. 65 /** Equivalent to zero-initialization of *this. */ 66 constexpr scoped_lock() : m_mutex(nullptr), m_transaction_state(rtm_state::rtm_none) {} 67 68 //! Acquire lock on given mutex. 69 scoped_lock(rtm_mutex& m) : m_mutex(nullptr), m_transaction_state(rtm_state::rtm_none) { 70 acquire(m); 71 } 72 73 //! Release lock (if lock is held). 74 ~scoped_lock() { 75 if(m_transaction_state != rtm_state::rtm_none) { 76 release(); 77 } 78 } 79 80 //! No Copy 81 scoped_lock(const scoped_lock&) = delete; 82 scoped_lock& operator=(const scoped_lock&) = delete; 83 84 //! Acquire lock on given mutex. 85 void acquire(rtm_mutex& m); 86 87 //! Try acquire lock on given mutex. 88 bool try_acquire(rtm_mutex& m); 89 90 //! Release lock 91 void release(); 92 93 private: 94 rtm_mutex* m_mutex; 95 rtm_state m_transaction_state; 96 friend r1::rtm_mutex_impl; 97 }; 98 99 //! Mutex traits 100 static constexpr bool is_rw_mutex = false; 101 static constexpr bool is_recursive_mutex = false; 102 static constexpr bool is_fair_mutex = false; 103 private: 104 friend r1::rtm_mutex_impl; 105 }; // end of rtm_mutex 106 } // namespace d1 107 108 namespace r1 { 109 //! Internal acquire lock. 110 // only_speculate == true if we're doing a try_lock, else false. 111 void __TBB_EXPORTED_FUNC acquire(d1::rtm_mutex&, d1::rtm_mutex::scoped_lock&, bool only_speculate = false); 112 //! Internal try_acquire lock. 113 bool __TBB_EXPORTED_FUNC try_acquire(d1::rtm_mutex&, d1::rtm_mutex::scoped_lock&); 114 //! Internal release lock. 115 void __TBB_EXPORTED_FUNC release(d1::rtm_mutex::scoped_lock&); 116 } // namespace r1 117 118 namespace d1 { 119 //! Acquire lock on given mutex. 120 inline void rtm_mutex::scoped_lock::acquire(rtm_mutex& m) { 121 __TBB_ASSERT(!m_mutex, "lock is already acquired"); 122 r1::acquire(m, *this); 123 } 124 125 //! Try acquire lock on given mutex. 126 inline bool rtm_mutex::scoped_lock::try_acquire(rtm_mutex& m) { 127 __TBB_ASSERT(!m_mutex, "lock is already acquired"); 128 return r1::try_acquire(m, *this); 129 } 130 131 //! Release lock 132 inline void rtm_mutex::scoped_lock::release() { 133 __TBB_ASSERT(m_mutex, "lock is not acquired"); 134 __TBB_ASSERT(m_transaction_state != rtm_state::rtm_none, "lock is not acquired"); 135 return r1::release(*this); 136 } 137 138 #if _MSC_VER && !defined(__INTEL_COMPILER) 139 #pragma warning (pop) // 4324 warning 140 #endif 141 142 #if TBB_USE_PROFILING_TOOLS 143 inline void set_name(rtm_mutex& obj, const char* name) { 144 itt_set_sync_name(&obj, name); 145 } 146 #if (_WIN32||_WIN64) && !__MINGW32__ 147 inline void set_name(rtm_mutex& obj, const wchar_t* name) { 148 itt_set_sync_name(&obj, name); 149 } 150 #endif // WIN 151 #else 152 inline void set_name(rtm_mutex&, const char*) {} 153 #if (_WIN32||_WIN64) && !__MINGW32__ 154 inline void set_name(rtm_mutex&, const wchar_t*) {} 155 #endif // WIN 156 #endif 157 158 } // namespace d1 159 } // namespace detail 160 } // namespace tbb 161 162 #endif /* __TBB__rtm_mutex_impl_H */ 163