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