mariadb/mysys/my_thr_init.c
unknown b59217ebbb Slow query log to file now displays queries with microsecond precission
--long-query-time is now given in seconds with microseconds as decimals
--min_examined_row_limit added for slow query log
long_query_time user variable is now double with 6 decimals
Added functions to get time in microseconds
Added faster time() functions for system that has gethrtime()  (Solaris)
We now do less time() calls.
Added field->in_read_set() and field->in_write_set() for easier field manipulation by handlers
set_var.cc and my_getopt() can now handle DOUBLE variables.
All time() calls changed to my_time()
my_time() now does retry's if time() call fails.
Added debug function for stopping in mysql_admin_table() when tables are locked
Some trivial function and struct variable renames to avoid merge errors.
Fixed compiler warnings
Initialization of some time variables on windows moved to my_init() 


include/my_getopt.h:
  Added support for double arguments
include/my_sys.h:
  Fixed wrong type to packfrm()
  Added new my_time functions
include/mysql/plugin.h:
  Added support for DOUBLE
libmysql/CMakeLists.txt:
  Added new time functions
libmysql/Makefile.shared:
  Added new time functions
mysql-test/r/variables.result:
  Testing of long_query_time
mysql-test/t/variables.test:
  Testing of long_query_time
mysys/charset.c:
  Fixed compiler warnings
mysys/default_modify.c:
  Fixed compiler warnings
mysys/hash.c:
  Fixed compiler warnings
mysys/mf_getdate.c:
  Use my_time()
mysys/mf_iocache2.c:
  Fixed compiler warnings
mysys/mf_pack.c:
  Fixed compiler warnings
mysys/mf_path.c:
  Fixed compiler warnings
mysys/my_append.c:
  Fixed compiler warnings
mysys/my_compress.c:
  Fixed compiler warnings
mysys/my_copy.c:
  Fixed compiler warnings
mysys/my_gethwaddr.c:
  Fixed compiler warnings
mysys/my_getopt.c:
  Added support for double arguments
mysys/my_getsystime.c:
  Added functions to get time in microseconds.
  Added faster time() functions for system that has gethrtime()  (Solaris)
  Moved windows initialization code to my_init()
mysys/my_init.c:
  Added initializing of variables needed for windows time functions
mysys/my_static.c:
  Added variables needed for windows time functions
mysys/my_static.h:
  Added variables needed for windows time functions
mysys/my_thr_init.c:
  Added THR_LOCK_time, used for faster my_time()
mysys/mysys_priv.h:
  Added THR_LOCK_time, used for faster my_time()
mysys/thr_alarm.c:
  time() -> my_time()
sql/event_data_objects.cc:
  end_time() -> set_current_time()
sql/event_queue.cc:
  end_time() -> set_current_time()
sql/event_scheduler.cc:
  Fixed compiler warnings
sql/field.h:
  Added field->in_read_set() and field->in_write_set() for easier field manipulation by handlers
sql/item.h:
  Added decimal to Item_float(double)
sql/item_cmpfunc.h:
  Added decimal to Item_float(double)
sql/item_timefunc.cc:
  time() -> my_time()
sql/item_xmlfunc.cc:
  Fixed compiler warning
sql/lock.cc:
  lock_time() -> set_time_after_lock()
sql/log.cc:
  Timing in slow query log to file is now done in microseconds
  Changed some while() loops to for() loops.
  Fixed indentation
  time() -> my_time()
sql/log.h:
  Slow query logging is now done based on microseconds
sql/log_event.cc:
  time() -> my_time()
  Fixed arguments to new Item_float()
sql/mysql_priv.h:
  Fixed compiler warnings
  Added opt_log_slow_slave_statements
sql/mysqld.cc:
  Added --log_slow_slave_statements and --min_examined_row_limit
  --long-query-time now takes a double argument with microsecond resolution
  Don't write shutdown message when using --help
  Removed not needed \n
  Thread create time and connect time is now done in microseconds
  time() -> my_time()
  Avoid some time() calls
