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