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