1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
Functions to handle initializating and allocationg of all mysys & debug
21
#include "mysys_priv.h"
27
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
29
pthread_key(struct st_my_thread_var, THR_KEY_mysys);
31
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
32
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
33
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
34
pthread_cond_t THR_COND_threads;
35
uint THR_thread_count= 0;
36
uint my_thread_end_wait_time= 5;
37
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
38
pthread_mutex_t LOCK_localtime_r;
40
#ifndef HAVE_GETHOSTBYNAME_R
41
pthread_mutex_t LOCK_gethostbyname_r;
43
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
44
pthread_mutexattr_t my_fast_mutexattr;
46
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
47
pthread_mutexattr_t my_errorcheck_mutexattr;
50
#ifdef TARGET_OS_LINUX
53
Dummy thread spawned in my_thread_global_init() below to avoid
54
race conditions in NPTL pthread_exit code.
57
static pthread_handler_t
58
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
65
#endif /* TARGET_OS_LINUX */
68
static uint get_thread_lib(void);
71
initialize thread environment
74
my_thread_global_init()
78
1 error (Couldn't create THR_KEY_mysys)
81
my_bool my_thread_global_init(void)
84
thd_lib_detected= get_thread_lib();
86
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
88
fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
92
#ifdef TARGET_OS_LINUX
94
BUG#24507: Race conditions inside current NPTL pthread_exit()
97
To avoid a possible segmentation fault during concurrent
98
executions of pthread_exit(), a dummy thread is spawned which
99
initializes internal variables of pthread lib. See bug description
100
for a full explanation.
102
TODO: Remove this code when fixed versions of glibc6 are in common
105
if (thd_lib_detected == THD_LIB_NPTL)
107
pthread_t dummy_thread;
108
pthread_attr_t dummy_thread_attr;
110
pthread_attr_init(&dummy_thread_attr);
111
pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
113
pthread_create(&dummy_thread,&dummy_thread_attr,
114
nptl_pthread_exit_hack_handler, NULL);
116
#endif /* TARGET_OS_LINUX */
118
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
120
Set mutex type to "fast" a.k.a "adaptive"
122
In this case the thread may steal the mutex from some other thread
123
that is waiting for the same mutex. This will save us some
124
context switches but may cause a thread to 'starve forever' while
125
waiting for the mutex (not likely if the code within the mutex is
128
pthread_mutexattr_init(&my_fast_mutexattr);
129
pthread_mutexattr_settype(&my_fast_mutexattr,
130
PTHREAD_MUTEX_ADAPTIVE_NP);
132
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
134
Set mutex type to "errorcheck"
136
pthread_mutexattr_init(&my_errorcheck_mutexattr);
137
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
138
PTHREAD_MUTEX_ERRORCHECK);
141
pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
142
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
143
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
144
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
145
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
146
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
147
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
148
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
149
pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
150
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
151
pthread_cond_init(&THR_COND_threads, NULL);
152
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
153
pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
155
#ifndef HAVE_GETHOSTBYNAME_R
156
pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
158
if (my_thread_init())
160
my_thread_global_end(); /* Clean up */
167
void my_thread_global_end(void)
169
struct timespec abstime;
170
my_bool all_threads_killed= 1;
172
set_timespec(abstime, my_thread_end_wait_time);
173
pthread_mutex_lock(&THR_LOCK_threads);
174
while (THR_thread_count > 0)
176
int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
178
if (error == ETIMEDOUT || error == ETIME)
180
#ifdef HAVE_PTHREAD_KILL
182
We shouldn't give an error here, because if we don't have
183
pthread_kill(), programs like mysqld can't ensure that all threads
184
are killed when we enter here.
186
if (THR_thread_count)
188
"Error in my_thread_global_end(): %d threads didn't exit\n",
191
all_threads_killed= 0;
195
pthread_mutex_unlock(&THR_LOCK_threads);
197
pthread_key_delete(THR_KEY_mysys);
198
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
199
pthread_mutexattr_destroy(&my_fast_mutexattr);
201
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
202
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
204
pthread_mutex_destroy(&THR_LOCK_malloc);
205
pthread_mutex_destroy(&THR_LOCK_open);
206
pthread_mutex_destroy(&THR_LOCK_lock);
207
pthread_mutex_destroy(&THR_LOCK_isam);
208
pthread_mutex_destroy(&THR_LOCK_myisam);
209
pthread_mutex_destroy(&THR_LOCK_heap);
210
pthread_mutex_destroy(&THR_LOCK_net);
211
pthread_mutex_destroy(&THR_LOCK_time);
212
pthread_mutex_destroy(&THR_LOCK_charset);
213
if (all_threads_killed)
215
pthread_mutex_destroy(&THR_LOCK_threads);
216
pthread_cond_destroy(&THR_COND_threads);
218
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
219
pthread_mutex_destroy(&LOCK_localtime_r);
221
#ifndef HAVE_GETHOSTBYNAME_R
222
pthread_mutex_destroy(&LOCK_gethostbyname_r);
226
static my_thread_id thread_id= 0;
229
Allocate thread specific memory for the thread, used by mysys and dbug
235
We can't use mutex_locks here if we are using windows as
236
we may have compiled the program with SAFE_MUTEX, in which
237
case the checking of mutex_locks will not work until
238
the pthread_self thread specific variable is initialized.
240
This function may called multiple times for a thread, for example
241
if one uses my_init() followed by mysql_server_init().
245
1 Fatal error; mysys/dbug functions can't be used
248
my_bool my_thread_init(void)
250
struct st_my_thread_var *tmp;
253
#ifdef EXTRA_DEBUG_THREADS
254
fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
255
(ulong) pthread_self());
258
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
260
#ifdef EXTRA_DEBUG_THREADS
261
fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
262
(long) pthread_self());
266
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
271
pthread_setspecific(THR_KEY_mysys,tmp);
272
tmp->pthread_self= pthread_self();
273
pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
274
pthread_cond_init(&tmp->suspend, NULL);
277
pthread_mutex_lock(&THR_LOCK_threads);
278
tmp->id= ++thread_id;
280
pthread_mutex_unlock(&THR_LOCK_threads);
282
/* Generate unique name for thread */
283
(void) my_thread_name();
292
Deallocate memory used by the thread for book-keeping
298
This may be called multiple times for a thread.
299
This happens for example when one calls 'mysql_server_init()'
300
mysql_server_end() and then ends with a mysql_end().
303
void my_thread_end(void)
305
struct st_my_thread_var *tmp;
306
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
308
#ifdef EXTRA_DEBUG_THREADS
309
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
310
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
312
if (tmp && tmp->init)
314
#if !defined(DBUG_OFF)
315
/* tmp->dbug is allocated inside DBUG library */
323
#if !defined(__bsdi__) && !defined(__OpenBSD__)
324
/* bsdi and openbsd 3.5 dumps core here */
325
pthread_cond_destroy(&tmp->suspend);
327
pthread_mutex_destroy(&tmp->mutex);
335
Decrement counter for number of running threads. We are using this
336
in my_thread_global_end() to wait until all threads have called
337
my_thread_end and thus freed all memory they have allocated in
338
my_thread_init() and DBUG_xxxx
340
pthread_mutex_lock(&THR_LOCK_threads);
341
DBUG_ASSERT(THR_thread_count != 0);
342
if (--THR_thread_count == 0)
343
pthread_cond_signal(&THR_COND_threads);
344
pthread_mutex_unlock(&THR_LOCK_threads);
346
/* The following free has to be done, even if my_thread_var() is 0 */
348
pthread_setspecific(THR_KEY_mysys,0);
352
struct st_my_thread_var *_my_thread_var(void)
354
struct st_my_thread_var *tmp=
355
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
357
/* This can only happen in a .DLL */
361
tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
368
/****************************************************************************
369
Get name of current thread.
370
****************************************************************************/
372
my_thread_id my_thread_dbug_id()
374
return my_thread_var->id;
378
const char *my_thread_name(void)
385
const char *my_thread_name(void)
388
struct st_my_thread_var *tmp=my_thread_var;
391
my_thread_id id= my_thread_dbug_id();
392
sprintf(name_buff,"T@%lu", (ulong) id);
393
strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
397
#endif /* DBUG_OFF */
400
static uint get_thread_lib(void)
402
#ifdef _CS_GNU_LIBPTHREAD_VERSION
405
confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
407
if (!strncasecmp(buff, "NPTL", 4))
409
if (!strncasecmp(buff, "linuxthreads", 12))
412
return THD_LIB_OTHER;