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