1/* Copyright (c) 2000, 2011 Oracle and/or its affiliates.
2 Copyright 2008-2011 Monty Program Ab
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 St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17/*
18 Functions to handle initializating and allocationg of all mysys & debug
19 thread variables.
20*/
21
22#include "mysys_priv.h"
23#include <m_string.h>
24#include <signal.h>
25
26pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
27mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open,
28 THR_LOCK_lock, THR_LOCK_myisam, THR_LOCK_heap,
29 THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads,
30 THR_LOCK_myisam_mmap;
31
32mysql_cond_t THR_COND_threads;
33uint THR_thread_count= 0;
34uint my_thread_end_wait_time= 5;
35#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
36mysql_mutex_t LOCK_localtime_r;
37#endif
38#ifdef _MSC_VER
39static void install_sigabrt_handler();
40#endif
41
42
43static uint get_thread_lib(void);
44
45/** True if @c my_thread_global_init() has been called. */
46static my_bool my_thread_global_init_done= 0;
47/* True if THR_KEY_mysys is created */
48my_bool my_thr_key_mysys_exists= 0;
49
50
51/*
52 These are mutexes not used by safe_mutex or my_thr_init.c
53
54 We want to free these earlier than other mutex so that safe_mutex
55 can detect if all mutex and memory is freed properly.
56*/
57
58static void my_thread_init_common_mutex(void)
59{
60 mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
61 mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
62 mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
63 mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
64 mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
65 mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
66 mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
67#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
68 mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
69#endif
70}
71
72void my_thread_destroy_common_mutex(void)
73{
74 mysql_mutex_destroy(&THR_LOCK_open);
75 mysql_mutex_destroy(&THR_LOCK_lock);
76 mysql_mutex_destroy(&THR_LOCK_myisam);
77 mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
78 mysql_mutex_destroy(&THR_LOCK_heap);
79 mysql_mutex_destroy(&THR_LOCK_net);
80 mysql_mutex_destroy(&THR_LOCK_charset);
81#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
82 mysql_mutex_destroy(&LOCK_localtime_r);
83#endif
84}
85
86
87/*
88 These mutexes are used by my_thread_init() and after
89 my_thread_destroy_mutex()
90*/
91
92static void my_thread_init_internal_mutex(void)
93{
94 mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
95 mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
96 mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
97}
98
99
100void my_thread_destroy_internal_mutex(void)
101{
102 mysql_mutex_destroy(&THR_LOCK_threads);
103 mysql_mutex_destroy(&THR_LOCK_malloc);
104 mysql_cond_destroy(&THR_COND_threads);
105}
106
107static void my_thread_init_thr_mutex(struct st_my_thread_var *var)
108{
109 mysql_mutex_init(key_my_thread_var_mutex, &var->mutex, MY_MUTEX_INIT_FAST);
110 mysql_cond_init(key_my_thread_var_suspend, &var->suspend, NULL);
111}
112
113static void my_thread_destory_thr_mutex(struct st_my_thread_var *var)
114{
115 mysql_mutex_destroy(&var->mutex);
116 mysql_cond_destroy(&var->suspend);
117}
118
119
120/**
121 Re-initialize components initialized early with @c my_thread_global_init.
122 Some mutexes were initialized before the instrumentation.
123 Destroy + create them again, now that the instrumentation
124 is in place.
125 This is safe, since this function() is called before creating new threads,
126 so the mutexes are not in use.
127*/
128void my_thread_global_reinit(void)
129{
130 struct st_my_thread_var *tmp;
131
132 DBUG_ASSERT(my_thread_global_init_done);
133
134#ifdef HAVE_PSI_INTERFACE
135 my_init_mysys_psi_keys();
136#endif
137
138 my_thread_destroy_common_mutex();
139 my_thread_init_common_mutex();
140
141 my_thread_destroy_internal_mutex();
142 my_thread_init_internal_mutex();
143
144 tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys);
145 DBUG_ASSERT(tmp);
146
147 my_thread_destory_thr_mutex(tmp);
148 my_thread_init_thr_mutex(tmp);
149}
150
151/*
152 initialize thread environment
153
154 SYNOPSIS
155 my_thread_global_init()
156
157 RETURN
158 0 ok
159 1 error (Couldn't create THR_KEY_mysys)
160*/
161
162my_bool my_thread_global_init(void)
163{
164 int pth_ret;
165
166 /* Normally this should never be called twice */
167 DBUG_ASSERT(my_thread_global_init_done == 0);
168 if (my_thread_global_init_done)
169 return 0;
170 my_thread_global_init_done= 1;
171
172 /*
173 THR_KEY_mysys is deleted in my_end() as DBUG libraries are using it even
174 after my_thread_global_end() is called.
175 my_thr_key_mysys_exist is used to protect against application like QT
176 that calls my_thread_global_init() + my_thread_global_end() multiple times
177 without calling my_init() + my_end().
178 */
179 if (!my_thr_key_mysys_exists &&
180 (pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
181 {
182 fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
183 return 1;
184 }
185 my_thr_key_mysys_exists= 1;
186
187 /* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */
188 my_thread_init_internal_mutex();
189
190 if (my_thread_init())
191 return 1;
192
193 thd_lib_detected= get_thread_lib();
194
195 my_thread_init_common_mutex();
196
197 return 0;
198}
199
200
201/**
202 End the mysys thread system. Called when ending the last thread
203*/
204
205void my_thread_global_end(void)
206{
207 struct timespec abstime;
208 my_bool all_threads_killed= 1;
209
210 set_timespec(abstime, my_thread_end_wait_time);
211 mysql_mutex_lock(&THR_LOCK_threads);
212 while (THR_thread_count > 0)
213 {
214 int error= mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
215 &abstime);
216 if (error == ETIMEDOUT || error == ETIME)
217 {
218#ifdef HAVE_PTHREAD_KILL
219 /*
220 We shouldn't give an error here, because if we don't have
221 pthread_kill(), programs like mysqld can't ensure that all threads
222 are killed when we enter here.
223 */
224 if (THR_thread_count)
225 fprintf(stderr,
226 "Error in my_thread_global_end(): %d threads didn't exit\n",
227 THR_thread_count);
228#endif
229 all_threads_killed= 0;
230 break;
231 }
232 }
233 mysql_mutex_unlock(&THR_LOCK_threads);
234
235 my_thread_destroy_common_mutex();
236
237 /*
238 Only destroy the mutex & conditions if we don't have other threads around
239 that could use them.
240 */
241 if (all_threads_killed)
242 {
243 my_thread_destroy_internal_mutex();
244 }
245 my_thread_global_init_done= 0;
246}
247
248static my_thread_id thread_id= 0;
249
250/*
251 Allocate thread specific memory for the thread, used by mysys and dbug
252
253 SYNOPSIS
254 my_thread_init()
255
256 NOTES
257 We can't use mutex_locks here if we are using windows as
258 we may have compiled the program with SAFE_MUTEX, in which
259 case the checking of mutex_locks will not work until
260 the pthread_self thread specific variable is initialized.
261
262 This function may called multiple times for a thread, for example
263 if one uses my_init() followed by mysql_server_init().
264
265 RETURN
266 0 ok
267 1 Fatal error; mysys/dbug functions can't be used
268*/
269
270my_bool my_thread_init(void)
271{
272 struct st_my_thread_var *tmp;
273 my_bool error=0;
274
275 if (!my_thread_global_init_done)
276 return 1; /* cannot proceed with uninitialized library */
277
278#ifdef EXTRA_DEBUG_THREADS
279 fprintf(stderr,"my_thread_init(): pthread_self: %p\n", pthread_self());
280#endif
281
282 if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
283 {
284#ifdef EXTRA_DEBUG_THREADS
285 fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
286 (long) pthread_self());
287#endif
288 goto end;
289 }
290
291#ifdef _MSC_VER
292 install_sigabrt_handler();
293#endif
294
295 if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
296 {
297 error= 1;
298 goto end;
299 }
300 pthread_setspecific(THR_KEY_mysys,tmp);
301 tmp->pthread_self= pthread_self();
302 my_thread_init_thr_mutex(tmp);
303
304 tmp->stack_ends_here= (char*)&tmp +
305 STACK_DIRECTION * (long)my_thread_stack_size;
306
307 mysql_mutex_lock(&THR_LOCK_threads);
308 tmp->id= tmp->dbug_id= ++thread_id;
309 ++THR_thread_count;
310 mysql_mutex_unlock(&THR_LOCK_threads);
311 tmp->init= 1;
312#ifndef DBUG_OFF
313 /* Generate unique name for thread */
314 (void) my_thread_name();
315#endif
316
317end:
318 return error;
319}
320
321
322/*
323 Deallocate memory used by the thread for book-keeping
324
325 SYNOPSIS
326 my_thread_end()
327
328 NOTE
329 This may be called multiple times for a thread.
330 This happens for example when one calls 'mysql_server_init()'
331 mysql_server_end() and then ends with a mysql_end().
332*/
333
334void my_thread_end(void)
335{
336 struct st_my_thread_var *tmp;
337 tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
338
339#ifdef EXTRA_DEBUG_THREADS
340 fprintf(stderr,"my_thread_end(): tmp: %p pthread_self: %p thread_id: %ld\n",
341 tmp, pthread_self(), tmp ? (long) tmp->id : 0L);
342#endif
343
344 /*
345 Remove the instrumentation for this thread.
346 This must be done before trashing st_my_thread_var,
347 because the LF_HASH depends on it.
348 */
349 PSI_CALL_delete_current_thread();
350
351 /*
352 We need to disable DBUG early for this thread to ensure that the
353 the mutex calls doesn't enable it again
354 To this we have to both do DBUG_POP() and also reset THR_KEY_mysys
355 as the key is used by DBUG.
356 */
357 DBUG_POP();
358 pthread_setspecific(THR_KEY_mysys,0);
359
360 if (tmp && tmp->init)
361 {
362#if !defined(DBUG_OFF)
363 /* tmp->dbug is allocated inside DBUG library */
364 if (tmp->dbug)
365 {
366 free(tmp->dbug);
367 tmp->dbug=0;
368 }
369#endif
370 my_thread_destory_thr_mutex(tmp);
371
372 /*
373 Decrement counter for number of running threads. We are using this
374 in my_thread_global_end() to wait until all threads have called
375 my_thread_end and thus freed all memory they have allocated in
376 my_thread_init() and DBUG_xxxx
377 */
378 mysql_mutex_lock(&THR_LOCK_threads);
379 DBUG_ASSERT(THR_thread_count != 0);
380 if (--THR_thread_count == 0)
381 mysql_cond_signal(&THR_COND_threads);
382 mysql_mutex_unlock(&THR_LOCK_threads);
383
384 /* Trash variable so that we can detect false accesses to my_thread_var */
385 tmp->init= 2;
386 free(tmp);
387 }
388}
389
390struct st_my_thread_var *_my_thread_var(void)
391{
392 return my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
393}
394
395int set_mysys_var(struct st_my_thread_var *mysys_var)
396{
397 return my_pthread_setspecific_ptr(THR_KEY_mysys, mysys_var);
398}
399
400/****************************************************************************
401 Get name of current thread.
402****************************************************************************/
403
404my_thread_id my_thread_dbug_id()
405{
406 /*
407 We need to do this test as some system thread may not yet have called
408 my_thread_init().
409 */
410 struct st_my_thread_var *tmp= my_thread_var;
411 return tmp ? tmp->dbug_id : 0;
412}
413
414#ifdef DBUG_OFF
415const char *my_thread_name(void)
416{
417 return "no_name";
418}
419
420#else
421
422const char *my_thread_name(void)
423{
424 char name_buff[100];
425 struct st_my_thread_var *tmp=my_thread_var;
426 if (!tmp->name[0])
427 {
428 my_thread_id id= my_thread_dbug_id();
429 sprintf(name_buff,"T@%lu", (ulong) id);
430 strmake_buf(tmp->name, name_buff);
431 }
432 return tmp->name;
433}
434
435/* Return pointer to DBUG for holding current state */
436
437extern void **my_thread_var_dbug()
438{
439 struct st_my_thread_var *tmp;
440 if (!my_thread_global_init_done)
441 return NULL;
442 tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
443 return tmp && tmp->init ? &tmp->dbug : 0;
444}
445#endif /* DBUG_OFF */
446
447/* Return pointer to mutex_in_use */
448
449safe_mutex_t **my_thread_var_mutex_in_use()
450{
451 struct st_my_thread_var *tmp;
452 if (!my_thread_global_init_done)
453 return NULL;
454 tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
455 return tmp ? &tmp->mutex_in_use : 0;
456}
457
458static uint get_thread_lib(void)
459{
460#ifdef _CS_GNU_LIBPTHREAD_VERSION
461 char buff[64];
462
463 confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
464
465 if (!strncasecmp(buff, "NPTL", 4))
466 return THD_LIB_NPTL;
467 if (!strncasecmp(buff, "linuxthreads", 12))
468 return THD_LIB_LT;
469#endif
470 return THD_LIB_OTHER;
471}
472
473#ifdef _WIN32
474/*
475 In Visual Studio 2005 and later, default SIGABRT handler will overwrite
476 any unhandled exception filter set by the application and will try to
477 call JIT debugger. This is not what we want, this we calling __debugbreak
478 to stop in debugger, if process is being debugged or to generate
479 EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
480*/
481
482#if (_MSC_VER >= 1400)
483static void my_sigabrt_handler(int sig)
484{
485 __debugbreak();
486}
487#endif /*_MSC_VER >=1400 */
488
489static void install_sigabrt_handler(void)
490{
491#if (_MSC_VER >=1400)
492 /*abort() should not override our exception filter*/
493 _set_abort_behavior(0,_CALL_REPORTFAULT);
494 signal(SIGABRT,my_sigabrt_handler);
495#endif /* _MSC_VER >=1400 */
496}
497#endif
498
499