summaryrefslogtreecommitdiff
path: root/libmysqlclient/mysql/mysys/my_thr_init.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libmysqlclient/mysql/mysys/my_thr_init.cc')
-rw-r--r--libmysqlclient/mysql/mysys/my_thr_init.cc385
1 files changed, 385 insertions, 0 deletions
diff --git a/libmysqlclient/mysql/mysys/my_thr_init.cc b/libmysqlclient/mysql/mysys/my_thr_init.cc
new file mode 100644
index 0000000..ba10464
--- /dev/null
+++ b/libmysqlclient/mysql/mysys/my_thr_init.cc
@@ -0,0 +1,385 @@
+/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2.0,
+ as published by the Free Software Foundation.
+
+ This program is also distributed with certain software (including
+ but not limited to OpenSSL) that is licensed under separate terms,
+ as designated in a particular file or component or in included license
+ documentation. The authors of MySQL hereby grant you an additional
+ permission to link the program and your derivative works with the
+ separately licensed software that they have included with MySQL.
+
+ Without limiting anything contained in the foregoing, this file,
+ which is part of C Driver for MySQL (Connector/C), is also subject to the
+ Universal FOSS Exception, version 1.0, a copy of which can be found at
+ http://oss.oracle.com/licenses/universal-foss-exception.
+
+ 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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/**
+ @file mysys/my_thr_init.cc
+ Functions to handle initialization and allocation of all mysys & debug
+ thread variables.
+*/
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <signal.h>
+#endif
+#include <time.h>
+
+#include "my_dbug.h"
+#include "my_inttypes.h"
+#include "my_loglevel.h"
+#include "my_macros.h"
+#include "my_psi_config.h"
+#include "my_sys.h"
+#include "my_systime.h"
+#include "my_thread.h"
+#include "my_thread_local.h"
+#include "mysql/psi/mysql_cond.h"
+#include "mysql/psi/mysql_mutex.h"
+#include "mysql/psi/mysql_thread.h"
+#include "mysql/psi/psi_thread.h"
+#include "mysys/mysys_priv.h"
+#include "mysys_err.h"
+#include "thr_mutex.h"
+
+static bool my_thread_global_init_done = false;
+#ifndef DBUG_OFF
+static uint THR_thread_count = 0;
+static uint my_thread_end_wait_time = 5;
+static my_thread_id thread_id = 0;
+struct st_my_thread_var;
+static thread_local st_my_thread_var *THR_mysys = nullptr;
+#endif
+static thread_local int THR_myerrno = 0;
+#ifdef _WIN32
+static thread_local int THR_winerrno = 0;
+#endif
+
+mysql_mutex_t THR_LOCK_myisam_mmap;
+mysql_mutex_t THR_LOCK_myisam;
+mysql_mutex_t THR_LOCK_heap;
+mysql_mutex_t THR_LOCK_malloc;
+mysql_mutex_t THR_LOCK_open;
+mysql_mutex_t THR_LOCK_lock;
+mysql_mutex_t THR_LOCK_net;
+mysql_mutex_t THR_LOCK_charset;
+#ifndef DBUG_OFF
+mysql_mutex_t THR_LOCK_threads;
+mysql_cond_t THR_COND_threads;
+#endif
+
+#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+native_mutexattr_t my_fast_mutexattr;
+#endif
+#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+native_mutexattr_t my_errorcheck_mutexattr;
+#endif
+#ifdef _WIN32
+static void install_sigabrt_handler();
+#endif
+
+#ifndef DBUG_OFF
+struct st_my_thread_var {
+ my_thread_id id;
+ struct CODE_STATE *dbug;
+};
+
+static struct st_my_thread_var *mysys_thread_var() { return THR_mysys; }
+
+static int set_mysys_thread_var(struct st_my_thread_var *mysys_var) {
+ THR_mysys = mysys_var;
+ return 0;
+}
+#endif
+
+/**
+ Re-initialize components initialized early with @c my_thread_global_init.
+ Some mutexes were initialized before the instrumentation.
+ Destroy + create them again, now that the instrumentation
+ is in place.
+ This is safe, since this function() is called before creating new threads,
+ so the mutexes are not in use.
+*/
+
+void my_thread_global_reinit() {
+ DBUG_ASSERT(my_thread_global_init_done);
+
+#ifdef HAVE_PSI_INTERFACE
+ my_init_mysys_psi_keys();
+#endif
+
+ mysql_mutex_destroy(&THR_LOCK_heap);
+ mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
+
+ mysql_mutex_destroy(&THR_LOCK_net);
+ mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
+
+ mysql_mutex_destroy(&THR_LOCK_myisam);
+ mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
+
+ mysql_mutex_destroy(&THR_LOCK_malloc);
+ mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
+
+ mysql_mutex_destroy(&THR_LOCK_open);
+ mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
+
+ mysql_mutex_destroy(&THR_LOCK_charset);
+ mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
+
+#ifndef DBUG_OFF
+ mysql_mutex_destroy(&THR_LOCK_threads);
+ mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
+
+ mysql_cond_destroy(&THR_COND_threads);
+ mysql_cond_init(key_THR_COND_threads, &THR_COND_threads);
+#endif
+}
+
+/**
+ initialize thread environment
+
+ @retval false ok
+ @retval true error
+*/
+
+bool my_thread_global_init() {
+ if (my_thread_global_init_done) return false;
+ my_thread_global_init_done = true;
+
+#if defined(SAFE_MUTEX)
+ safe_mutex_global_init(); /* Must be called early */
+#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
+
+ mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
+ mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap,
+ MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
+#ifndef DBUG_OFF
+ mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_THR_COND_threads, &THR_COND_threads);
+#endif
+
+ return false;
+}
+
+void my_thread_global_end() {
+#ifndef DBUG_OFF
+ struct timespec abstime;
+ bool all_threads_killed = true;
+
+ set_timespec(&abstime, my_thread_end_wait_time);
+ mysql_mutex_lock(&THR_LOCK_threads);
+ while (THR_thread_count > 0) {
+ int error =
+ mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads, &abstime);
+ if (is_timeout(error)) {
+#ifndef _WIN32
+ /*
+ We shouldn't give an error here, because if we don't have
+ pthread_kill(), programs like mysqld can't ensure that all threads
+ are killed when we enter here.
+ */
+ if (THR_thread_count) /* purecov: begin inspected */
+ my_message_local(ERROR_LEVEL, EE_FAILED_TO_KILL_ALL_THREADS,
+ THR_thread_count);
+ /* purecov: end */
+#endif
+ all_threads_killed = false;
+ break;
+ }
+ }
+ mysql_mutex_unlock(&THR_LOCK_threads);
+#endif
+
+#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
+ mysql_mutex_destroy(&THR_LOCK_malloc);
+ mysql_mutex_destroy(&THR_LOCK_open);
+ mysql_mutex_destroy(&THR_LOCK_lock);
+ mysql_mutex_destroy(&THR_LOCK_myisam);
+ mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
+ mysql_mutex_destroy(&THR_LOCK_heap);
+ mysql_mutex_destroy(&THR_LOCK_net);
+ mysql_mutex_destroy(&THR_LOCK_charset);
+#ifndef DBUG_OFF
+ if (all_threads_killed) {
+ mysql_mutex_destroy(&THR_LOCK_threads);
+ mysql_cond_destroy(&THR_COND_threads);
+ }
+#endif
+
+ my_thread_global_init_done = false;
+}
+
+/**
+ Allocate thread specific memory for the thread, used by mysys and dbug
+
+ @note This function may called multiple times for a thread, for example
+ if one uses my_init() followed by mysql_server_init().
+
+ @retval false ok
+ @retval true Fatal error; mysys/dbug functions can't be used
+*/
+
+extern "C" bool my_thread_init() {
+#ifndef DBUG_OFF
+ struct st_my_thread_var *tmp;
+#endif
+
+ if (!my_thread_global_init_done)
+ return true; /* cannot proceed with unintialized library */
+
+#ifdef _WIN32
+ install_sigabrt_handler();
+#endif
+
+#ifndef DBUG_OFF
+ if (mysys_thread_var()) return false;
+
+ if (!(tmp = (struct st_my_thread_var *)calloc(1, sizeof(*tmp)))) return true;
+
+ mysql_mutex_lock(&THR_LOCK_threads);
+ tmp->id = ++thread_id;
+ ++THR_thread_count;
+ mysql_mutex_unlock(&THR_LOCK_threads);
+ set_mysys_thread_var(tmp);
+#endif
+
+ return false;
+}
+
+/**
+ Deallocate memory used by the thread for book-keeping
+
+ @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().
+*/
+
+extern "C" void my_thread_end() {
+#ifndef DBUG_OFF
+ struct st_my_thread_var *tmp = mysys_thread_var();
+#endif
+
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ /*
+ Remove the instrumentation for this thread.
+ This must be done before trashing st_my_thread_var,
+ because the LF_HASH depends on it.
+ */
+ PSI_THREAD_CALL(delete_current_thread)();
+#endif
+
+#if !defined(DBUG_OFF)
+ if (tmp) {
+ /* tmp->dbug is allocated inside DBUG library */
+ if (tmp->dbug) {
+ DBUG_POP();
+ free(tmp->dbug);
+ tmp->dbug = NULL;
+ }
+ free(tmp);
+
+ /*
+ 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
+ */
+ mysql_mutex_lock(&THR_LOCK_threads);
+ DBUG_ASSERT(THR_thread_count != 0);
+ if (--THR_thread_count == 0) mysql_cond_signal(&THR_COND_threads);
+ mysql_mutex_unlock(&THR_LOCK_threads);
+ }
+ set_mysys_thread_var(NULL);
+#endif
+}
+
+int my_errno() { return THR_myerrno; }
+
+void set_my_errno(int my_errno) { THR_myerrno = my_errno; }
+
+#ifdef _WIN32
+int thr_winerr() { return THR_winerrno; }
+
+void set_thr_winerr(int winerr) { THR_winerrno = winerr; }
+#endif
+
+#ifndef DBUG_OFF
+my_thread_id my_thread_var_id() { return mysys_thread_var()->id; }
+
+void set_my_thread_var_id(my_thread_id id) { mysys_thread_var()->id = id; }
+
+CODE_STATE **my_thread_var_dbug() {
+ struct st_my_thread_var *tmp = THR_mysys;
+ return tmp ? &tmp->dbug : NULL;
+}
+#endif /* DBUG_OFF */
+
+#ifdef _WIN32
+/*
+ In Visual Studio 2005 and later, default SIGABRT handler will overwrite
+ any unhandled exception filter set by the application and will try to
+ call JIT debugger. This is not what we want, this we calling __debugbreak
+ to stop in debugger, if process is being debugged or to generate
+ EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
+*/
+
+static void my_sigabrt_handler(int sig) { __debugbreak(); }
+
+static void install_sigabrt_handler() {
+ /*abort() should not override our exception filter*/
+
+ // Requires msvcrt90 or later but forcing this in a library is
+ // probably not a good idea.
+ //
+#ifndef __MINGW32__
+ _set_abort_behavior(0, _CALL_REPORTFAULT);
+#endif
+ signal(SIGABRT, my_sigabrt_handler);
+}
+#endif