From c7fa4a5be885c13689c021bce364041a47ccd890 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 24 Apr 2024 17:56:19 +0300 Subject: Release version 8.0.15+16 Add support for building with MinGW GCC. --- libmysqlclient/mysql/mysys/my_thr_init.cc | 385 ++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 libmysqlclient/mysql/mysys/my_thr_init.cc (limited to 'libmysqlclient/mysql/mysys/my_thr_init.cc') 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 +#include +#ifdef _WIN32 +#include +#endif +#include + +#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 -- cgit v1.1