@@ -137,6 +137,29 @@ static const LEX_CSTRING *view_algorithm(TABLE_LIST *table);
137
137
138
138
bool get_lookup_field_values (THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);
139
139
140
+ /* *
141
+ Try to lock a mutex, but give up after a short while to not cause deadlocks
142
+
143
+ The loop is short, as the mutex we are trying to lock are mutex the should
144
+ never be locked a long time, just over a few instructions.
145
+
146
+ @return 0 ok
147
+ @return 1 error
148
+ */
149
+
150
+ static bool trylock_short (mysql_mutex_t *mutex)
151
+ {
152
+ uint i;
153
+ for (i= 0 ; i < 100 ; i++)
154
+ {
155
+ if (!mysql_mutex_trylock (mutex))
156
+ return 0 ;
157
+ LF_BACKOFF ();
158
+ }
159
+ return 1 ;
160
+ }
161
+
162
+
140
163
/* **************************************************************************
141
164
** List all table types supported
142
165
***************************************************************************/
@@ -2634,7 +2657,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
2634
2657
while ((tmp=it++))
2635
2658
{
2636
2659
Security_context *tmp_sctx= tmp->security_ctx ;
2637
- struct st_my_thread_var *mysys_var;
2660
+ struct st_my_thread_var *mysys_var= 0 ;
2661
+ bool got_thd_data, got_mysys_lock= 0 ;
2638
2662
if ((tmp->vio_ok () || tmp->system_thread ) &&
2639
2663
(!user || (!tmp->system_thread &&
2640
2664
tmp_sctx->user && !strcmp (tmp_sctx->user , user))))
@@ -2658,48 +2682,66 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
2658
2682
tmp_sctx->host_or_ip :
2659
2683
tmp_sctx->host ? tmp_sctx->host : " " );
2660
2684
thd_info->command =(int ) tmp->get_command ();
2661
- mysql_mutex_lock (&tmp->LOCK_thd_data );
2662
- if ((thd_info->db = tmp->db )) // Safe test
2663
- thd_info->db = thd->strdup (thd_info->db );
2664
- if ((mysys_var= tmp->mysys_var ))
2665
- mysql_mutex_lock (&mysys_var->mutex );
2666
- thd_info->proc_info = (char *) (tmp->killed >= KILL_QUERY ?
2667
- " Killed" : 0 );
2668
- thd_info->state_info = thread_state_info (tmp);
2669
- if (mysys_var)
2670
- mysql_mutex_unlock (&mysys_var->mutex );
2671
2685
2672
- /* Lock THD mutex that protects its data when looking at it. */
2673
- if (tmp->query ())
2674
- {
2675
- uint length= MY_MIN (max_query_length, tmp->query_length ());
2676
- char *q= thd->strmake (tmp->query (),length);
2677
- /* Safety: in case strmake failed, we set length to 0. */
2678
- thd_info->query_string =
2679
- CSET_STRING (q, q ? length : 0 , tmp->query_charset ());
2680
- }
2686
+ if ((got_thd_data= !trylock_short (&tmp->LOCK_thd_data )))
2687
+ if ((mysys_var= tmp->mysys_var ))
2688
+ got_mysys_lock= !trylock_short (&mysys_var->mutex );
2681
2689
2682
- /*
2683
- Progress report. We need to do this under a lock to ensure that all
2684
- is from the same stage.
2685
- */
2686
- if (tmp->progress .max_counter )
2690
+ if (got_thd_data)
2687
2691
{
2688
- uint max_stage= MY_MAX (tmp->progress .max_stage , 1 );
2689
- thd_info->progress = (((tmp->progress .stage / (double ) max_stage) +
2690
- ((tmp->progress .counter /
2691
- (double ) tmp->progress .max_counter ) /
2692
- (double ) max_stage)) *
2693
- 100.0 );
2694
- set_if_smaller (thd_info->progress , 100 );
2692
+ /* This is correct under mysys_lock, otherwise an approximation */
2693
+ thd_info->proc_info = (char *) (tmp->killed >= KILL_QUERY ?
2694
+ " Killed" : 0 );
2695
+ if (got_mysys_lock)
2696
+ mysql_mutex_unlock (&mysys_var->mutex );
2697
+
2698
+ /*
2699
+ The following variables are only safe to access under a lock
2700
+ */
2701
+
2702
+ if ((thd_info->db = tmp->db )) // Safe test
2703
+ thd_info->db = thd->strdup (thd_info->db );
2704
+
2705
+ if (tmp->query ())
2706
+ {
2707
+ uint length= MY_MIN (max_query_length, tmp->query_length ());
2708
+ char *q= thd->strmake (tmp->query (),length);
2709
+ /* Safety: in case strmake failed, we set length to 0. */
2710
+ thd_info->query_string =
2711
+ CSET_STRING (q, q ? length : 0 , tmp->query_charset ());
2712
+ }
2713
+
2714
+ /*
2715
+ Progress report. We need to do this under a lock to ensure that all
2716
+ is from the same stage.
2717
+ */
2718
+ if (tmp->progress .max_counter )
2719
+ {
2720
+ uint max_stage= MY_MAX (tmp->progress .max_stage , 1 );
2721
+ thd_info->progress = (((tmp->progress .stage / (double ) max_stage) +
2722
+ ((tmp->progress .counter /
2723
+ (double ) tmp->progress .max_counter ) /
2724
+ (double ) max_stage)) *
2725
+ 100.0 );
2726
+ set_if_smaller (thd_info->progress , 100 );
2727
+ }
2728
+ else
2729
+ thd_info->progress = 0.0 ;
2695
2730
}
2696
2731
else
2732
+ {
2733
+ thd_info->proc_info = " Busy" ;
2697
2734
thd_info->progress = 0.0 ;
2735
+ }
2736
+
2737
+ thd_info->state_info = thread_state_info (tmp);
2698
2738
thd_info->start_time = tmp->start_utime ;
2699
2739
ulonglong utime_after_query_snapshot= tmp->utime_after_query ;
2700
2740
if (thd_info->start_time < utime_after_query_snapshot)
2701
2741
thd_info->start_time = utime_after_query_snapshot; // COM_SLEEP
2702
- mysql_mutex_unlock (&tmp->LOCK_thd_data );
2742
+
2743
+ if (got_thd_data)
2744
+ mysql_mutex_unlock (&tmp->LOCK_thd_data );
2703
2745
thread_infos.append (thd_info);
2704
2746
}
2705
2747
}
@@ -2938,7 +2980,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
2938
2980
explain_req.request_thd = thd;
2939
2981
explain_req.failed_to_produce = FALSE ;
2940
2982
2941
- /* Ok, we have a lock on target->LOCK_thd_data , can call: */
2983
+ /* Ok, we have a lock on target->LOCK_thd_kill , can call: */
2942
2984
bres= tmp->apc_target .make_apc_call (thd, &explain_req, timeout_sec, &timed_out);
2943
2985
2944
2986
if (bres || explain_req.failed_to_produce )
@@ -3017,9 +3059,10 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
3017
3059
while ((tmp= it++))
3018
3060
{
3019
3061
Security_context *tmp_sctx= tmp->security_ctx ;
3020
- struct st_my_thread_var *mysys_var;
3062
+ struct st_my_thread_var *mysys_var= 0 ;
3021
3063
const char *val, *db;
3022
3064
ulonglong max_counter;
3065
+ bool got_thd_data, got_mysys_lock= 0 ;
3023
3066
3024
3067
if ((!tmp->vio_ok () && !tmp->system_thread ) ||
3025
3068
(user && (tmp->system_thread || !tmp_sctx->user ||
@@ -3045,23 +3088,33 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
3045
3088
else
3046
3089
table->field [2 ]->store (tmp_sctx->host_or_ip ,
3047
3090
strlen (tmp_sctx->host_or_ip ), cs);
3048
- /* DB */
3049
- mysql_mutex_lock (&tmp->LOCK_thd_data );
3050
- if ((db= tmp->db ))
3091
+
3092
+ if ((got_thd_data= !trylock_short (&tmp->LOCK_thd_data )))
3093
+ if ((mysys_var= tmp->mysys_var ))
3094
+ got_mysys_lock= !trylock_short (&mysys_var->mutex );
3095
+
3096
+ if (got_thd_data)
3051
3097
{
3052
- table->field [3 ]->store (db, strlen (db), cs);
3053
- table->field [3 ]->set_notnull ();
3098
+ /* DB */
3099
+ if ((db= tmp->db ))
3100
+ {
3101
+ table->field [3 ]->store (db, strlen (db), cs);
3102
+ table->field [3 ]->set_notnull ();
3103
+ }
3054
3104
}
3055
3105
3056
- if ((mysys_var= tmp->mysys_var ))
3057
- mysql_mutex_lock (&mysys_var->mutex );
3058
3106
/* COMMAND */
3059
- if ((val= (char *) ((tmp->killed >= KILL_QUERY ?
3107
+ if ((val= (char *) (!got_thd_data ? " Busy" :
3108
+ (tmp->killed >= KILL_QUERY ?
3060
3109
" Killed" : 0 ))))
3061
3110
table->field [4 ]->store (val, strlen (val), cs);
3062
3111
else
3063
3112
table->field [4 ]->store (command_name[tmp->get_command ()].str ,
3064
3113
command_name[tmp->get_command ()].length , cs);
3114
+
3115
+ if (got_mysys_lock)
3116
+ mysql_mutex_unlock (&mysys_var->mutex );
3117
+
3065
3118
/* MYSQL_TIME */
3066
3119
ulonglong utime= tmp->start_utime ;
3067
3120
ulonglong utime_after_query_snapshot= tmp->utime_after_query ;
@@ -3070,52 +3123,47 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
3070
3123
utime= utime && utime < unow ? unow - utime : 0 ;
3071
3124
3072
3125
table->field [5 ]->store (utime / HRTIME_RESOLUTION, TRUE );
3126
+
3073
3127
/* STATE */
3074
3128
if ((val= thread_state_info (tmp)))
3075
3129
{
3076
3130
table->field [6 ]->store (val, strlen (val), cs);
3077
3131
table->field [6 ]->set_notnull ();
3078
3132
}
3079
3133
3080
- if (mysys_var)
3081
- mysql_mutex_unlock (&mysys_var->mutex );
3082
- mysql_mutex_unlock (&tmp->LOCK_thd_data );
3083
-
3084
- /* TIME_MS */
3085
- table->field [8 ]->store ((double )(utime / (HRTIME_RESOLUTION / 1000.0 )));
3086
-
3087
- /* INFO */
3088
- /* Lock THD mutex that protects its data when looking at it. */
3089
- mysql_mutex_lock (&tmp->LOCK_thd_data );
3090
- if (tmp->query ())
3134
+ if (got_thd_data)
3091
3135
{
3092
- table->field [7 ]->store (tmp->query (),
3093
- MY_MIN (PROCESS_LIST_INFO_WIDTH,
3094
- tmp->query_length ()), cs);
3095
- table->field [7 ]->set_notnull ();
3096
- }
3136
+ if (tmp->query ())
3137
+ {
3138
+ table->field [7 ]->store (tmp->query (),
3139
+ MY_MIN (PROCESS_LIST_INFO_WIDTH,
3140
+ tmp->query_length ()), cs);
3141
+ table->field [7 ]->set_notnull ();
3142
+
3143
+ /* INFO_BINARY */
3144
+ table->field [16 ]->store (tmp->query (),
3145
+ MY_MIN (PROCESS_LIST_INFO_WIDTH,
3146
+ tmp->query_length ()),
3147
+ &my_charset_bin);
3148
+ table->field [16 ]->set_notnull ();
3149
+ }
3097
3150
3098
- /* INFO_BINARY */
3099
- if (tmp->query ())
3100
- {
3101
- table->field [16 ]->store (tmp->query (),
3102
- MY_MIN (PROCESS_LIST_INFO_WIDTH,
3103
- tmp->query_length ()), &my_charset_bin);
3104
- table->field [16 ]->set_notnull ();
3151
+ /*
3152
+ Progress report. We need to do this under a lock to ensure that all
3153
+ is from the same stage.
3154
+ */
3155
+ if ((max_counter= tmp->progress .max_counter ))
3156
+ {
3157
+ table->field [9 ]->store ((longlong) tmp->progress .stage + 1 , 1 );
3158
+ table->field [10 ]->store ((longlong) tmp->progress .max_stage , 1 );
3159
+ table->field [11 ]->store ((double ) tmp->progress .counter /
3160
+ (double ) max_counter*100.0 );
3161
+ }
3162
+ mysql_mutex_unlock (&tmp->LOCK_thd_data );
3105
3163
}
3106
3164
3107
- /*
3108
- Progress report. We need to do this under a lock to ensure that all
3109
- is from the same stage.
3110
- */
3111
- if ((max_counter= tmp->progress .max_counter ))
3112
- {
3113
- table->field [9 ]->store ((longlong) tmp->progress .stage + 1 , 1 );
3114
- table->field [10 ]->store ((longlong) tmp->progress .max_stage , 1 );
3115
- table->field [11 ]->store ((double ) tmp->progress .counter /
3116
- (double ) max_counter*100.0 );
3117
- }
3118
- mysql_mutex_unlock (&tmp->LOCK_thd_data );
3165
+ /* TIME_MS */
3166
+ table->field [8 ]->store ((double )(utime / (HRTIME_RESOLUTION / 1000.0 )));
3119
3167
3120
3168
/*
3121
3169
This may become negative if we free a memory allocated by another
0 commit comments