sql/net_serv.cc:
  Fixed compiler warnings
sql/parse_file.cc:
  time() -> my_time()
sql/set_var.cc:
  Added support for DOUBLE variables
  Added support for variables that are given in seconds with microsecond resolution
sql/set_var.h:
  Added support for variables that are given in seconds with microsecond resolution
sql/slave.cc:
  Allow logging of slave queries to slow query log if 'opt_log_slow_slave_statements' is given
  time() -> my_time()
sql/sql_cache.h:
  Fixed compiler warning()
sql/sql_class.cc:
  Initialize new THD variables
sql/sql_class.h:
  long_query_time is now in microseconds
  Added min_examined_row_limit
  Reordered some THD elements for higher efficency
  Added timers in microseconds (connect_utime, thr_create_utime, start_utime and utime_after_lock)
  Start of query is now recorded both in seconds and in microseconds.
  Following renames was made for more clarity and avoid merge problems from earlier versions:
  connect_time -> connect_utime
  thr_create_time -> thr_create_utime
  end_time()  -> set_current_time()
  lock_time() -> set_time_after_lock()
  
  Added THD::start_utime, which is start of query in microseconds from some arbitary time
  Added function THD::current_utime()
  
  Removed safe_time() as retry's are handled in my_time()
sql/sql_connect.cc:
  User resources are now using microsecond resolution
sql/sql_insert.cc:
  end_time() -> set_current_time()
sql-common/client.c:
  time() -> my_time()
sql/sql_parse.cc:
  Testing if we should print to slow_query_log() is now done with microsecond precission.
  If min_examined_row_limit is given, only log queries to slow query log that has examined more rows than this.
sql/sql_select.cc:
  Simplify code now that Item_float() takes decimals as argument
sql/sql_show.cc:
  time() -> my_time()
  Added support for SYS_DOUBLE
sql/sql_table.cc:
  Added debug function for stopping in mysql_admin_table() when tables are locked
sql/structs.h:
  intime -> reset_utime
2007-07-30 11:33:50 +03:00

423 lines
11 KiB
C

