/src/server/include/my_pthread.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. |
2 | | Copyright (c) 2009, 2020, MariaDB Corporation. |
3 | | |
4 | | This program is free software; you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation; version 2 of the License. |
7 | | |
8 | | This program is distributed in the hope that it will be useful, |
9 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | GNU General Public License for more details. |
12 | | |
13 | | You should have received a copy of the GNU General Public License |
14 | | along with this program; if not, write to the Free Software |
15 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ |
16 | | |
17 | | /* Defines to make different thread packages compatible */ |
18 | | |
19 | | #ifndef _my_pthread_h |
20 | | #define _my_pthread_h |
21 | | |
22 | | #ifndef ETIME |
23 | | #define ETIME ETIMEDOUT /* For FreeBSD */ |
24 | | #endif |
25 | | |
26 | | #ifdef __cplusplus |
27 | | #define EXTERNC extern "C" |
28 | | extern "C" { |
29 | | #else |
30 | | #define EXTERNC |
31 | | #endif /* __cplusplus */ |
32 | | |
33 | | #if defined(_WIN32) |
34 | | typedef CRITICAL_SECTION pthread_mutex_t; |
35 | | typedef DWORD pthread_t; |
36 | | typedef struct thread_attr { |
37 | | DWORD dwStackSize ; |
38 | | DWORD dwCreatingFlag ; |
39 | | } pthread_attr_t ; |
40 | | |
41 | | typedef struct { int dummy; } pthread_condattr_t; |
42 | | |
43 | | /* Implementation of posix conditions */ |
44 | | |
45 | | typedef struct st_pthread_link { |
46 | | DWORD thread_id; |
47 | | struct st_pthread_link *next; |
48 | | } pthread_link; |
49 | | |
50 | | /** |
51 | | Implementation of Windows condition variables. |
52 | | We use native conditions on Vista and later, and fallback to own |
53 | | implementation on earlier OS version. |
54 | | */ |
55 | | typedef CONDITION_VARIABLE pthread_cond_t; |
56 | | |
57 | | |
58 | | typedef int pthread_mutexattr_t; |
59 | | #define pthread_self() GetCurrentThreadId() |
60 | | #define pthread_handler_t EXTERNC void * __cdecl |
61 | | typedef void * (__cdecl *pthread_handler)(void *); |
62 | | |
63 | | typedef INIT_ONCE my_pthread_once_t; |
64 | | #define MY_PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT; |
65 | | |
66 | | #if !STRUCT_TIMESPEC_HAS_TV_SEC || !STRUCT_TIMESPEC_HAS_TV_NSEC |
67 | | struct timespec { |
68 | | time_t tv_sec; |
69 | | long tv_nsec; |
70 | | }; |
71 | | #endif |
72 | | |
73 | | int win_pthread_mutex_trylock(pthread_mutex_t *mutex); |
74 | | int pthread_create(pthread_t *, const pthread_attr_t *, pthread_handler, void *); |
75 | | int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); |
76 | | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); |
77 | | int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, |
78 | | const struct timespec *abstime); |
79 | | int pthread_cond_signal(pthread_cond_t *cond); |
80 | | int pthread_cond_broadcast(pthread_cond_t *cond); |
81 | | int pthread_cond_destroy(pthread_cond_t *cond); |
82 | | int pthread_attr_init(pthread_attr_t *connect_att); |
83 | | int pthread_attr_setstacksize(pthread_attr_t *connect_att,size_t stack); |
84 | | int pthread_attr_destroy(pthread_attr_t *connect_att); |
85 | | int my_pthread_once(my_pthread_once_t *once_control,void (*init_routine)(void)); |
86 | | |
87 | | static inline struct tm *localtime_r(const time_t *timep, struct tm *tmp) |
88 | | { |
89 | | localtime_s(tmp, timep); |
90 | | return tmp; |
91 | | } |
92 | | |
93 | | static inline struct tm *gmtime_r(const time_t *clock, struct tm *res) |
94 | | { |
95 | | gmtime_s(res, clock); |
96 | | return res; |
97 | | } |
98 | | |
99 | | void pthread_exit(void *a); |
100 | | int pthread_join(pthread_t thread, void **value_ptr); |
101 | | int pthread_cancel(pthread_t thread); |
102 | | |
103 | | #ifndef ETIMEDOUT |
104 | | #define ETIMEDOUT 145 /* Win32 doesn't have this */ |
105 | | #endif |
106 | | |
107 | | #define HAVE_LOCALTIME_R 1 |
108 | | #define _REENTRANT 1 |
109 | | #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 |
110 | | |
111 | | #undef SAFE_MUTEX /* This will cause conflicts */ |
112 | | #define pthread_key(T,V) DWORD V |
113 | | #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) |
114 | | #define pthread_key_delete(A) TlsFree(A) |
115 | | #define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) |
116 | | #define pthread_setspecific(A,B) (!TlsSetValue((A),(LPVOID)(B))) |
117 | | #define pthread_getspecific(A) (TlsGetValue(A)) |
118 | | #define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) |
119 | | #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) |
120 | | |
121 | | #define pthread_equal(A,B) ((A) == (B)) |
122 | | #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) |
123 | | #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) |
124 | | #define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A)) |
125 | | #define pthread_mutex_unlock(A) (LeaveCriticalSection(A), 0) |
126 | | #define pthread_mutex_destroy(A) (DeleteCriticalSection(A), 0) |
127 | | #define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) |
128 | | |
129 | | |
130 | | /* Dummy defines for easier code */ |
131 | | #define pthread_attr_setdetachstate(A,B) pthread_dummy(0) |
132 | | #define pthread_attr_setscope(A,B) |
133 | | #define pthread_detach_this_thread() |
134 | | #define pthread_condattr_init(A) |
135 | | #define pthread_condattr_destroy(A) |
136 | | #define pthread_yield() SwitchToThread() |
137 | | #define my_sigset(A,B) signal(A,B) |
138 | | |
139 | | #else /* Normal threads */ |
140 | | |
141 | | #ifdef HAVE_rts_threads |
142 | | #define sigwait org_sigwait |
143 | | #include <signal.h> |
144 | | #undef sigwait |
145 | | #endif |
146 | | #include <pthread.h> |
147 | | #ifndef _REENTRANT |
148 | | #define _REENTRANT |
149 | | #endif |
150 | | #ifdef HAVE_SCHED_H |
151 | | #include <sched.h> |
152 | | #endif |
153 | | #ifdef HAVE_SYNCH_H |
154 | | #include <synch.h> |
155 | | #endif |
156 | | |
157 | | #define pthread_key(T,V) pthread_key_t V |
158 | | #define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) |
159 | 0 | #define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) |
160 | | #define pthread_detach_this_thread() |
161 | | #define pthread_handler_t EXTERNC void * |
162 | | typedef void *(* pthread_handler)(void *); |
163 | | |
164 | | #define my_pthread_once_t pthread_once_t |
165 | | #if defined(PTHREAD_ONCE_INITIALIZER) |
166 | | #define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INITIALIZER |
167 | | #else |
168 | | #define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT |
169 | | #endif |
170 | 0 | #define my_pthread_once(C,F) pthread_once(C,F) |
171 | | |
172 | | /* Test first for RTS or FSU threads */ |
173 | | |
174 | | #if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) |
175 | | #define HAVE_rts_threads |
176 | | extern int my_pthread_create_detached; |
177 | | #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) |
178 | | #define PTHREAD_CREATE_DETACHED &my_pthread_create_detached |
179 | | #define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL |
180 | | #define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL |
181 | | #endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ |
182 | | |
183 | | #if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910 |
184 | | int sigwait(sigset_t *set, int *sig); |
185 | | #endif |
186 | | |
187 | | static inline int my_sigwait(sigset_t *set, int *sig, int *code) |
188 | 0 | { |
189 | 0 | #ifdef HAVE_SIGWAITINFO |
190 | 0 | siginfo_t siginfo; |
191 | 0 | *sig= sigwaitinfo(set, &siginfo); |
192 | 0 | *code= siginfo.si_code; |
193 | 0 | return *sig < 0 ? errno : 0; |
194 | 0 | #else |
195 | 0 | *code= 0; |
196 | 0 | return sigwait(set, sig); |
197 | 0 | #endif |
198 | 0 | } Unexecuted instantiation: fuzz_json.c:my_sigwait Unexecuted instantiation: json_lib.c:my_sigwait Unexecuted instantiation: ctype-ucs2.c:my_sigwait Unexecuted instantiation: dtoa.c:my_sigwait Unexecuted instantiation: xml.c:my_sigwait Unexecuted instantiation: ctype-simple.c:my_sigwait Unexecuted instantiation: my_strtoll10.c:my_sigwait Unexecuted instantiation: my_vsnprintf.c:my_sigwait Unexecuted instantiation: my_malloc.c:my_sigwait Unexecuted instantiation: my_static.c:my_sigwait Unexecuted instantiation: my_thr_init.c:my_sigwait Unexecuted instantiation: thr_mutex.c:my_sigwait Unexecuted instantiation: thr_rwlock.c:my_sigwait Unexecuted instantiation: psi_noop.c:my_sigwait Unexecuted instantiation: my_error.c:my_sigwait Unexecuted instantiation: my_getsystime.c:my_sigwait Unexecuted instantiation: my_init.c:my_sigwait Unexecuted instantiation: my_mess.c:my_sigwait Unexecuted instantiation: my_once.c:my_sigwait Unexecuted instantiation: my_symlink.c:my_sigwait Unexecuted instantiation: my_sync.c:my_sigwait Unexecuted instantiation: charset.c:my_sigwait Unexecuted instantiation: errors.c:my_sigwait Unexecuted instantiation: hash.c:my_sigwait Unexecuted instantiation: mf_dirname.c:my_sigwait Unexecuted instantiation: mf_loadpath.c:my_sigwait Unexecuted instantiation: mf_pack.c:my_sigwait Unexecuted instantiation: my_div.c:my_sigwait Unexecuted instantiation: my_getwd.c:my_sigwait Unexecuted instantiation: my_lib.c:my_sigwait Unexecuted instantiation: my_open.c:my_sigwait Unexecuted instantiation: my_read.c:my_sigwait Unexecuted instantiation: array.c:my_sigwait Unexecuted instantiation: charset-def.c:my_sigwait Unexecuted instantiation: mf_qsort.c:my_sigwait Unexecuted instantiation: my_alloc.c:my_sigwait Unexecuted instantiation: ctype-tis620.c:my_sigwait Unexecuted instantiation: str2int.c:my_sigwait |
199 | | |
200 | | #if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK) |
201 | | #define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C)) |
202 | | #endif |
203 | | |
204 | | #if !defined(HAVE_SIGWAIT) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(_AIX) |
205 | | int sigwait(sigset_t *setp, int *sigp); /* Use our implementation */ |
206 | | #endif |
207 | | |
208 | | |
209 | | /* |
210 | | We define my_sigset() and use that instead of the system sigset() so that |
211 | | we can favor an implementation based on sigaction(). On some systems, such |
212 | | as Mac OS X, sigset() results in flags such as SA_RESTART being set, and |
213 | | we want to make sure that no such flags are set. |
214 | | */ |
215 | | #if defined(HAVE_SIGACTION) && !defined(my_sigset) |
216 | | #define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; \ |
217 | | DBUG_ASSERT((A) != 0); \ |
218 | | sigemptyset(&l_set); \ |
219 | | l_s.sa_handler = (B); \ |
220 | | l_s.sa_mask = l_set; \ |
221 | | l_s.sa_flags = 0; \ |
222 | | sigaction((A), &l_s, NULL); \ |
223 | | } while (0) |
224 | | #elif defined(HAVE_SIGSET) && !defined(my_sigset) |
225 | | #define my_sigset(A,B) sigset((A),(B)) |
226 | | #elif !defined(my_sigset) |
227 | | #define my_sigset(A,B) signal((A),(B)) |
228 | | #endif |
229 | | |
230 | | #if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) |
231 | | #define pthread_attr_setscope(A,B) |
232 | | #undef HAVE_GETHOSTBYADDR_R /* No definition */ |
233 | | #endif |
234 | | |
235 | 0 | #define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B)) |
236 | | |
237 | | #ifndef HAVE_LOCALTIME_R |
238 | | struct tm *localtime_r(const time_t *clock, struct tm *res); |
239 | | #endif |
240 | | |
241 | | #ifndef HAVE_GMTIME_R |
242 | | struct tm *gmtime_r(const time_t *clock, struct tm *res); |
243 | | #endif |
244 | | |
245 | | #ifdef HAVE_PTHREAD_CONDATTR_CREATE |
246 | | /* DCE threads on HPUX 10.20 */ |
247 | | #define pthread_condattr_init pthread_condattr_create |
248 | | #define pthread_condattr_destroy pthread_condattr_delete |
249 | | #endif |
250 | | |
251 | | /* FSU THREADS */ |
252 | | #if !defined(HAVE_PTHREAD_KEY_DELETE) && !defined(pthread_key_delete) |
253 | | #define pthread_key_delete(A) pthread_dummy(0) |
254 | | #endif |
255 | | |
256 | | #if defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT) |
257 | | /* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */ |
258 | | #define pthread_key_create(A,B) \ |
259 | | pthread_keycreate(A,(B) ?\ |
260 | | (pthread_destructor_t) (B) :\ |
261 | | (pthread_destructor_t) pthread_dummy) |
262 | | #define pthread_attr_init(A) pthread_attr_create(A) |
263 | | #define pthread_attr_destroy(A) pthread_attr_delete(A) |
264 | | #define pthread_attr_setdetachstate(A,B) pthread_dummy(0) |
265 | | #define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) |
266 | | #ifndef pthread_sigmask |
267 | | #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) |
268 | | #endif |
269 | | #define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) |
270 | | #undef pthread_detach_this_thread |
271 | | #define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } |
272 | | #else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */ |
273 | | #define HAVE_PTHREAD_KILL 1 |
274 | | #endif |
275 | | |
276 | | #endif /* defined(_WIN32) */ |
277 | | |
278 | | #if defined(HPUX10) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) |
279 | | #undef pthread_cond_timedwait |
280 | | #define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) |
281 | | int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, |
282 | | struct timespec *abstime); |
283 | | #endif |
284 | | |
285 | | #if defined(HPUX10) |
286 | | #define pthread_attr_getstacksize(A,B) my_pthread_attr_getstacksize(A,B) |
287 | | void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size); |
288 | | #endif |
289 | | |
290 | | #if defined(HAVE_POSIX1003_4a_MUTEX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) |
291 | | #undef pthread_mutex_trylock |
292 | | #define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) |
293 | | int my_pthread_mutex_trylock(pthread_mutex_t *mutex); |
294 | | #endif |
295 | | |
296 | | #ifdef HAVE_SCHED_YIELD |
297 | | #define pthread_yield() sched_yield() |
298 | | #else |
299 | | #if !defined(HAVE_PTHREAD_YIELD_ZERO_ARG) |
300 | | /* no pthread_yield() available */ |
301 | | #if defined(HAVE_PTHREAD_YIELD_NP) /* can be Mac OS X */ |
302 | | #define pthread_yield() pthread_yield_np() |
303 | | #elif defined(HAVE_THR_YIELD) |
304 | | #define pthread_yield() thr_yield() |
305 | | #endif //defined(HAVE_PTHREAD_YIELD_NP) |
306 | | #endif //!defined(HAVE_PTHREAD_YIELD_ZERO_ARG) |
307 | | #endif //HAVE_SCHED_YIELD |
308 | | |
309 | | size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize); |
310 | | |
311 | | /* |
312 | | The defines set_timespec and set_timespec_nsec should be used |
313 | | for calculating an absolute time at which |
314 | | pthread_cond_timedwait should timeout |
315 | | */ |
316 | 0 | #define set_timespec(ABSTIME,SEC) set_timespec_nsec((ABSTIME),(SEC)*1000000000ULL) |
317 | | |
318 | | #ifndef set_timespec_nsec |
319 | | #define set_timespec_nsec(ABSTIME,NSEC) \ |
320 | 0 | set_timespec_time_nsec((ABSTIME), my_hrtime_coarse().val*1000 + (NSEC)) |
321 | | #endif /* !set_timespec_nsec */ |
322 | | |
323 | | /* adapt for two different flavors of struct timespec */ |
324 | | #ifdef HAVE_TIMESPEC_TS_SEC |
325 | | #define MY_tv_sec ts_sec |
326 | | #define MY_tv_nsec ts_nsec |
327 | | #else |
328 | 0 | #define MY_tv_sec tv_sec |
329 | 0 | #define MY_tv_nsec tv_nsec |
330 | | #endif /* HAVE_TIMESPEC_TS_SEC */ |
331 | | |
332 | | /** |
333 | | Compare two timespec structs. |
334 | | |
335 | | @retval 1 If TS1 ends after TS2. |
336 | | |
337 | | @retval 0 If TS1 is equal to TS2. |
338 | | |
339 | | @retval -1 If TS1 ends before TS2. |
340 | | */ |
341 | | #ifndef cmp_timespec |
342 | | #define cmp_timespec(TS1, TS2) \ |
343 | | ((TS1.MY_tv_sec > TS2.MY_tv_sec || \ |
344 | | (TS1.MY_tv_sec == TS2.MY_tv_sec && TS1.MY_tv_nsec > TS2.MY_tv_nsec)) ? 1 : \ |
345 | | ((TS1.MY_tv_sec < TS2.MY_tv_sec || \ |
346 | | (TS1.MY_tv_sec == TS2.MY_tv_sec && TS1.MY_tv_nsec < TS2.MY_tv_nsec)) ? -1 : 0)) |
347 | | #endif /* !cmp_timespec */ |
348 | | |
349 | | #ifndef set_timespec_time_nsec |
350 | 0 | #define set_timespec_time_nsec(ABSTIME,NSEC) do { \ |
351 | 0 | ulonglong _now_= (NSEC); \ |
352 | 0 | (ABSTIME).MY_tv_sec= (time_t) (_now_ / 1000000000ULL); \ |
353 | 0 | (ABSTIME).MY_tv_nsec= (ulong) (_now_ % 1000000000UL); \ |
354 | 0 | } while(0) |
355 | | #endif /* !set_timespec_time_nsec */ |
356 | | |
357 | | #ifdef MYSQL_CLIENT |
358 | | #define _current_thd() NULL |
359 | | #else |
360 | | MYSQL_THD _current_thd(); |
361 | | #endif |
362 | | |
363 | | /* safe_mutex adds checking to mutex for easier debugging */ |
364 | | struct st_hash; |
365 | | typedef struct st_safe_mutex_t |
366 | | { |
367 | | pthread_mutex_t global,mutex; |
368 | | const char *file, *name; |
369 | | uint line,count; |
370 | | myf create_flags, active_flags; |
371 | | ulong id; |
372 | | pthread_t thread; |
373 | | struct st_hash *locked_mutex, *used_mutex; |
374 | | struct st_safe_mutex_t *prev, *next; |
375 | | #ifdef SAFE_MUTEX_DETECT_DESTROY |
376 | | struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */ |
377 | | #endif |
378 | | } safe_mutex_t; |
379 | | |
380 | | typedef struct st_safe_mutex_deadlock_t |
381 | | { |
382 | | const char *file, *name; |
383 | | safe_mutex_t *mutex; |
384 | | uint line; |
385 | | ulong count; |
386 | | ulong id; |
387 | | my_bool warning_only; |
388 | | } safe_mutex_deadlock_t; |
389 | | |
390 | | #ifdef SAFE_MUTEX_DETECT_DESTROY |
391 | | /* |
392 | | Used to track the destroying of mutexes. This needs to be a separate |
393 | | structure because the safe_mutex_t structure could be freed before |
394 | | the mutexes are destroyed. |
395 | | */ |
396 | | |
397 | | typedef struct st_safe_mutex_info_t |
398 | | { |
399 | | struct st_safe_mutex_info_t *next; |
400 | | struct st_safe_mutex_info_t *prev; |
401 | | const char *init_file; |
402 | | uint32 init_line; |
403 | | } safe_mutex_info_t; |
404 | | #endif /* SAFE_MUTEX_DETECT_DESTROY */ |
405 | | |
406 | | int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, |
407 | | const char *name, const char *file, uint line); |
408 | | int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, |
409 | | uint line); |
410 | | int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); |
411 | | int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); |
412 | | int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, |
413 | | uint line); |
414 | | int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, |
415 | | const struct timespec *abstime, |
416 | | const char *file, uint line); |
417 | | void safe_mutex_global_init(void); |
418 | | void safe_mutex_end(FILE *file); |
419 | | void safe_mutex_free_deadlock_data(safe_mutex_t *mp); |
420 | | |
421 | | /* Wrappers if safe mutex is actually used */ |
422 | | #define MYF_TRY_LOCK 1 |
423 | | #define MYF_NO_DEADLOCK_DETECTION 2 |
424 | | |
425 | | #ifdef SAFE_MUTEX |
426 | | #define safe_mutex_is_owner(mp) ((mp)->count > 0 && \ |
427 | | pthread_equal(pthread_self(), (mp)->thread)) |
428 | | #define safe_mutex_assert_owner(mp) DBUG_ASSERT(safe_mutex_is_owner(mp)) |
429 | | #define safe_mutex_assert_not_owner(mp) DBUG_ASSERT(!safe_mutex_is_owner(mp)) |
430 | | #define safe_mutex_setflags(mp, F) do { (mp)->create_flags|= (F); } while (0) |
431 | | #define my_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) |
432 | | #define my_cond_wait(A,B) safe_cond_wait((A), (B), __FILE__, __LINE__) |
433 | | #else |
434 | | |
435 | | #define safe_mutex_is_owner(mp) (1) |
436 | | #define safe_mutex_assert_owner(mp) do {} while (0) |
437 | | #define safe_mutex_assert_not_owner(mp) do {} while (0) |
438 | | #define safe_mutex_setflags(mp, F) do {} while (0) |
439 | | |
440 | 0 | #define my_cond_timedwait(A,B,C) pthread_cond_timedwait((A),(B),(C)) |
441 | 0 | #define my_cond_wait(A,B) pthread_cond_wait((A), (B)) |
442 | | #endif /* !SAFE_MUTEX */ |
443 | | |
444 | | /* READ-WRITE thread locking */ |
445 | | |
446 | | #if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS) |
447 | | /* use these defs for simple mutex locking */ |
448 | | #define rw_lock_t pthread_mutex_t |
449 | | #define my_rwlock_init(A,B) pthread_mutex_init((A),(B)) |
450 | | #define rw_rdlock(A) pthread_mutex_lock((A)) |
451 | | #define rw_wrlock(A) pthread_mutex_lock((A)) |
452 | | #define rw_tryrdlock(A) pthread_mutex_trylock((A)) |
453 | | #define rw_trywrlock(A) pthread_mutex_trylock((A)) |
454 | | #define rw_unlock(A) pthread_mutex_unlock((A)) |
455 | | #define rwlock_destroy(A) pthread_mutex_destroy((A)) |
456 | | #elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK) |
457 | | #define rw_lock_t pthread_rwlock_t |
458 | | #define my_rwlock_init(A,B) pthread_rwlock_init((A),(B)) |
459 | 0 | #define rw_rdlock(A) pthread_rwlock_rdlock(A) |
460 | 0 | #define rw_wrlock(A) pthread_rwlock_wrlock(A) |
461 | 0 | #define rw_tryrdlock(A) pthread_rwlock_tryrdlock((A)) |
462 | 0 | #define rw_trywrlock(A) pthread_rwlock_trywrlock((A)) |
463 | | #define rw_unlock(A) pthread_rwlock_unlock(A) |
464 | | #define rwlock_destroy(A) pthread_rwlock_destroy(A) |
465 | | #elif defined(HAVE_RWLOCK_INIT) |
466 | | #ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */ |
467 | | #define rw_lock_t rwlock_t |
468 | | #endif |
469 | | #define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) |
470 | | #else |
471 | | /* Use our own version of read/write locks */ |
472 | | #define NEED_MY_RW_LOCK 1 |
473 | | #define rw_lock_t my_rw_lock_t |
474 | | #define my_rwlock_init(A,B) my_rw_init((A)) |
475 | | #define rw_rdlock(A) my_rw_rdlock((A)) |
476 | | #define rw_wrlock(A) my_rw_wrlock((A)) |
477 | | #define rw_tryrdlock(A) my_rw_tryrdlock((A)) |
478 | | #define rw_trywrlock(A) my_rw_trywrlock((A)) |
479 | | #define rw_unlock(A) my_rw_unlock((A)) |
480 | | #define rwlock_destroy(A) my_rw_destroy((A)) |
481 | | #define rw_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A)) |
482 | | #define rw_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A)) |
483 | | #endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ |
484 | | |
485 | | |
486 | | /** |
487 | | Portable implementation of special type of read-write locks. |
488 | | |
489 | | These locks have two properties which are unusual for rwlocks: |
490 | | 1) They "prefer readers" in the sense that they do not allow |
491 | | situations in which rwlock is rd-locked and there is a |
492 | | pending rd-lock which is blocked (e.g. due to pending |
493 | | request for wr-lock). |
494 | | This is a stronger guarantee than one which is provided for |
495 | | PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux. |
496 | | MDL subsystem deadlock detector relies on this property for |
497 | | its correctness. |
498 | | 2) They are optimized for uncontended wr-lock/unlock case. |
499 | | This is a scenario in which they are most often used |
500 | | within MDL subsystem. Optimizing for it gives significant |
501 | | performance improvements in some of the tests involving many |
502 | | connections. |
503 | | |
504 | | Another important requirement imposed on this type of rwlock |
505 | | by the MDL subsystem is that it should be OK to destroy rwlock |
506 | | object which is in unlocked state even though some threads might |
507 | | have not yet fully left unlock operation for it (of course there |
508 | | is an external guarantee that no thread will try to lock rwlock |
509 | | which is destroyed). |
510 | | Putting it another way the unlock operation should not access |
511 | | rwlock data after changing its state to unlocked. |
512 | | |
513 | | TODO/FIXME: We should consider alleviating this requirement as |
514 | | it blocks us from doing certain performance optimizations. |
515 | | */ |
516 | | |
517 | | typedef struct st_rw_pr_lock_t { |
518 | | /** |
519 | | Lock which protects the structure. |
520 | | Also held for the duration of wr-lock. |
521 | | */ |
522 | | pthread_mutex_t lock; |
523 | | /** |
524 | | Condition variable which is used to wake-up |
525 | | writers waiting for readers to go away. |
526 | | */ |
527 | | pthread_cond_t no_active_readers; |
528 | | /** Number of active readers. */ |
529 | | uint active_readers; |
530 | | /** Number of writers waiting for readers to go away. */ |
531 | | uint writers_waiting_readers; |
532 | | /** Indicates whether there is an active writer. */ |
533 | | my_bool active_writer; |
534 | | #ifdef SAFE_MUTEX |
535 | | /** Thread holding wr-lock (for debug purposes only). */ |
536 | | pthread_t writer_thread; |
537 | | #endif |
538 | | } rw_pr_lock_t; |
539 | | |
540 | | extern int rw_pr_init(rw_pr_lock_t *); |
541 | | extern int rw_pr_rdlock(rw_pr_lock_t *); |
542 | | extern int rw_pr_wrlock(rw_pr_lock_t *); |
543 | | extern int rw_pr_unlock(rw_pr_lock_t *); |
544 | | extern int rw_pr_destroy(rw_pr_lock_t *); |
545 | | #ifdef SAFE_MUTEX |
546 | | #define rw_pr_lock_assert_write_owner(A) \ |
547 | | DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \ |
548 | | (A)->writer_thread)) |
549 | | #define rw_pr_lock_assert_not_write_owner(A) \ |
550 | | DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \ |
551 | | (A)->writer_thread)) |
552 | | #else |
553 | | #define rw_pr_lock_assert_write_owner(A) |
554 | | #define rw_pr_lock_assert_not_write_owner(A) |
555 | | #endif /* SAFE_MUTEX */ |
556 | | |
557 | | |
558 | | #ifdef NEED_MY_RW_LOCK |
559 | | |
560 | | #ifdef _WIN32 |
561 | | |
562 | | /** |
563 | | Implementation of Windows rwlock. |
564 | | |
565 | | We use native (slim) rwlocks on Windows, which requires Win7 |
566 | | or later. |
567 | | */ |
568 | | typedef struct _my_rwlock_t |
569 | | { |
570 | | SRWLOCK srwlock; /* native reader writer lock */ |
571 | | BOOL have_exclusive_srwlock; /* used for unlock */ |
572 | | } my_rw_lock_t; |
573 | | |
574 | | |
575 | | #else /* _WIN32 */ |
576 | | |
577 | | /* |
578 | | On systems which don't support native read/write locks we have |
579 | | to use own implementation. |
580 | | */ |
581 | | typedef struct st_my_rw_lock_t { |
582 | | pthread_mutex_t lock; /* lock for structure */ |
583 | | pthread_cond_t readers; /* waiting readers */ |
584 | | pthread_cond_t writers; /* waiting writers */ |
585 | | int state; /* -1:writer,0:free,>0:readers */ |
586 | | int waiters; /* number of waiting writers */ |
587 | | #ifdef SAFE_MUTEX |
588 | | pthread_t write_thread; |
589 | | #endif |
590 | | } my_rw_lock_t; |
591 | | |
592 | | #endif /*! _WIN32 */ |
593 | | |
594 | | extern int my_rw_init(my_rw_lock_t *); |
595 | | extern int my_rw_destroy(my_rw_lock_t *); |
596 | | extern int my_rw_rdlock(my_rw_lock_t *); |
597 | | extern int my_rw_wrlock(my_rw_lock_t *); |
598 | | extern int my_rw_unlock(my_rw_lock_t *); |
599 | | extern int my_rw_tryrdlock(my_rw_lock_t *); |
600 | | extern int my_rw_trywrlock(my_rw_lock_t *); |
601 | | #ifdef SAFE_MUTEX |
602 | | #define my_rw_lock_assert_write_owner(A) \ |
603 | | DBUG_ASSERT((A)->state == -1 && pthread_equal(pthread_self(), \ |
604 | | (A)->write_thread)) |
605 | | #define my_rw_lock_assert_not_write_owner(A) \ |
606 | | DBUG_ASSERT((A)->state >= 0 || ! pthread_equal(pthread_self(), \ |
607 | | (A)->write_thread)) |
608 | | #else |
609 | | #define my_rw_lock_assert_write_owner(A) |
610 | | #define my_rw_lock_assert_not_write_owner(A) |
611 | | #endif |
612 | | #endif /* NEED_MY_RW_LOCK */ |
613 | | |
614 | | |
615 | | #define GETHOSTBYADDR_BUFF_SIZE 2048 |
616 | | |
617 | | #if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize) |
618 | | #define pthread_attr_setstacksize(A,B) pthread_dummy(0) |
619 | | #endif |
620 | | |
621 | | /* Define mutex types, see my_thr_init.c */ |
622 | | #define MY_MUTEX_INIT_SLOW NULL |
623 | | #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP |
624 | | extern pthread_mutexattr_t my_fast_mutexattr; |
625 | | #define MY_MUTEX_INIT_FAST &my_fast_mutexattr |
626 | | #else |
627 | | #define MY_MUTEX_INIT_FAST NULL |
628 | | #endif |
629 | | #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP |
630 | | extern pthread_mutexattr_t my_errorcheck_mutexattr; |
631 | | #define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr |
632 | | #else |
633 | | #define MY_MUTEX_INIT_ERRCHK NULL |
634 | | #endif |
635 | | |
636 | | #ifndef ESRCH |
637 | | /* Define it to something */ |
638 | | #define ESRCH 1 |
639 | | #endif |
640 | | |
641 | | typedef uint64 my_thread_id; |
642 | | |
643 | | extern void my_threadattr_global_init(void); |
644 | | extern my_bool my_thread_global_init(void); |
645 | | extern void my_thread_global_reinit(void); |
646 | | extern void my_thread_global_end(void); |
647 | | extern my_bool my_thread_init(void); |
648 | | extern void my_thread_end(void); |
649 | | extern const char *my_thread_name(void); |
650 | | extern my_thread_id my_thread_dbug_id(void); |
651 | | extern int pthread_dummy(int); |
652 | | extern void my_mutex_init(void); |
653 | | extern void my_mutex_end(void); |
654 | | |
655 | | /* All thread specific variables are in the following struct */ |
656 | | |
657 | | #define THREAD_NAME_SIZE 10 |
658 | | #ifndef DEFAULT_THREAD_STACK |
659 | | /* |
660 | | We need to have at least 256K stack to handle calls to myisamchk_init() |
661 | | with the current number of keys and key parts. |
662 | | */ |
663 | | # if defined(__SANITIZE_ADDRESS__) || defined(WITH_UBSAN) |
664 | | /* |
665 | | Optimized WITH_ASAN=ON executables produced |
666 | | by GCC 12.3.0, GCC 13.2.0, or clang 16.0.6 |
667 | | would fail ./mtr main.1st when the stack size is 5 MiB. |
668 | | The minimum is more than 6 MiB for CMAKE_BUILD_TYPE=RelWithDebInfo and |
669 | | more than 10 MiB for CMAKE_BUILD_TYPE=Debug. |
670 | | Let us add some safety margin. |
671 | | */ |
672 | | # define DEFAULT_THREAD_STACK (11L<<20) |
673 | | # else |
674 | | # define DEFAULT_THREAD_STACK (292*1024L) /* 299008 */ |
675 | | # endif |
676 | | #endif |
677 | | |
678 | | #define MY_PTHREAD_LOCK_READ 0 |
679 | | #define MY_PTHREAD_LOCK_WRITE 1 |
680 | | |
681 | | #include <mysql/psi/mysql_thread.h> |
682 | | |
683 | | #define INSTRUMENT_ME 0 |
684 | | |
685 | | /* |
686 | | Thread specific variables |
687 | | |
688 | | Aria key cache is using the following variables for keeping track of |
689 | | state: |
690 | | suspend, next, prev, keycache_link, keycache_file, suspend, lock_type |
691 | | |
692 | | MariaDB uses the following to |
693 | | mutex, current_mutex, current_cond, abort |
694 | | */ |
695 | | |
696 | | struct st_my_thread_var |
697 | | { |
698 | | int thr_errno; |
699 | | mysql_cond_t suspend; |
700 | | mysql_mutex_t mutex; |
701 | | struct st_my_thread_var *next,**prev; |
702 | | mysql_mutex_t * volatile current_mutex; |
703 | | mysql_cond_t * volatile current_cond; |
704 | | void *keycache_link; |
705 | | void *keycache_file; |
706 | | void *stack_ends_here; |
707 | | safe_mutex_t *mutex_in_use; |
708 | | pthread_t pthread_self; |
709 | | my_thread_id id, dbug_id; |
710 | | int volatile abort; |
711 | | uint lock_type; /* used by conditional release the queue */ |
712 | | my_bool init; |
713 | | #ifndef DBUG_OFF |
714 | | void *dbug; |
715 | | char name[THREAD_NAME_SIZE+1]; |
716 | | #endif |
717 | | }; |
718 | | |
719 | | struct st_my_thread_var *_my_thread_var(void); |
720 | | extern void **my_thread_var_dbug(void); |
721 | | extern safe_mutex_t **my_thread_var_mutex_in_use(void); |
722 | | extern uint my_thread_end_wait_time; |
723 | | extern my_bool safe_mutex_deadlock_detector; |
724 | 0 | #define my_thread_var (_my_thread_var()) |
725 | 0 | #define my_errno my_thread_var->thr_errno |
726 | | int set_mysys_var(struct st_my_thread_var *mysys_var); |
727 | | |
728 | | |
729 | | /* |
730 | | thread_safe_xxx functions are for critical statistic or counters. |
731 | | The implementation is guaranteed to be thread safe, on all platforms. |
732 | | Note that the calling code should *not* assume the counter is protected |
733 | | by the mutex given, as the implementation of these helpers may change |
734 | | to use my_atomic operations instead. |
735 | | */ |
736 | | |
737 | | #ifndef thread_safe_increment |
738 | | #ifdef _WIN32 |
739 | | #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) |
740 | | #define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) |
741 | | #else |
742 | | #define thread_safe_increment(V,L) \ |
743 | | (mysql_mutex_lock((L)), (V)++, mysql_mutex_unlock((L))) |
744 | | #define thread_safe_decrement(V,L) \ |
745 | | (mysql_mutex_lock((L)), (V)--, mysql_mutex_unlock((L))) |
746 | | #endif |
747 | | #endif |
748 | | |
749 | | #ifndef thread_safe_add |
750 | | #ifdef _WIN32 |
751 | | #define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) |
752 | | #define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) |
753 | | #else |
754 | | #define thread_safe_add(V,C,L) \ |
755 | | (mysql_mutex_lock((L)), (V)+=(C), mysql_mutex_unlock((L))) |
756 | | #define thread_safe_sub(V,C,L) \ |
757 | | (mysql_mutex_lock((L)), (V)-=(C), mysql_mutex_unlock((L))) |
758 | | #endif |
759 | | #endif |
760 | | |
761 | | |
762 | | /* |
763 | | statistics_xxx functions are for non critical statistic, |
764 | | maintained in global variables. |
765 | | When compiling with SAFE_STATISTICS: |
766 | | - race conditions can not occur. |
767 | | - some locking occurs, which may cause performance degradation. |
768 | | |
769 | | When compiling without SAFE_STATISTICS: |
770 | | - race conditions can occur, making the result slightly inaccurate. |
771 | | - the lock given is not honored. |
772 | | */ |
773 | | #ifdef SAFE_STATISTICS |
774 | | #define statistic_increment(V,L) thread_safe_increment((V),(L)) |
775 | | #define statistic_decrement(V,L) thread_safe_decrement((V),(L)) |
776 | | #define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) |
777 | | #define statistic_sub(V,C,L) thread_safe_sub((V),(C),(L)) |
778 | | #else |
779 | | #define statistic_decrement(V,L) (V)-- |
780 | 0 | #define statistic_increment(V,L) (V)++ |
781 | | #define statistic_add(V,C,L) (V)+=(C) |
782 | | #define statistic_sub(V,C,L) (V)-=(C) |
783 | | #endif /* SAFE_STATISTICS */ |
784 | | |
785 | | /* |
786 | | No locking needed, the counter is owned by the thread |
787 | | */ |
788 | | #define status_var_increment(V) (V)++ |
789 | | #define status_var_decrement(V) (V)-- |
790 | | #define status_var_add(V,C) (V)+=(C) |
791 | | #define status_var_sub(V,C) (V)-=(C) |
792 | | |
793 | | #ifdef SAFE_MUTEX |
794 | | #define mysql_mutex_record_order(A,B) \ |
795 | | do { \ |
796 | | mysql_mutex_lock(A); mysql_mutex_lock(B); \ |
797 | | mysql_mutex_unlock(B); mysql_mutex_unlock(A); \ |
798 | | } while(0) |
799 | | #else |
800 | | #define mysql_mutex_record_order(A,B) do { } while(0) |
801 | | #endif |
802 | | |
803 | | /* At least Windows and NetBSD do not have this definition */ |
804 | | #ifndef PTHREAD_STACK_MIN |
805 | | #define PTHREAD_STACK_MIN 65536 |
806 | | #endif |
807 | | |
808 | | #ifdef __cplusplus |
809 | | } |
810 | | #endif |
811 | | #endif /* _my_ptread_h */ |