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_CRITICAL_SECTION_H_ |
18 | #define _TBB_CRITICAL_SECTION_H_ |
19 | |
20 | #if _WIN32||_WIN64 |
21 | #include "machine/windows_api.h" |
22 | #else |
23 | #include <pthread.h> |
24 | #include <errno.h> |
25 | #endif // _WIN32||WIN64 |
26 | |
27 | #include "tbb_stddef.h" |
28 | #include "tbb_thread.h" |
29 | #include "tbb_exception.h" |
30 | |
31 | #include "tbb_profiling.h" |
32 | |
33 | namespace tbb { |
34 | |
35 | namespace internal { |
36 | class critical_section_v4 : internal::no_copy { |
37 | #if _WIN32||_WIN64 |
38 | CRITICAL_SECTION my_impl; |
39 | #else |
40 | pthread_mutex_t my_impl; |
41 | #endif |
42 | tbb_thread::id my_tid; |
43 | public: |
44 | |
45 | void __TBB_EXPORTED_METHOD internal_construct(); |
46 | |
47 | critical_section_v4() { |
48 | #if _WIN32||_WIN64 |
49 | InitializeCriticalSectionEx( &my_impl, 4000, 0 ); |
50 | #else |
51 | pthread_mutex_init(&my_impl, NULL); |
52 | #endif |
53 | internal_construct(); |
54 | } |
55 | |
56 | ~critical_section_v4() { |
57 | __TBB_ASSERT(my_tid == tbb_thread::id(), "Destroying a still-held critical section" ); |
58 | #if _WIN32||_WIN64 |
59 | DeleteCriticalSection(&my_impl); |
60 | #else |
61 | pthread_mutex_destroy(&my_impl); |
62 | #endif |
63 | } |
64 | |
65 | class scoped_lock : internal::no_copy { |
66 | private: |
67 | critical_section_v4 &my_crit; |
68 | public: |
69 | scoped_lock( critical_section_v4& lock_me) :my_crit(lock_me) { |
70 | my_crit.lock(); |
71 | } |
72 | |
73 | ~scoped_lock() { |
74 | my_crit.unlock(); |
75 | } |
76 | }; |
77 | |
78 | void lock() { |
79 | tbb_thread::id local_tid = this_tbb_thread::get_id(); |
80 | if(local_tid == my_tid) throw_exception( eid_improper_lock ); |
81 | #if _WIN32||_WIN64 |
82 | EnterCriticalSection( &my_impl ); |
83 | #else |
84 | int rval = pthread_mutex_lock(&my_impl); |
85 | __TBB_ASSERT_EX(!rval, "critical_section::lock: pthread_mutex_lock failed" ); |
86 | #endif |
87 | __TBB_ASSERT(my_tid == tbb_thread::id(), NULL); |
88 | my_tid = local_tid; |
89 | } |
90 | |
91 | bool try_lock() { |
92 | bool gotlock; |
93 | tbb_thread::id local_tid = this_tbb_thread::get_id(); |
94 | if(local_tid == my_tid) return false; |
95 | #if _WIN32||_WIN64 |
96 | gotlock = TryEnterCriticalSection( &my_impl ) != 0; |
97 | #else |
98 | int rval = pthread_mutex_trylock(&my_impl); |
99 | // valid returns are 0 (locked) and [EBUSY] |
100 | __TBB_ASSERT(rval == 0 || rval == EBUSY, "critical_section::trylock: pthread_mutex_trylock failed" ); |
101 | gotlock = rval == 0; |
102 | #endif |
103 | if(gotlock) { |
104 | my_tid = local_tid; |
105 | } |
106 | return gotlock; |
107 | } |
108 | |
109 | void unlock() { |
110 | __TBB_ASSERT(this_tbb_thread::get_id() == my_tid, "thread unlocking critical_section is not thread that locked it" ); |
111 | my_tid = tbb_thread::id(); |
112 | #if _WIN32||_WIN64 |
113 | LeaveCriticalSection( &my_impl ); |
114 | #else |
115 | int rval = pthread_mutex_unlock(&my_impl); |
116 | __TBB_ASSERT_EX(!rval, "critical_section::unlock: pthread_mutex_unlock failed" ); |
117 | #endif |
118 | } |
119 | |
120 | static const bool is_rw_mutex = false; |
121 | static const bool is_recursive_mutex = false; |
122 | static const bool is_fair_mutex = true; |
123 | }; // critical_section_v4 |
124 | } // namespace internal |
125 | typedef internal::critical_section_v4 critical_section; |
126 | |
127 | __TBB_DEFINE_PROFILING_SET_NAME(critical_section) |
128 | } // namespace tbb |
129 | #endif // _TBB_CRITICAL_SECTION_H_ |
130 | |