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
33namespace tbb {
34
35 namespace internal {
36class 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;
43public:
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
125typedef 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