mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-10010 - potential deadlock on windows due to recursive
SRWLock acquisition Backport patch from 10.1
This commit is contained in:
@ -2896,68 +2896,8 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
|
|||||||
if (!thd->variables.dynamic_variables_ptr ||
|
if (!thd->variables.dynamic_variables_ptr ||
|
||||||
(uint)offset > thd->variables.dynamic_variables_head)
|
(uint)offset > thd->variables.dynamic_variables_head)
|
||||||
{
|
{
|
||||||
uint idx;
|
|
||||||
|
|
||||||
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
|
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
|
||||||
|
sync_dynamic_session_variables(thd, global_lock);
|
||||||
thd->variables.dynamic_variables_ptr= (char*)
|
|
||||||
my_realloc(thd->variables.dynamic_variables_ptr,
|
|
||||||
global_variables_dynamic_size,
|
|
||||||
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
|
|
||||||
|
|
||||||
if (global_lock)
|
|
||||||
mysql_mutex_lock(&LOCK_global_system_variables);
|
|
||||||
|
|
||||||
mysql_mutex_assert_owner(&LOCK_global_system_variables);
|
|
||||||
|
|
||||||
memcpy(thd->variables.dynamic_variables_ptr +
|
|
||||||
thd->variables.dynamic_variables_size,
|
|
||||||
global_system_variables.dynamic_variables_ptr +
|
|
||||||
thd->variables.dynamic_variables_size,
|
|
||||||
global_system_variables.dynamic_variables_size -
|
|
||||||
thd->variables.dynamic_variables_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
now we need to iterate through any newly copied 'defaults'
|
|
||||||
and if it is a string type with MEMALLOC flag, we need to strdup
|
|
||||||
*/
|
|
||||||
for (idx= 0; idx < bookmark_hash.records; idx++)
|
|
||||||
{
|
|
||||||
sys_var_pluginvar *pi;
|
|
||||||
sys_var *var;
|
|
||||||
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
|
|
||||||
|
|
||||||
if (v->version <= thd->variables.dynamic_variables_version)
|
|
||||||
continue; /* already in thd->variables */
|
|
||||||
|
|
||||||
if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
|
|
||||||
!(pi= var->cast_pluginvar()) ||
|
|
||||||
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Here we do anything special that may be required of the data types */
|
|
||||||
|
|
||||||
if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
|
|
||||||
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
|
|
||||||
{
|
|
||||||
char **pp= (char**) (thd->variables.dynamic_variables_ptr +
|
|
||||||
*(int*)(pi->plugin_var + 1));
|
|
||||||
if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
|
|
||||||
*(int*)(pi->plugin_var + 1))))
|
|
||||||
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global_lock)
|
|
||||||
mysql_mutex_unlock(&LOCK_global_system_variables);
|
|
||||||
|
|
||||||
thd->variables.dynamic_variables_version=
|
|
||||||
global_system_variables.dynamic_variables_version;
|
|
||||||
thd->variables.dynamic_variables_head=
|
|
||||||
global_system_variables.dynamic_variables_head;
|
|
||||||
thd->variables.dynamic_variables_size=
|
|
||||||
global_system_variables.dynamic_variables_size;
|
|
||||||
|
|
||||||
mysql_rwlock_unlock(&LOCK_system_variables_hash);
|
mysql_rwlock_unlock(&LOCK_system_variables_hash);
|
||||||
}
|
}
|
||||||
DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
|
DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
|
||||||
@ -3037,6 +2977,70 @@ void plugin_thdvar_init(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void sync_dynamic_session_variables(THD* thd, bool global_lock)
|
||||||
|
{
|
||||||
|
uint idx;
|
||||||
|
|
||||||
|
thd->variables.dynamic_variables_ptr= (char*)
|
||||||
|
my_realloc(thd->variables.dynamic_variables_ptr,
|
||||||
|
global_variables_dynamic_size,
|
||||||
|
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
|
||||||
|
|
||||||
|
if (global_lock)
|
||||||
|
mysql_mutex_lock(&LOCK_global_system_variables);
|
||||||
|
|
||||||
|
mysql_mutex_assert_owner(&LOCK_global_system_variables);
|
||||||
|
|
||||||
|
memcpy(thd->variables.dynamic_variables_ptr +
|
||||||
|
thd->variables.dynamic_variables_size,
|
||||||
|
global_system_variables.dynamic_variables_ptr +
|
||||||
|
thd->variables.dynamic_variables_size,
|
||||||
|
global_system_variables.dynamic_variables_size -
|
||||||
|
thd->variables.dynamic_variables_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
now we need to iterate through any newly copied 'defaults'
|
||||||
|
and if it is a string type with MEMALLOC flag, we need to strdup
|
||||||
|
*/
|
||||||
|
for (idx= 0; idx < bookmark_hash.records; idx++)
|
||||||
|
{
|
||||||
|
sys_var_pluginvar *pi;
|
||||||
|
sys_var *var;
|
||||||
|
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
|
||||||
|
|
||||||
|
if (v->version <= thd->variables.dynamic_variables_version)
|
||||||
|
continue; /* already in thd->variables */
|
||||||
|
|
||||||
|
if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
|
||||||
|
!(pi= var->cast_pluginvar()) ||
|
||||||
|
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Here we do anything special that may be required of the data types */
|
||||||
|
|
||||||
|
if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
|
||||||
|
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
|
||||||
|
{
|
||||||
|
int offset= ((thdvar_str_t *)(pi->plugin_var))->offset;
|
||||||
|
char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset);
|
||||||
|
if (*pp)
|
||||||
|
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global_lock)
|
||||||
|
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||||
|
|
||||||
|
thd->variables.dynamic_variables_version=
|
||||||
|
global_system_variables.dynamic_variables_version;
|
||||||
|
thd->variables.dynamic_variables_head=
|
||||||
|
global_system_variables.dynamic_variables_head;
|
||||||
|
thd->variables.dynamic_variables_size=
|
||||||
|
global_system_variables.dynamic_variables_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unlocks all system variables which hold a reference
|
Unlocks all system variables which hold a reference
|
||||||
*/
|
*/
|
||||||
|
@ -174,4 +174,6 @@ typedef my_bool (plugin_foreach_func)(THD *thd,
|
|||||||
#define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
|
#define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
|
||||||
extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
|
extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
|
||||||
int type, uint state_mask, void *arg);
|
int type, uint state_mask, void *arg);
|
||||||
|
|
||||||
|
extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
|
||||||
#endif
|
#endif
|
||||||
|
@ -6937,19 +6937,30 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||||||
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
|
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
|
||||||
enum enum_schema_tables schema_table_idx=
|
enum enum_schema_tables schema_table_idx=
|
||||||
get_schema_table_idx(tables->schema_table);
|
get_schema_table_idx(tables->schema_table);
|
||||||
enum enum_var_type option_type= OPT_SESSION;
|
enum enum_var_type scope= OPT_SESSION;
|
||||||
bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
|
bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
|
||||||
bool sorted_vars= (schema_table_idx == SCH_VARIABLES);
|
bool sorted_vars= (schema_table_idx == SCH_VARIABLES);
|
||||||
|
|
||||||
if ((sorted_vars && lex->option_type == OPT_GLOBAL) ||
|
if ((sorted_vars && lex->option_type == OPT_GLOBAL) ||
|
||||||
schema_table_idx == SCH_GLOBAL_VARIABLES)
|
schema_table_idx == SCH_GLOBAL_VARIABLES)
|
||||||
option_type= OPT_GLOBAL;
|
scope= OPT_GLOBAL;
|
||||||
|
|
||||||
COND *partial_cond= make_cond_for_info_schema(cond, tables);
|
COND *partial_cond= make_cond_for_info_schema(cond, tables);
|
||||||
|
|
||||||
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
|
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
|
||||||
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
|
|
||||||
option_type, NULL, "", tables->table,
|
/*
|
||||||
|
Avoid recursive LOCK_system_variables_hash acquisition in
|
||||||
|
intern_sys_var_ptr() by pre-syncing dynamic session variables.
|
||||||
|
*/
|
||||||
|
if (scope == OPT_SESSION &&
|
||||||
|
(!thd->variables.dynamic_variables_ptr ||
|
||||||
|
global_system_variables.dynamic_variables_head >
|
||||||
|
thd->variables.dynamic_variables_head))
|
||||||
|
sync_dynamic_session_variables(thd, true);
|
||||||
|
|
||||||
|
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, scope),
|
||||||
|
scope, NULL, "", tables->table,
|
||||||
upper_case_names, partial_cond);
|
upper_case_names, partial_cond);
|
||||||
mysql_rwlock_unlock(&LOCK_system_variables_hash);
|
mysql_rwlock_unlock(&LOCK_system_variables_hash);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
|
Reference in New Issue
Block a user