2
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
4
The MySQL Connector/C++ is licensed under the terms of the GPLv2
5
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
6
MySQL Connectors. There are special exceptions to the terms and
7
conditions of the GPLv2 as it is applied to this software, see the
8
FLOSS License Exception
9
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published
13
by the Free Software Foundation; version 2 of the License.
15
This program is distributed in the hope that it will be useful, but
16
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20
You should have received a copy of the GNU General Public License along
21
with this program; if not, write to the Free Software Foundation, Inc.,
22
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29
Functions for initialization and allocation of all mysys & debug
34
#include "my_pthread.h"
35
extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
36
extern pthread_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net;
37
extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
39
#include "my_no_pthread.h"
42
//#include "mysys_priv.h"
43
//#include <m_string.h>
47
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
48
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
49
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_heap, THR_LOCK_net,
50
THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
51
/** For insert/delete in the list of MyISAM open tables */
52
pthread_mutex_t THR_LOCK_myisam;
53
/** For writing to the MyISAM logs */
54
pthread_mutex_t THR_LOCK_myisam_log;
55
pthread_cond_t THR_COND_threads;
56
uint THR_thread_count= 0;
57
uint my_thread_end_wait_time= 5;
58
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
59
pthread_mutex_t LOCK_localtime_r;
61
#ifndef HAVE_GETHOSTBYNAME_R
62
pthread_mutex_t LOCK_gethostbyname_r;
64
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
65
pthread_mutexattr_t my_fast_mutexattr;
67
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
68
pthread_mutexattr_t my_errorcheck_mutexattr;
71
static void install_sigabrt_handler();
73
#ifdef TARGET_OS_LINUX
76
Dummy thread spawned in my_thread_global_init() below to avoid
77
race conditions in NPTL pthread_exit code.
80
static pthread_handler_t
81
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
88
#endif /* TARGET_OS_LINUX */
93
Initialize thread attributes.
96
void my_threadattr_global_init(void)
98
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
100
Set mutex type to "fast" a.k.a "adaptive"
102
In this case the thread may steal the mutex from some other thread
103
that is waiting for the same mutex. This will save us some
104
context switches but may cause a thread to 'starve forever' while
105
waiting for the mutex (not likely if the code within the mutex is
108
pthread_mutexattr_init(&my_fast_mutexattr); /* ?= MY_MUTEX_INIT_FAST */
109
pthread_mutexattr_settype(&my_fast_mutexattr,
110
PTHREAD_MUTEX_ADAPTIVE_NP);
112
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
114
Set mutex type to "errorcheck"
116
pthread_mutexattr_init(&my_errorcheck_mutexattr);
117
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
118
PTHREAD_MUTEX_ERRORCHECK);
123
static uint get_thread_lib(void);
126
initialize thread environment
129
my_thread_global_init()
133
1 error (Couldn't create THR_KEY_mysys)
136
my_bool my_thread_global_init(void)
139
thd_lib_detected= get_thread_lib();
141
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
143
fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
147
#ifdef TARGET_OS_LINUX
149
BUG#24507: Race conditions inside current NPTL pthread_exit()
152
To avoid a possible segmentation fault during concurrent
153
executions of pthread_exit(), a dummy thread is spawned which
154
initializes internal variables of pthread lib. See bug description
155
for a full explanation.
157
TODO: Remove this code when fixed versions of glibc6 are in common
160
if (thd_lib_detected == THD_LIB_NPTL)
162
pthread_t dummy_thread;
163
pthread_attr_t dummy_thread_attr;
165
pthread_attr_init(&dummy_thread_attr);
166
pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
168
pthread_create(&dummy_thread,&dummy_thread_attr,
169
nptl_pthread_exit_hack_handler, NULL);
171
#endif /* TARGET_OS_LINUX */
173
/* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */
174
my_pthread_mutex_init(&THR_LOCK_threads, MY_MUTEX_INIT_FAST,
175
"THR_LOCK_threads", MYF_NO_DEADLOCK_DETECTION);
176
my_pthread_mutex_init(&THR_LOCK_malloc, MY_MUTEX_INIT_FAST,
177
"THR_LOCK_malloc", MYF_NO_DEADLOCK_DETECTION);
179
if (my_thread_init())
183
/* Mutex uses by mysys */
184
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
185
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
186
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
187
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
188
pthread_mutex_init(&THR_LOCK_myisam_log,MY_MUTEX_INIT_SLOW);
189
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
190
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
191
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
192
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
193
pthread_cond_init(&THR_COND_threads, NULL);
195
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
196
pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
198
#ifndef HAVE_GETHOSTBYNAME_R
199
pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
206
Wait for all threads in system to die
207
@fn my_wait_for_other_threads_to_die()
208
@param number_of_threads Wait until this number of threads
210
@retval 0 Less or equal to number_of_threads left
211
@retval 1 Wait failed
214
my_bool my_wait_for_other_threads_to_die(uint number_of_threads)
216
struct timespec abstime;
217
my_bool all_threads_killed= 1;
219
set_timespec(abstime, my_thread_end_wait_time);
220
pthread_mutex_lock(&THR_LOCK_threads);
221
while (THR_thread_count > number_of_threads)
223
int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
225
if (error == ETIMEDOUT || error == ETIME)
227
all_threads_killed= 0;
231
pthread_mutex_unlock(&THR_LOCK_threads);
232
return all_threads_killed;
237
End the mysys thread system. Called when ending the last thread
241
void my_thread_global_end(void)
243
my_bool all_threads_killed;
245
if (!(all_threads_killed= my_wait_for_other_threads_to_die(0)))
247
#ifdef HAVE_PTHREAD_KILL
249
We shouldn't give an error here, because if we don't have
250
pthread_kill(), programs like mysqld can't ensure that all threads
251
are killed when we enter here.
253
if (THR_thread_count)
255
"Error in my_thread_global_end(): %d threads didn't exit\n",
260
pthread_key_delete(THR_KEY_mysys);
261
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
262
pthread_mutexattr_destroy(&my_fast_mutexattr);
264
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
265
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
267
if (all_threads_killed)
269
pthread_mutex_destroy(&THR_LOCK_threads);
270
pthread_cond_destroy(&THR_COND_threads);
271
pthread_mutex_destroy(&THR_LOCK_malloc);
275
/* Free all mutex used by mysys */
277
void my_thread_destroy_mutex(void)
279
struct st_my_thread_var *tmp;
280
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
283
safe_mutex_free_deadlock_data(&tmp->mutex);
286
pthread_mutex_destroy(&THR_LOCK_open);
287
pthread_mutex_destroy(&THR_LOCK_lock);
288
pthread_mutex_destroy(&THR_LOCK_isam);
289
pthread_mutex_destroy(&THR_LOCK_myisam);
290
pthread_mutex_destroy(&THR_LOCK_myisam_log);
291
pthread_mutex_destroy(&THR_LOCK_heap);
292
pthread_mutex_destroy(&THR_LOCK_net);
293
pthread_mutex_destroy(&THR_LOCK_time);
294
pthread_mutex_destroy(&THR_LOCK_charset);
295
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
296
pthread_mutex_destroy(&LOCK_localtime_r);
298
#ifndef HAVE_GETHOSTBYNAME_R
299
pthread_mutex_destroy(&LOCK_gethostbyname_r);
303
static my_thread_id thread_id= 0;
306
Allocate thread specific memory for the thread, used by mysys and dbug
312
We can't use mutex_locks here if we are using windows as
313
we may have compiled the program with SAFE_MUTEX, in which
314
case the checking of mutex_locks will not work until
315
the pthread_self thread specific variable is initialized.
317
This function may called multiple times for a thread, for example
318
if one uses my_init() followed by mysql_server_init().
322
1 Fatal error; mysys/dbug functions can't be used
325
my_bool my_thread_init(void)
327
struct st_my_thread_var *tmp;
330
#ifdef EXTRA_DEBUG_THREADS
331
fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
332
(ulong) pthread_self());
335
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
337
#ifdef EXTRA_DEBUG_THREADS
338
fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
339
(long) pthread_self());
345
install_sigabrt_handler();
348
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
353
pthread_setspecific(THR_KEY_mysys,tmp);
354
tmp->pthread_self= pthread_self();
355
my_pthread_mutex_init(&tmp->mutex, MY_MUTEX_INIT_FAST, "mysys_var->mutex",
357
pthread_cond_init(&tmp->suspend, NULL);
359
tmp->stack_ends_here= (char*)&tmp +
360
STACK_DIRECTION * (long)my_thread_stack_size;
362
pthread_mutex_lock(&THR_LOCK_threads);
363
tmp->id= ++thread_id;
365
pthread_mutex_unlock(&THR_LOCK_threads);
368
/* Generate unique name for thread */
369
(void) my_thread_name();
378
Deallocate memory used by the thread for book-keeping
384
This may be called multiple times for a thread.
385
This happens for example when one calls 'mysql_server_init()'
386
mysql_server_end() and then ends with a mysql_end().
389
void my_thread_end(void)
391
struct st_my_thread_var *tmp;
392
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
394
#ifdef EXTRA_DEBUG_THREADS
395
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
396
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
398
if (tmp && tmp->init)
401
#if !defined(__bsdi__) && !defined(__OpenBSD__)
402
/* bsdi and openbsd 3.5 dumps core here */
403
pthread_cond_destroy(&tmp->suspend);
405
pthread_mutex_destroy(&tmp->mutex);
407
#if !defined(DBUG_OFF)
408
/* tmp->dbug is allocated inside DBUG library */
412
Frees memory allocated in SET DEBUG=...; does nothing if there were no
413
SET DEBUG in a thread.
421
/* To find bugs when accessing unallocated data */
422
bfill(tmp, sizeof(tmp), 0x8F);
425
pthread_setspecific(THR_KEY_mysys,0);
427
Decrement counter for number of running threads. We are using this
428
in my_thread_global_end() to wait until all threads have called
429
my_thread_end and thus freed all memory they have allocated in
430
my_thread_init() and DBUG_xxxx
432
pthread_mutex_lock(&THR_LOCK_threads);
433
DBUG_ASSERT(THR_thread_count != 0);
434
if (--THR_thread_count == 0)
435
pthread_cond_signal(&THR_COND_threads);
436
pthread_mutex_unlock(&THR_LOCK_threads);
440
pthread_setspecific(THR_KEY_mysys,0);
444
struct st_my_thread_var *_my_thread_var(void)
446
return my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
450
/* Return pointer to DBUG for holding current state */
452
extern void **my_thread_var_dbug()
454
struct st_my_thread_var *tmp=
455
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
456
return tmp && tmp->init ? &tmp->dbug : 0;
460
/* Return pointer to mutex_in_use */
462
safe_mutex_t **my_thread_var_mutex_in_use()
464
struct st_my_thread_var *tmp=
465
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
466
return tmp ? &tmp->mutex_in_use : 0;
469
/****************************************************************************
470
Get name of current thread.
471
****************************************************************************/
473
my_thread_id my_thread_dbug_id()
475
return my_thread_var->id;
479
const char *my_thread_name(void)
486
const char *my_thread_name(void)
489
struct st_my_thread_var *tmp=my_thread_var;
492
my_thread_id id= my_thread_dbug_id();
493
sprintf(name_buff,"T@%lu", (ulong) id);
494
strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
498
#endif /* DBUG_OFF */
501
static uint get_thread_lib(void)
503
#ifdef _CS_GNU_LIBPTHREAD_VERSION
506
confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
508
if (!strncasecmp(buff, "NPTL", 4))
510
if (!strncasecmp(buff, "linuxthreads", 12))
513
return THD_LIB_OTHER;
518
In Visual Studio 2005 and later, default SIGABRT handler will overwrite
519
any unhandled exception filter set by the application and will try to
520
call JIT debugger. This is not what we want, this we calling __debugbreak
521
to stop in debugger, if process is being debugged or to generate
522
EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
525
#if (_MSC_VER >= 1400)
526
static void my_sigabrt_handler(int sig)
530
#endif /*_MSC_VER >=1400 */
532
static void install_sigabrt_handler(void)
534
#if (_MSC_VER >=1400)
535
/*abort() should not override our exception filter*/
536
_set_abort_behavior(0,_CALL_REPORTFAULT);
537
signal(SIGABRT,my_sigabrt_handler);
538
#endif /* _MSC_VER >=1400 */