/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Functions to handle initializating and allocationg of all mysys & debug
thread variables.
*/
#include "mysys_priv.h"
#include <m_string.h>
#include <signal.h>
#ifdef THREAD
#ifdef USE_TLS
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
#else
pthread_key(struct st_my_thread_var, THR_KEY_mysys);
#endif /* USE_TLS */
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
pthread_cond_t THR_COND_threads;
uint THR_thread_count= 0;
uint my_thread_end_wait_time= 5;
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_t LOCK_localtime_r;
#endif
#ifndef HAVE_GETHOSTBYNAME_R
pthread_mutex_t LOCK_gethostbyname_r;
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
pthread_mutexattr_t my_fast_mutexattr;
#endif
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
pthread_mutexattr_t my_errorcheck_mutexattr;
#endif
#ifdef NPTL_PTHREAD_EXIT_BUG /* see my_pthread.h */
/*
Dummy thread spawned in my_thread_global_init() below to avoid
race conditions in NPTL pthread_exit code.
*/
static pthread_handler_t
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
{
/* Do nothing! */
pthread_exit(0);
return 0;
}
#endif
static uint get_thread_lib(void);
/*
initialize thread environment
SYNOPSIS
my_thread_global_init()
RETURN
0 ok
1 error (Couldn't create THR_KEY_mysys)
*/
my_bool my_thread_global_init(void)
{
int pth_ret;
thd_lib_detected= get_thread_lib();
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
{
fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
return 1;
}
#ifdef NPTL_PTHREAD_EXIT_BUG
/*
BUG#24507: Race conditions inside current NPTL pthread_exit()
implementation.
To avoid a possible segmentation fault during concurrent
executions of pthread_exit(), a dummy thread is spawned which
initializes internal variables of pthread lib. See bug description
for a full explanation.
TODO: Remove this code when fixed versions of glibc6 are in common
use.
*/
if (thd_lib_detected == THD_LIB_NPTL)
{
pthread_t dummy_thread;
pthread_attr_t dummy_thread_attr;
pthread_attr_init(&dummy_thread_attr);
pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
pthread_create(&dummy_thread,&dummy_thread_attr,
nptl_pthread_exit_hack_handler, NULL);
}
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
/*
Set mutex type to "fast" a.k.a "adaptive"
In this case the thread may steal the mutex from some other thread
that is waiting for the same mutex. This will save us some
context switches but may cause a thread to 'starve forever' while
waiting for the mutex (not likely if the code within the mutex is
short).
*/
pthread_mutexattr_init(&my_fast_mutexattr);
pthread_mutexattr_settype(&my_fast_mutexattr,
PTHREAD_MUTEX_ADAPTIVE_NP);
#endif
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
/*
Set mutex type to "errorcheck"
*/
pthread_mutexattr_init(&my_errorcheck_mutexattr);
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
PTHREAD_MUTEX_ERRORCHECK);
#endif
pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
pthread_cond_init(&THR_COND_threads, NULL);
#if defined( __WIN__) || defined(OS2)
win_pthread_init();
#endif
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
#endif
#ifndef HAVE_GETHOSTBYNAME_R
pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
#endif
if (my_thread_init())
{
my_thread_global_end(); /* Clean up */
return 1;
}
return 0;
}
void my_thread_global_end(void)
{
struct timespec abstime;
my_bool all_threads_killed= 1;
set_timespec(abstime, my_thread_end_wait_time);
pthread_mutex_lock(&THR_LOCK_threads);
while (THR_thread_count > 0)
{
int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
&abstime);
if (error == ETIMEDOUT || error == ETIME)
{
if (THR_thread_count)
fprintf(stderr,
"Error in my_thread_global_end(): %d threads didn't exit\n",
THR_thread_count);
all_threads_killed= 0;
break;
}
}
pthread_mutex_unlock(&THR_LOCK_threads);
pthread_key_delete(THR_KEY_mysys);
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
pthread_mutexattr_destroy(&my_fast_mutexattr);
#endif
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
#endif
pthread_mutex_destroy(&THR_LOCK_malloc);
pthread_mutex_destroy(&THR_LOCK_open);
pthread_mutex_destroy(&THR_LOCK_lock);
pthread_mutex_destroy(&THR_LOCK_isam);
pthread_mutex_destroy(&THR_LOCK_myisam);
pthread_mutex_destroy(&THR_LOCK_heap);
pthread_mutex_destroy(&THR_LOCK_net);
pthread_mutex_destroy(&THR_LOCK_time);
pthread_mutex_destroy(&THR_LOCK_charset);
if (all_threads_killed)
{
pthread_mutex_destroy(&THR_LOCK_threads);
pthread_cond_destroy (&THR_COND_threads);
}
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_destroy(&LOCK_localtime_r);
#endif
#ifndef HAVE_GETHOSTBYNAME_R
pthread_mutex_destroy(&LOCK_gethostbyname_r);
#endif
}
static my_thread_id thread_id= 0;
/*
Allocate thread specific memory for the thread, used by mysys and dbug
SYNOPSIS
my_thread_init()
NOTES
We can't use mutex_locks here if we are using windows as
we may have compiled the program with SAFE_MUTEX, in which
case the checking of mutex_locks will not work until
the pthread_self thread specific variable is initialized.
This function may called multiple times for a thread, for example
if one uses my_init() followed by mysql_server_init().
RETURN
0 ok
1 Fatal error; mysys/dbug functions can't be used
*/
my_bool my_thread_init(void)
{
struct st_my_thread_var *tmp;
my_bool error=0;
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
(ulong) pthread_self());
#endif
#if !defined(__WIN__) || defined(USE_TLS)
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
{
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
(long) pthread_self());
#endif
goto end;
}
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
{
error= 1;
goto end;
}
pthread_setspecific(THR_KEY_mysys,tmp);
#else /* defined(__WIN__) && !(defined(USE_TLS) */
/*
Skip initialization if the thread specific variable is already initialized
*/
if (THR_KEY_mysys.id)
goto end;
tmp= &THR_KEY_mysys;
#endif
#if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
tmp->pthread_self= (pthread_t) getpid();
#else
tmp->pthread_self= pthread_self();
#endif
pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&tmp->suspend, NULL);
tmp->init= 1;
pthread_mutex_lock(&THR_LOCK_threads);
tmp->id= ++thread_id;
++THR_thread_count;
pthread_mutex_unlock(&THR_LOCK_threads);
#ifndef DBUG_OFF
/* Generate unique name for thread */
(void) my_thread_name();
#endif
end:
return error;
}
/*
Deallocate memory used by the thread for book-keeping
SYNOPSIS
my_thread_end()
NOTE
This may be called multiple times for a thread.
This happens for example when one calls 'mysql_server_init()'
mysql_server_end() and then ends with a mysql_end().
*/
void my_thread_end(void)
{
struct st_my_thread_var *tmp;
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
#endif
if (tmp && tmp->init)
{
#if !defined(DBUG_OFF)
/* tmp->dbug is allocated inside DBUG library */
if (tmp->dbug)
{
free(tmp->dbug);
tmp->dbug=0;
}
#endif
#if !defined(__bsdi__) && !defined(__OpenBSD__)
/* bsdi and openbsd 3.5 dumps core here */
pthread_cond_destroy(&tmp->suspend);
#endif
pthread_mutex_destroy(&tmp->mutex);
#if !defined(__WIN__) || defined(USE_TLS)
free(tmp);
#else
tmp->init= 0;
#endif
/*
Decrement counter for number of running threads. We are using this
in my_thread_global_end() to wait until all threads have called
my_thread_end and thus freed all memory they have allocated in
my_thread_init() and DBUG_xxxx
*/
pthread_mutex_lock(&THR_LOCK_threads);
DBUG_ASSERT(THR_thread_count != 0);
if (--THR_thread_count == 0)
pthread_cond_signal(&THR_COND_threads);
pthread_mutex_unlock(&THR_LOCK_threads);
}
/* The following free has to be done, even if my_thread_var() is 0 */
#if !defined(__WIN__) || defined(USE_TLS)
pthread_setspecific(THR_KEY_mysys,0);
#endif
}
struct st_my_thread_var *_my_thread_var(void)
{
struct st_my_thread_var *tmp=
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
#if defined(USE_TLS)
/* This can only happen in a .DLL */
if (!tmp)
{
my_thread_init();
tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
}
#endif
return tmp;
}
/****************************************************************************
Get name of current thread.
****************************************************************************/
my_thread_id my_thread_dbug_id()
{
return my_thread_var->id;
}
#ifdef DBUG_OFF
const char *my_thread_name(void)
{
return "no_name";
}
#else
const char *my_thread_name(void)
{
char name_buff[100];
struct st_my_thread_var *tmp=my_thread_var;
if (!tmp->name[0])
{
my_thread_id id= my_thread_dbug_id();
sprintf(name_buff,"T@%lu", (ulong) id);
strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
}
return tmp->name;
}
#endif /* DBUG_OFF */
static uint get_thread_lib(void)
{
#ifdef _CS_GNU_LIBPTHREAD_VERSION
char buff[64];
confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
if (!strncasecmp(buff, "NPTL", 4))
return THD_LIB_NPTL;
if (!strncasecmp(buff, "linuxthreads", 12))
return THD_LIB_LT;
#endif
return THD_LIB_OTHER;
}
#endif /* THREAD */