Commit 54143350 authored by Dmitry Shulga's avatar Dmitry Shulga

MDEV-31871: maria-install-db fails on MacOS

mariadb-install crashes on start when the static variable debug_sync_global
of the class st_debug_sync_globals is initialized by constructor.

Definition of the class st_debug_sync_globals has a data member of the type
Hash_set whose implementation depends on thread-specific data associated
with the key THD_KEY_mysys. This dependency results from constructor of
the class Hash_set that runs my_hash_init2() which in turn invokes my_malloc.
The thread-specific data value associated with the key THD_KEY_mysys is used
by the function sf_malloc to get id of the current thread. The key
THD_KEY_mysys is defined as static variable at my_thr_init.c initialized
with the value -1. Proper initialization of the key THD_KEY_mysys is done
with the library call pthread_key_create but it happens at the  my_init()
that called much later after the first time the THD_KEY_mysys() has been
invoked. In according with Single Unix Specification, the effect of calling
pthread_setspecific() or pthread_getspecific() with a key value not obtained
from pthread_key_create() is undefined. That is the reason why mariadb-install
crashes on MacOS.

To fix the issue, the static variable debug_sync_global is converted to
a pointer to the class st_debug_sync_globals and its instantiation is done
explicitly at the function debug_sync_init() that is called at right time.

This is the follow-up patch to the commits
  8885225d
  f6ecadfe
