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_spin_mutex_H
18 #define __TBB_spin_mutex_H
19
20 #include "detail/_namespace_injection.h"
21 #include "detail/_mutex_common.h"
22
23 #include "profiling.h"
24
25 #include "detail/_assert.h"
26 #include "detail/_utils.h"
27 #include "detail/_scoped_lock.h"
28
29 #include <atomic>
30
31 namespace tbb {
32 namespace detail {
33 namespace d1 {
34
35 #if __TBB_TSX_INTRINSICS_PRESENT
36 class rtm_mutex;
37 #endif
38
39 /** A spin_mutex is a low-level synchronization primitive.
40 While locked, it causes the waiting threads to spin in a loop until the lock is released.
41 It should be used only for locking short critical sections
42 (typically less than 20 instructions) when fairness is not an issue.
43 If zero-initialized, the mutex is considered unheld.
44 @ingroup synchronization */
45 class spin_mutex {
46 public:
47 //! Constructors
spin_mutex()48 spin_mutex() noexcept : m_flag(false) {
49 create_itt_sync(this, "tbb::spin_mutex", "");
50 };
51
52 //! Destructor
53 ~spin_mutex() = default;
54
55 //! No Copy
56 spin_mutex(const spin_mutex&) = delete;
57 spin_mutex& operator=(const spin_mutex&) = delete;
58
59 using scoped_lock = unique_scoped_lock<spin_mutex>;
60
61 //! Mutex traits
62 static constexpr bool is_rw_mutex = false;
63 static constexpr bool is_recursive_mutex = false;
64 static constexpr bool is_fair_mutex = false;
65
66 //! Acquire lock
67 /** Spin if the lock is taken */
lock()68 void lock() {
69 atomic_backoff backoff;
70 call_itt_notify(prepare, this);
71 while (m_flag.exchange(true)) backoff.pause();
72 call_itt_notify(acquired, this);
73 }
74
75 //! Try acquiring lock (non-blocking)
76 /** Return true if lock acquired; false otherwise. */
try_lock()77 bool try_lock() {
78 bool result = !m_flag.exchange(true);
79 if (result) {
80 call_itt_notify(acquired, this);
81 }
82 return result;
83 }
84
85 //! Release lock
unlock()86 void unlock() {
87 call_itt_notify(releasing, this);
88 m_flag.store(false, std::memory_order_release);
89 }
90
91 protected:
92 std::atomic<bool> m_flag;
93 }; // class spin_mutex
94
95 #if TBB_USE_PROFILING_TOOLS
set_name(spin_mutex & obj,const char * name)96 inline void set_name(spin_mutex& obj, const char* name) {
97 itt_set_sync_name(&obj, name);
98 }
99 #if (_WIN32||_WIN64)
set_name(spin_mutex & obj,const wchar_t * name)100 inline void set_name(spin_mutex& obj, const wchar_t* name) {
101 itt_set_sync_name(&obj, name);
102 }
103 #endif //WIN
104 #else
set_name(spin_mutex &,const char *)105 inline void set_name(spin_mutex&, const char*) {}
106 #if (_WIN32||_WIN64)
set_name(spin_mutex &,const wchar_t *)107 inline void set_name(spin_mutex&, const wchar_t*) {}
108 #endif // WIN
109 #endif
110 } // namespace d1
111 } // namespace detail
112
113 inline namespace v1 {
114 using detail::d1::spin_mutex;
115 } // namespace v1
116 namespace profiling {
117 using detail::d1::set_name;
118 }
119 } // namespace tbb
120
121 #include "detail/_rtm_mutex.h"
122
123 namespace tbb {
124 inline namespace v1 {
125 #if __TBB_TSX_INTRINSICS_PRESENT
126 using speculative_spin_mutex = detail::d1::rtm_mutex;
127 #else
128 using speculative_spin_mutex = detail::d1::spin_mutex;
129 #endif
130 }
131 }
132
133 #endif /* __TBB_spin_mutex_H */
134
135