xref: /oneTBB/include/oneapi/tbb/detail/_rtm_mutex.h (revision 8827ea7d)
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 */
alignas(max_nfs_size)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     TBB_EXPORT void __TBB_EXPORTED_FUNC acquire(d1::rtm_mutex&, d1::rtm_mutex::scoped_lock&, bool only_speculate = false);
112     //! Internal try_acquire lock.
113     TBB_EXPORT bool __TBB_EXPORTED_FUNC try_acquire(d1::rtm_mutex&, d1::rtm_mutex::scoped_lock&);
114     //! Internal release lock.
115     TBB_EXPORT void __TBB_EXPORTED_FUNC release(d1::rtm_mutex::scoped_lock&);
116 } // namespace r1
117 
118 namespace d1 {
119 //! Acquire lock on given mutex.
acquire(rtm_mutex & m)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.
try_acquire(rtm_mutex & m)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
release()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
set_name(rtm_mutex & obj,const char * name)143 inline void set_name(rtm_mutex& obj, const char* name) {
144     itt_set_sync_name(&obj, name);
145 }
146 #if (_WIN32||_WIN64)
set_name(rtm_mutex & obj,const wchar_t * name)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
set_name(rtm_mutex &,const char *)152 inline void set_name(rtm_mutex&, const char*) {}
153 #if (_WIN32||_WIN64)
set_name(rtm_mutex &,const wchar_t *)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