where was introduced a statically instantiated object debug_sync_global of
the structure st_debug_sync_globals and the key THR_KEY_mysys for this
thread-specific data was initialized with the value -1.
parent 52e70162
...@@ -163,7 +163,7 @@ struct st_debug_sync_globals ...@@ -163,7 +163,7 @@ struct st_debug_sync_globals
} }
}; };
static st_debug_sync_globals debug_sync_global; /* All globals in one object */ static st_debug_sync_globals *debug_sync_global; /* All globals in one object */
/** /**
Callbacks from C files. Callbacks from C files.
...@@ -237,16 +237,19 @@ int debug_sync_init(void) ...@@ -237,16 +237,19 @@ int debug_sync_init(void)
init_debug_sync_psi_keys(); init_debug_sync_psi_keys();
#endif #endif
if (!debug_sync_global)
debug_sync_global= new st_debug_sync_globals();
if (opt_debug_sync_timeout) if (opt_debug_sync_timeout)
{ {
int rc; int rc;
/* Initialize the global variables. */ /* Initialize the global variables. */
debug_sync_global.clear_set(); debug_sync_global->clear_set();
if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond, if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond,
&debug_sync_global.ds_cond, NULL)) || &debug_sync_global->ds_cond, NULL)) ||
(rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex, (rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex,
&debug_sync_global.ds_mutex, &debug_sync_global->ds_mutex,
MY_MUTEX_INIT_FAST))) MY_MUTEX_INIT_FAST)))
DBUG_RETURN(rc); /* purecov: inspected */ DBUG_RETURN(rc); /* purecov: inspected */
...@@ -276,21 +279,25 @@ void debug_sync_end(void) ...@@ -276,21 +279,25 @@ void debug_sync_end(void)
debug_sync_C_callback_ptr= NULL; debug_sync_C_callback_ptr= NULL;
/* Destroy the global variables. */ /* Destroy the global variables. */
debug_sync_global.clear_set(); debug_sync_global->clear_set();
mysql_cond_destroy(&debug_sync_global.ds_cond); mysql_cond_destroy(&debug_sync_global->ds_cond);
mysql_mutex_destroy(&debug_sync_global.ds_mutex); mysql_mutex_destroy(&debug_sync_global->ds_mutex);
/* Print statistics. */ /* Print statistics. */
{ {
sql_print_information("Debug sync points hit: %lld", sql_print_information("Debug sync points hit: %lld",
debug_sync_global.dsp_hits); debug_sync_global->dsp_hits);
sql_print_information("Debug sync points executed: %lld", sql_print_information("Debug sync points executed: %lld",
debug_sync_global.dsp_executed); debug_sync_global->dsp_executed);
sql_print_information("Debug sync points max active per thread: %lld", sql_print_information("Debug sync points max active per thread: %lld",
debug_sync_global.dsp_max_active); debug_sync_global->dsp_max_active);
} }
} }
delete debug_sync_global;
/* Just to be safe */
debug_sync_global= NULL;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -360,11 +367,11 @@ void debug_sync_init_thread(THD *thd) ...@@ -360,11 +367,11 @@ void debug_sync_init_thread(THD *thd)
*/ */
static const char *get_signal_set_as_string() static const char *get_signal_set_as_string()
{ {
mysql_mutex_assert_owner(&debug_sync_global.ds_mutex); mysql_mutex_assert_owner(&debug_sync_global->ds_mutex);
size_t req_size= 1; // In case of empty set for the end '\0' char. size_t req_size= 1; // In case of empty set for the end '\0' char.
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++) for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
req_size+= debug_sync_global.ds_signal_set.at(i)->length + 1; req_size+= debug_sync_global->ds_signal_set.at(i)->length + 1;
char *buf= (char *) my_malloc(PSI_NOT_INSTRUMENTED, req_size, MYF(0)); char *buf= (char *) my_malloc(PSI_NOT_INSTRUMENTED, req_size, MYF(0));
if (!buf) if (!buf)
...@@ -372,11 +379,11 @@ static const char *get_signal_set_as_string() ...@@ -372,11 +379,11 @@ static const char *get_signal_set_as_string()
memset(buf, '\0', req_size); memset(buf, '\0', req_size);
char *cur_pos= buf; char *cur_pos= buf;
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++) for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
{ {
const LEX_CSTRING *signal= debug_sync_global.ds_signal_set.at(i); const LEX_CSTRING *signal= debug_sync_global->ds_signal_set.at(i);
memcpy(cur_pos, signal->str, signal->length); memcpy(cur_pos, signal->str, signal->length);
if (i != debug_sync_global.ds_signal_set.size() - 1) if (i != debug_sync_global->ds_signal_set.size() - 1)
cur_pos[signal->length]= ','; cur_pos[signal->length]= ',';
else else
cur_pos[signal->length] = '\0'; cur_pos[signal->length] = '\0';
...@@ -415,12 +422,12 @@ void debug_sync_end_thread(THD *thd) ...@@ -415,12 +422,12 @@ void debug_sync_end_thread(THD *thd)
} }
/* Statistics. */ /* Statistics. */
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global->ds_mutex);
debug_sync_global.dsp_hits+= ds_control->dsp_hits; debug_sync_global->dsp_hits+= ds_control->dsp_hits;
debug_sync_global.dsp_executed+= ds_control->dsp_executed; debug_sync_global->dsp_executed+= ds_control->dsp_executed;
if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active) if (debug_sync_global->dsp_max_active < ds_control->dsp_max_active)
debug_sync_global.dsp_max_active= ds_control->dsp_max_active; debug_sync_global->dsp_max_active= ds_control->dsp_max_active;
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global->ds_mutex);
my_free(ds_control); my_free(ds_control);
thd->debug_sync_control= NULL; thd->debug_sync_control= NULL;
...@@ -668,9 +675,9 @@ static void debug_sync_reset(THD *thd) ...@@ -668,9 +675,9 @@ static void debug_sync_reset(THD *thd)
ds_control->ds_active= 0; ds_control->ds_active= 0;
/* Clear the global signal. */ /* Clear the global signal. */
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global->ds_mutex);
debug_sync_global.clear_set(); debug_sync_global->clear_set();
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global->ds_mutex);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1454,14 +1461,14 @@ uchar *debug_sync_value_ptr(THD *thd) ...@@ -1454,14 +1461,14 @@ uchar *debug_sync_value_ptr(THD *thd)
static const char on[]= "ON - current signals: '"; static const char on[]= "ON - current signals: '";
// Ensure exclusive access to debug_sync_global.ds_signal // Ensure exclusive access to debug_sync_global.ds_signal
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global->ds_mutex);
size_t lgt= sizeof(on) + 1; /* +1 as we'll have to append ' at the end. */ size_t lgt= sizeof(on) + 1; /* +1 as we'll have to append ' at the end. */
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++) for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
{ {
/* Assume each signal is separated by a comma, hence +1. */ /* Assume each signal is separated by a comma, hence +1. */
lgt+= debug_sync_global.ds_signal_set.at(i)->length + 1; lgt+= debug_sync_global->ds_signal_set.at(i)->length + 1;
} }
char *vend; char *vend;
...@@ -1471,18 +1478,18 @@ uchar *debug_sync_value_ptr(THD *thd) ...@@ -1471,18 +1478,18 @@ uchar *debug_sync_value_ptr(THD *thd)
{ {
vend= value + lgt - 1; /* reserve space for '\0'. */ vend= value + lgt - 1; /* reserve space for '\0'. */
vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on)); vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on));
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++) for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
{ {
const LEX_CSTRING *s= debug_sync_global.ds_signal_set.at(i); const LEX_CSTRING *s= debug_sync_global->ds_signal_set.at(i);
vptr= debug_sync_bmove_len(vptr, vend, s->str, s->length); vptr= debug_sync_bmove_len(vptr, vend, s->str, s->length);
if (i != debug_sync_global.ds_signal_set.size() - 1) if (i != debug_sync_global->ds_signal_set.size() - 1)
*(vptr++)= ','; *(vptr++)= ',';
} }
DBUG_ASSERT(vptr < vend); DBUG_ASSERT(vptr < vend);
*(vptr++)= '\''; *(vptr++)= '\'';
*vptr= '\0'; /* We have one byte reserved for the worst case. */ *vptr= '\0'; /* We have one byte reserved for the worst case. */
} }
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global->ds_mutex);
} }
else else
{ {
...@@ -1554,7 +1561,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1554,7 +1561,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
threads just reads an old cached version of the signal. threads just reads an old cached version of the signal.
*/ */
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global->ds_mutex);
if (action->signal.length()) if (action->signal.length())
{ {
...@@ -1566,15 +1573,15 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1566,15 +1573,15 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
variable for each one. */ variable for each one. */
while (!error && (pos= action->signal.strstr(",", 1, offset)) > 0) while (!error && (pos= action->signal.strstr(",", 1, offset)) > 0)
{ {
error= debug_sync_global.set_signal(action->signal.ptr() + offset, error= debug_sync_global->set_signal(action->signal.ptr() + offset,
pos - offset); pos - offset);
offset= pos + 1; offset= pos + 1;
} }
if (error || if (error ||
/* The last signal in the list. */ /* The last signal in the list. */
debug_sync_global.set_signal(action->signal.ptr() + offset, debug_sync_global->set_signal(action->signal.ptr() + offset,
action->signal.length() - offset)) action->signal.length() - offset))
{ {
/* /*
Error is reported by my_malloc(). Error is reported by my_malloc().
...@@ -1583,7 +1590,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1583,7 +1590,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
debug_sync_emergency_disable(); /* purecov: tested */ debug_sync_emergency_disable(); /* purecov: tested */
} }
/* Wake threads waiting in a sync point. */ /* Wake threads waiting in a sync point. */
mysql_cond_broadcast(&debug_sync_global.ds_cond); mysql_cond_broadcast(&debug_sync_global->ds_cond);
DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'", DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'",
sig_emit, dsp_name)); sig_emit, dsp_name));
} /* end if (action->signal.length()) */ } /* end if (action->signal.length()) */
...@@ -1610,8 +1617,8 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1610,8 +1617,8 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
old_mutex= thd->mysys_var->current_mutex; old_mutex= thd->mysys_var->current_mutex;
old_cond= thd->mysys_var->current_cond; old_cond= thd->mysys_var->current_cond;
restore_current_mutex = true; restore_current_mutex = true;
thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex; thd->mysys_var->current_mutex= &debug_sync_global->ds_mutex;
thd->mysys_var->current_cond= &debug_sync_global.ds_cond; thd->mysys_var->current_cond= &debug_sync_global->ds_cond;
} }
else else
restore_current_mutex = false; restore_current_mutex = false;
...@@ -1640,13 +1647,13 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1640,13 +1647,13 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
The facility can become disabled when some thread cannot get The facility can become disabled when some thread cannot get
the required dynamic memory allocated. the required dynamic memory allocated.
*/ */
while (!debug_sync_global.is_signalled(action->wait_for.ptr(), while (!debug_sync_global->is_signalled(action->wait_for.ptr(),
action->wait_for.length()) && action->wait_for.length()) &&
!(thd->killed & KILL_HARD_BIT) && !(thd->killed & KILL_HARD_BIT) &&
opt_debug_sync_timeout) opt_debug_sync_timeout)
{ {
error= mysql_cond_timedwait(&debug_sync_global.ds_cond, error= mysql_cond_timedwait(&debug_sync_global->ds_cond,
&debug_sync_global.ds_mutex, &debug_sync_global->ds_mutex,
&abstime); &abstime);
// TODO turn this into a for loop printing. // TODO turn this into a for loop printing.
DBUG_EXECUTE("debug_sync", { DBUG_EXECUTE("debug_sync", {
...@@ -1668,7 +1675,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1668,7 +1675,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
} }
if (action->clear_event) if (action->clear_event)
debug_sync_global.clear_signal(action->wait_for); debug_sync_global->clear_signal(action->wait_for);
DBUG_EXECUTE("debug_sync_exec", DBUG_EXECUTE("debug_sync_exec",
if (thd->killed) if (thd->killed)
...@@ -1688,7 +1695,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1688,7 +1695,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
protected mutex must always unlocked _before_ mysys_var->mutex protected mutex must always unlocked _before_ mysys_var->mutex
is locked. (See comment in THD::exit_cond().) is locked. (See comment in THD::exit_cond().)
*/ */
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global->ds_mutex);
if (restore_current_mutex) if (restore_current_mutex)
{ {
mysql_mutex_lock(&thd->mysys_var->mutex); mysql_mutex_lock(&thd->mysys_var->mutex);
...@@ -1703,7 +1710,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1703,7 +1710,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
else else
{ {
/* In case we don't wait, we just release the mutex. */ /* In case we don't wait, we just release the mutex. */
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global->ds_mutex);
} /* end if (action->wait_for.length()) */ } /* end if (action->wait_for.length()) */
} /* end if (action->execute) */ } /* end if (action->execute) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment