1 #ifndef THR_MUTEX_INCLUDED
2 #define THR_MUTEX_INCLUDED
3
4 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License, version 2.0, for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
25
26 /**
27 MySQL mutex implementation.
28
29 There are three "layers":
30 1) native_mutex_*()
31 Functions that map directly down to OS primitives.
32 Windows - CriticalSection
33 Other OSes - pthread
34 2) my_mutex_*()
35 Functions that implement SAFE_MUTEX (default for debug),
36 Otherwise native_mutex_*() is used.
37 3) mysql_mutex_*()
38 Functions that include Performance Schema instrumentation.
39 See include/mysql/psi/mysql_thread.h
40 */
41
42 #include <my_global.h>
43 #include "my_thread.h"
44
45 C_MODE_START
46
47 #ifdef _WIN32
48 typedef CRITICAL_SECTION native_mutex_t;
49 typedef int native_mutexattr_t;
50 #else
51 typedef pthread_mutex_t native_mutex_t;
52 typedef pthread_mutexattr_t native_mutexattr_t;
53 #endif
54
55 /* Define mutex types, see my_thr_init.c */
56 #define MY_MUTEX_INIT_SLOW NULL
57
58 /* Can be set in /usr/include/pthread.h */
59 #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
60 extern native_mutexattr_t my_fast_mutexattr;
61 #define MY_MUTEX_INIT_FAST &my_fast_mutexattr
62 #else
63 #define MY_MUTEX_INIT_FAST NULL
64 #endif
65
66 /* Can be set in /usr/include/pthread.h */
67 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
68 extern native_mutexattr_t my_errorcheck_mutexattr;
69 #define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr
70 #else
71 #define MY_MUTEX_INIT_ERRCHK NULL
72 #endif
73
native_mutex_init(native_mutex_t * mutex,const native_mutexattr_t * attr)74 static inline int native_mutex_init(native_mutex_t *mutex,
75 const native_mutexattr_t *attr)
76 {
77 #ifdef _WIN32
78 InitializeCriticalSection(mutex);
79 return 0;
80 #else
81 return pthread_mutex_init(mutex, attr);
82 #endif
83 }
84
native_mutex_lock(native_mutex_t * mutex)85 static inline int native_mutex_lock(native_mutex_t *mutex)
86 {
87 #ifdef _WIN32
88 EnterCriticalSection(mutex);
89 return 0;
90 #else
91 return pthread_mutex_lock(mutex);
92 #endif
93 }
94
native_mutex_trylock(native_mutex_t * mutex)95 static inline int native_mutex_trylock(native_mutex_t *mutex)
96 {
97 #ifdef _WIN32
98 if (TryEnterCriticalSection(mutex))
99 {
100 /* Don't allow recursive lock */
101 if (mutex->RecursionCount > 1){
102 LeaveCriticalSection(mutex);
103 return EBUSY;
104 }
105 return 0;
106 }
107 return EBUSY;
108 #else
109 return pthread_mutex_trylock(mutex);
110 #endif
111 }
112
native_mutex_unlock(native_mutex_t * mutex)113 static inline int native_mutex_unlock(native_mutex_t *mutex)
114 {
115 #ifdef _WIN32
116 LeaveCriticalSection(mutex);
117 return 0;
118 #else
119 return pthread_mutex_unlock(mutex);
120 #endif
121 }
122
native_mutex_destroy(native_mutex_t * mutex)123 static inline int native_mutex_destroy(native_mutex_t *mutex)
124 {
125 #ifdef _WIN32
126 DeleteCriticalSection(mutex);
127 return 0;
128 #else
129 return pthread_mutex_destroy(mutex);
130 #endif
131 }
132
133
134 #ifdef SAFE_MUTEX
135 /* safe_mutex adds checking to mutex for easier debugging */
136 typedef struct st_safe_mutex_t
137 {
138 native_mutex_t global, mutex;
139 const char *file;
140 uint line, count;
141 my_thread_t thread;
142 } my_mutex_t;
143
144 void safe_mutex_global_init();
145 int safe_mutex_init(my_mutex_t *mp, const native_mutexattr_t *attr,
146 const char *file, uint line);
147 int safe_mutex_lock(my_mutex_t *mp, my_bool try_lock, const char *file, uint line);
148 int safe_mutex_unlock(my_mutex_t *mp, const char *file, uint line);
149 int safe_mutex_destroy(my_mutex_t *mp, const char *file, uint line);
150
safe_mutex_assert_owner(const my_mutex_t * mp)151 static inline void safe_mutex_assert_owner(const my_mutex_t *mp)
152 {
153 assert(mp->count > 0 &&
154 my_thread_equal(my_thread_self(), mp->thread));
155 }
156
safe_mutex_assert_not_owner(const my_mutex_t * mp)157 static inline void safe_mutex_assert_not_owner(const my_mutex_t *mp)
158 {
159 assert(!mp->count ||
160 !my_thread_equal(my_thread_self(), mp->thread));
161 }
162
163 #else
164 typedef native_mutex_t my_mutex_t;
165 #endif
166
my_mutex_init(my_mutex_t * mp,const native_mutexattr_t * attr,const char * file,uint line)167 static inline int my_mutex_init(my_mutex_t *mp, const native_mutexattr_t *attr
168 #ifdef SAFE_MUTEX
169 , const char *file, uint line
170 #endif
171 )
172 {
173 #ifdef SAFE_MUTEX
174 return safe_mutex_init(mp, attr, file, line);
175 #else
176 return native_mutex_init(mp, attr);
177 #endif
178 }
179
my_mutex_lock(my_mutex_t * mp,const char * file,uint line)180 static inline int my_mutex_lock(my_mutex_t *mp
181 #ifdef SAFE_MUTEX
182 , const char *file, uint line
183 #endif
184 )
185 {
186 #ifdef SAFE_MUTEX
187 return safe_mutex_lock(mp, FALSE, file, line);
188 #else
189 return native_mutex_lock(mp);
190 #endif
191 }
192
my_mutex_trylock(my_mutex_t * mp,const char * file,uint line)193 static inline int my_mutex_trylock(my_mutex_t *mp
194 #ifdef SAFE_MUTEX
195 , const char *file, uint line
196 #endif
197 )
198 {
199 #ifdef SAFE_MUTEX
200 return safe_mutex_lock(mp, TRUE, file, line);
201 #else
202 return native_mutex_trylock(mp);
203 #endif
204 }
205
my_mutex_unlock(my_mutex_t * mp,const char * file,uint line)206 static inline int my_mutex_unlock(my_mutex_t *mp
207 #ifdef SAFE_MUTEX
208 , const char *file, uint line
209 #endif
210 )
211 {
212 #ifdef SAFE_MUTEX
213 return safe_mutex_unlock(mp, file, line);
214 #else
215 return native_mutex_unlock(mp);
216 #endif
217 }
218
my_mutex_destroy(my_mutex_t * mp,const char * file,uint line)219 static inline int my_mutex_destroy(my_mutex_t *mp
220 #ifdef SAFE_MUTEX
221 , const char *file, uint line
222 #endif
223 )
224 {
225 #ifdef SAFE_MUTEX
226 return safe_mutex_destroy(mp, file, line);
227 #else
228 return native_mutex_destroy(mp);
229 #endif
230 }
231
232 C_MODE_END
233
234 #endif /* THR_MUTEX_INCLUDED */
235