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 | |
31 | namespace tbb { |
32 | |
33 | //! Wrapper around the platform's native lock. |
34 | /** @ingroup synchronization */ |
35 | class mutex : internal::mutex_copy_deprecated_and_disabled { |
36 | public: |
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 | }; |
204 | private: |
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 |
219 | public: |
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 | |