| 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 | |