1/*
2 Copyright (c) 2005-2019 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_mutex_H
18#define __TBB_mutex_H
19
20#if _WIN32||_WIN64
21#include "machine/windows_api.h"
22#else
23#include <pthread.h>
24#endif /* _WIN32||_WIN64 */
25
26#include <new>
27#include "aligned_space.h"
28#include "tbb_stddef.h"
29#include "tbb_profiling.h"
30
31namespace tbb {
32
33//! Wrapper around the platform's native lock.
34/** @ingroup synchronization */
35class mutex : internal::mutex_copy_deprecated_and_disabled {
36public:
37 //! Construct unacquired mutex.
38 mutex() {
39#if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS
40 internal_construct();
41#else
42 #if _WIN32||_WIN64
43 InitializeCriticalSectionEx(&impl, 4000, 0);
44 #else
45 int error_code = pthread_mutex_init(&impl,NULL);
46 if( error_code )
47 tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_init failed");
48 #endif /* _WIN32||_WIN64*/
49#endif /* TBB_USE_ASSERT */
50 };
51
52 ~mutex() {
53#if TBB_USE_ASSERT
54 internal_destroy();
55#else
56 #if _WIN32||_WIN64
57 DeleteCriticalSection(&impl);
58 #else
59 pthread_mutex_destroy(&impl);
60
61 #endif /* _WIN32||_WIN64 */
62#endif /* TBB_USE_ASSERT */
63 };
64
65 class scoped_lock;
66 friend class scoped_lock;
67
68 //! The scoped locking pattern
69 /** It helps to avoid the common problem of forgetting to release lock.
70 It also nicely provides the "node" for queuing locks. */
71 class scoped_lock : internal::no_copy {
72 public:
73 //! Construct lock that has not acquired a mutex.
74 scoped_lock() : my_mutex(NULL) {};
75
76 //! Acquire lock on given mutex.
77 scoped_lock( mutex& mutex ) {
78 acquire( mutex );
79 }
80
81 //! Release lock (if lock is held).
82 ~scoped_lock() {
83 if( my_mutex )
84 release();
85 }
86
87 //! Acquire lock on given mutex.
88 void acquire( mutex& mutex ) {
89#if TBB_USE_ASSERT
90 internal_acquire(mutex);
91#else
92 mutex.lock();
93 my_mutex = &mutex;
94#endif /* TBB_USE_ASSERT */
95 }
96
97 //! Try acquire lock on given mutex.
98 bool try_acquire( mutex& mutex ) {
99#if TBB_USE_ASSERT
100 return internal_try_acquire (mutex);
101#else
102 bool result = mutex.try_lock();
103 if( result )
104 my_mutex = &mutex;
105 return result;
106#endif /* TBB_USE_ASSERT */
107 }
108
109 //! Release lock
110 void release() {
111#if TBB_USE_ASSERT
112 internal_release ();
113#else
114 my_mutex->unlock();
115 my_mutex = NULL;
116#endif /* TBB_USE_ASSERT */
117 }
118
119 private:
120 //! The pointer to the current mutex to work
121 mutex* my_mutex;
122
123 //! All checks from acquire using mutex.state were moved here
124 void __TBB_EXPORTED_METHOD internal_acquire( mutex& m );
125
126 //! All checks from try_acquire using mutex.state were moved here
127 bool __TBB_EXPORTED_METHOD internal_try_acquire( mutex& m );
128
129 //! All checks from release using mutex.state were moved here
130 void __TBB_EXPORTED_METHOD internal_release();
131
132 friend class mutex;
133 };
134
135 // Mutex traits
136 static const bool is_rw_mutex = false;
137 static const bool is_recursive_mutex = false;
138 static const bool is_fair_mutex = false;
139
140 // ISO C++0x compatibility methods
141
142 //! Acquire lock
143 void lock() {
144#if TBB_USE_ASSERT
145 aligned_space<scoped_lock> tmp;
146 new(tmp.begin()) scoped_lock(*this);
147#else
148 #if _WIN32||_WIN64
149 EnterCriticalSection(&impl);
150 #else
151 int error_code = pthread_mutex_lock(&impl);
152 if( error_code )
153 tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_lock failed");
154 #endif /* _WIN32||_WIN64 */
155#endif /* TBB_USE_ASSERT */
156 }
157
158 //! Try acquiring lock (non-blocking)
159 /** Return true if lock acquired; false otherwise. */
160 bool try_lock() {
161#if TBB_USE_ASSERT
162 aligned_space<scoped_lock> tmp;
163 scoped_lock& s = *tmp.begin();
164 s.my_mutex = NULL;
165 return s.internal_try_acquire(*this);
166#else
167 #if _WIN32||_WIN64
168 return TryEnterCriticalSection(&impl)!=0;
169 #else
170 return pthread_mutex_trylock(&impl)==0;
171 #endif /* _WIN32||_WIN64 */
172#endif /* TBB_USE_ASSERT */
173 }
174
175 //! Release lock
176 void unlock() {
177#if TBB_USE_ASSERT
178 aligned_space<scoped_lock> tmp;
179 scoped_lock& s = *tmp.begin();
180 s.my_mutex = this;
181 s.internal_release();
182#else
183 #if _WIN32||_WIN64
184 LeaveCriticalSection(&impl);
185 #else
186 pthread_mutex_unlock(&impl);
187 #endif /* _WIN32||_WIN64 */
188#endif /* TBB_USE_ASSERT */
189 }
190
191 //! Return native_handle
192 #if _WIN32||_WIN64
193 typedef LPCRITICAL_SECTION native_handle_type;
194 #else
195 typedef pthread_mutex_t* native_handle_type;
196 #endif
197 native_handle_type native_handle() { return (native_handle_type) &impl; }
198
199 enum state_t {
200 INITIALIZED=0x1234,
201 DESTROYED=0x789A,
202 HELD=0x56CD
203 };
204private:
205#if _WIN32||_WIN64
206 CRITICAL_SECTION impl;
207 enum state_t state;
208#else
209 pthread_mutex_t impl;
210#endif /* _WIN32||_WIN64 */
211
212 //! All checks from mutex constructor using mutex.state were moved here
213 void __TBB_EXPORTED_METHOD internal_construct();
214
215 //! All checks from mutex destructor using mutex.state were moved here
216 void __TBB_EXPORTED_METHOD internal_destroy();
217
218#if _WIN32||_WIN64
219public:
220 //! Set the internal state
221 void set_state( state_t to ) { state = to; }
222#endif
223};
224
225__TBB_DEFINE_PROFILING_SET_NAME(mutex)
226
227} // namespace tbb
228
229#endif /* __TBB_mutex_H */
230