MDEV-32567 Remove thr_alarm from server codebase

This allows to simplify net_real_read() and net_real_write() a bit.

Removed some superfluous #ifdef/ifndef MYSQL_SERVER from net_serv.cc
The code always runs in server, either normal or embedded.
Dead code for switching socket between blocking and non-blocking modes,
is also removed.

Removed pthread_kill() with alarm signal that woke up main thread on
server shutdown. Used shutdown(2) on polling sockets instead, to the same
effect.

Removed yet another superstitious pthread_kill(), that ran on non-Windows
in terminate_slave_thread().
This commit is contained in:
Vladislav Vaintroub 2023-10-26 15:02:35 +02:00 committed by Daniel Black
parent 3424ed7d42
commit 013fc02a23
19 changed files with 125 additions and 1515 deletions

View file

@ -384,7 +384,6 @@
#cmakedefine HAVE_GCC_C11_ATOMICS 1
#cmakedefine HAVE_SOLARIS_ATOMIC 1
#cmakedefine NO_FCNTL_NONBLOCK 1
#cmakedefine NO_ALARM 1
#cmakedefine _LARGE_FILES 1
#cmakedefine _LARGEFILE_SOURCE 1

View file

@ -836,7 +836,6 @@ CHECK_CXX_SOURCE_COMPILES("
"
HAVE_SOLARIS_STYLE_GETHOST)
SET(NO_ALARM 1 CACHE BOOL "No need to use alarm to implement timeout")
# As a consequence of ALARMs no longer being used, thread
# notification for KILL must close the socket to wake up

View file

@ -181,7 +181,6 @@ extern int my_pthread_create_detached;
#define PTHREAD_CREATE_DETACHED &my_pthread_create_detached
#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL
#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL
#define USE_ALARM_THREAD
#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */
#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910

View file

@ -1,115 +0,0 @@
/* Copyright (c) 2000, 2011, 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 as published by
the Free Software Foundation; version 2 of the License.
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 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-1335 USA */
/* Prototypes when using thr_alarm library functions */
#ifndef _thr_alarm_h
#define _thr_alarm_h
#ifdef __cplusplus
extern "C" {
#endif
#ifndef USE_ALARM_THREAD
#define USE_ONE_SIGNAL_HAND /* One must call process_alarm */
#endif
#ifdef HAVE_rts_threads
#undef USE_ONE_SIGNAL_HAND
#define USE_ALARM_THREAD
#define THR_SERVER_ALARM SIGUSR1
#else
#define THR_SERVER_ALARM SIGALRM
#endif
typedef struct st_alarm_info
{
time_t next_alarm_time;
uint active_alarms;
uint max_used_alarms;
} ALARM_INFO;
void thr_alarm_info(ALARM_INFO *info);
extern my_bool my_disable_thr_alarm;
#ifdef _WIN32
#define DONT_USE_THR_ALARM
#endif
#if defined(DONT_USE_THR_ALARM)
#define USE_ALARM_THREAD
#undef USE_ONE_SIGNAL_HAND
typedef my_bool thr_alarm_t;
typedef my_bool ALARM;
#define thr_alarm_init(A) (*(A))=0
#define thr_alarm_in_use(A) (*(A) != 0)
#define thr_end_alarm(A)
#define thr_alarm(A,B,C) ((*(A)=1)-1)
/* The following should maybe be (*(A)) */
#define thr_got_alarm(A) 0
#define init_thr_alarm(A)
#define thr_alarm_kill(A)
#define resize_thr_alarm(N)
#define end_thr_alarm(A)
#else
#if defined(_WIN32)
typedef struct st_thr_alarm_entry
{
UINT_PTR crono;
} thr_alarm_entry;
#else /* System with posix threads */
typedef int thr_alarm_entry;
#define thr_got_alarm(thr_alarm) (**(thr_alarm))
#endif /* _WIN32 */
typedef thr_alarm_entry* thr_alarm_t;
typedef struct st_alarm {
time_t expire_time;
thr_alarm_entry alarmed; /* set when alarm is due */
pthread_t thread;
my_thread_id thread_id;
uint index_in_queue;
my_bool malloced;
} ALARM;
extern uint thr_client_alarm;
extern pthread_t alarm_thread;
#define thr_alarm_init(A) (*(A))=0
#define thr_alarm_in_use(A) (*(A)!= 0)
void init_thr_alarm(uint max_alarm);
void resize_thr_alarm(uint max_alarms);
my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff);
void thr_alarm_kill(my_thread_id thread_id);
void thr_end_alarm(thr_alarm_t *alarmed);
void end_thr_alarm(my_bool free_structures);
sig_handler process_alarm(int);
#ifndef thr_got_alarm
my_bool thr_got_alarm(thr_alarm_t *alrm);
#endif
#endif /* DONT_USE_THR_ALARM */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _thr_alarm_h */

View file

@ -1,21 +0,0 @@
select @@global.debug_no_thread_alarm;
@@global.debug_no_thread_alarm
0
select @@session.debug_no_thread_alarm;
ERROR HY000: Variable 'debug_no_thread_alarm' is a GLOBAL variable
show global variables like 'debug_no_thread_alarm';
Variable_name Value
debug_no_thread_alarm OFF
show session variables like 'debug_no_thread_alarm';
Variable_name Value
debug_no_thread_alarm OFF
select * from information_schema.global_variables where variable_name='debug_no_thread_alarm';
VARIABLE_NAME VARIABLE_VALUE
DEBUG_NO_THREAD_ALARM OFF
select * from information_schema.session_variables where variable_name='debug_no_thread_alarm';
VARIABLE_NAME VARIABLE_VALUE
DEBUG_NO_THREAD_ALARM OFF
set global debug_no_thread_alarm=1;
ERROR HY000: Variable 'debug_no_thread_alarm' is a read only variable
set session debug_no_thread_alarm=1;
ERROR HY000: Variable 'debug_no_thread_alarm' is a read only variable

View file

@ -46,21 +46,6 @@ ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
GLOBAL_VALUE_PATH NULL
VARIABLE_NAME DEBUG_NO_THREAD_ALARM
SESSION_VALUE NULL
GLOBAL_VALUE OFF
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE OFF
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Disable system thread alarm calls. Disabling it may be useful in debugging or testing, never do it in production
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
GLOBAL_VALUE_PATH NULL
VARIABLE_NAME DEBUG_SYNC
SESSION_VALUE ON - current signals: ''
GLOBAL_VALUE NULL

View file

@ -1,21 +0,0 @@
# bool readonly
#
# show values;
#
select @@global.debug_no_thread_alarm;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.debug_no_thread_alarm;
show global variables like 'debug_no_thread_alarm';
show session variables like 'debug_no_thread_alarm';
select * from information_schema.global_variables where variable_name='debug_no_thread_alarm';
select * from information_schema.session_variables where variable_name='debug_no_thread_alarm';
#
# show that it's read-only
#
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
set global debug_no_thread_alarm=1;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
set session debug_no_thread_alarm=1;

View file

@ -34,7 +34,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c my_default.c
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c
my_basename.c
my_write.c ptr_cmp.c queues.c stacktrace.c
string.c thr_alarm.c thr_lock.c thr_mutex.c
string.c thr_lock.c thr_mutex.c
thr_rwlock.c thr_timer.c
tree.c typelib.c base64.c my_memmem.c
my_getpagesize.c

View file

@ -468,7 +468,7 @@ PSI_mutex_key key_LOCK_localtime_r;
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock,
key_LOCK_alarm, key_LOCK_timer,
key_LOCK_timer,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
key_THR_LOCK_lock, key_THR_LOCK_malloc,
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
@ -487,7 +487,6 @@ static PSI_mutex_info all_mysys_mutexes[]=
{ &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
{ &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
{ &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
{ &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL},
{ &key_LOCK_timer, "LOCK_timer", PSI_FLAG_GLOBAL},
{ &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
{ &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
@ -504,13 +503,12 @@ static PSI_mutex_info all_mysys_mutexes[]=
{ &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL }
};
PSI_cond_key key_COND_alarm, key_COND_timer, key_IO_CACHE_SHARE_cond,
PSI_cond_key key_COND_timer, key_IO_CACHE_SHARE_cond,
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
key_THR_COND_threads, key_WT_RESOURCE_cond;
static PSI_cond_info all_mysys_conds[]=
{
{ &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL},
{ &key_COND_timer, "COND_timer", PSI_FLAG_GLOBAL},
{ &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
{ &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
@ -526,16 +524,10 @@ static PSI_rwlock_info all_mysys_rwlocks[]=
{ &key_SAFEHASH_mutex, "SAFE_HASH::mutex", 0}
};
#ifdef USE_ALARM_THREAD
PSI_thread_key key_thread_alarm;
#endif
PSI_thread_key key_thread_timer;
static PSI_thread_info all_mysys_threads[]=
{
#ifdef USE_ALARM_THREAD
{ &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL},
#endif
{ &key_thread_timer, "statement_timer", PSI_FLAG_GLOBAL}
};

View file

@ -20,7 +20,6 @@
#include "mysys_priv.h"
#include <signal.h>
#include <m_string.h>
#include <thr_alarm.h>
#include <my_pthread.h>
#if (defined(__BSD__) || defined(_BSDI_VERSION))
@ -234,11 +233,7 @@ void *sigwait_thread(void *set_arg)
sigaction(i, &sact, (struct sigaction*) 0);
}
}
/* Ensure that init_thr_alarm() is called */
DBUG_ASSERT(thr_client_alarm);
sigaddset(set, thr_client_alarm);
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
alarm_thread=pthread_self(); /* For thr_alarm */
for (;;)
{ /* Wait for signals */

View file

@ -43,20 +43,17 @@ extern PSI_mutex_key key_LOCK_localtime_r;
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
key_THR_LOCK_lock, key_THR_LOCK_malloc,
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
key_THR_LOCK_open, key_THR_LOCK_threads, key_LOCK_uuid_generator,
key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap, key_LOCK_timer;
extern PSI_cond_key key_COND_alarm, key_COND_timer, key_IO_CACHE_SHARE_cond,
extern PSI_cond_key key_COND_timer, key_IO_CACHE_SHARE_cond,
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
key_THR_COND_threads;
#ifdef USE_ALARM_THREAD
extern PSI_thread_key key_thread_alarm;
#endif /* USE_ALARM_THREAD */
extern PSI_thread_key key_thread_timer;
extern PSI_rwlock_key key_SAFEHASH_mutex;

View file

@ -1,845 +0,0 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates
Copyright (c) 2012, 2014, SkySQL Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
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 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-1335 USA */
/* To avoid problems with alarms in debug code, we disable DBUG here */
#define FORCE_DBUG_OFF
#include "mysys_priv.h"
#include <my_global.h>
#if !defined(DONT_USE_THR_ALARM)
#include <errno.h>
#include <my_pthread.h>
#include <signal.h>
#include <my_sys.h>
#include <m_string.h>
#include <queues.h>
#include "thr_alarm.h"
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h> /* AIX needs this for fd_set */
#endif
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
#ifdef DBUG_OFF
#define reset_index_in_queue(alarm_data)
#else
#define reset_index_in_queue(alarm_data) alarm_data->index_in_queue= 0;
#endif /* DBUG_OFF */
#ifndef USE_ONE_SIGNAL_HAND
#define one_signal_hand_sigmask(A,B,C) pthread_sigmask((A), (B), (C))
#else
#define one_signal_hand_sigmask(A,B,C)
#endif
my_bool thr_alarm_inited= 0, my_disable_thr_alarm= 0;
#if !defined(_WIN32)
uint thr_client_alarm;
static int alarm_aborted=1; /* No alarm thread */
volatile my_bool alarm_thread_running= 0;
time_t next_alarm_expire_time= ~ (time_t) 0;
static sig_handler process_alarm_part2(int sig);
static mysql_mutex_t LOCK_alarm;
static mysql_cond_t COND_alarm;
static sigset_t full_signal_set;
static QUEUE alarm_queue;
static uint max_used_alarms=0;
pthread_t alarm_thread;
#define MY_THR_ALARM_QUEUE_EXTENT 10
#ifdef USE_ALARM_THREAD
static void *alarm_handler(void *arg);
#define reschedule_alarms() mysql_cond_signal(&COND_alarm)
#else
#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
#endif
static sig_handler thread_alarm(int sig __attribute__((unused)));
static int compare_ulong(void *not_used __attribute__((unused)),
uchar *a_ptr,uchar* b_ptr)
{
ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
return (a < b) ? -1 : (a == b) ? 0 : 1;
}
void init_thr_alarm(uint max_alarms)
{
sigset_t s;
DBUG_ENTER("init_thr_alarm");
alarm_aborted=0;
next_alarm_expire_time= ~ (time_t) 0;
init_queue(&alarm_queue, max_alarms+1, offsetof(ALARM,expire_time), 0,
compare_ulong, NullS, offsetof(ALARM, index_in_queue)+1,
MY_THR_ALARM_QUEUE_EXTENT);
sigfillset(&full_signal_set); /* Neaded to block signals */
mysql_mutex_init(key_LOCK_alarm, &LOCK_alarm, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_alarm, &COND_alarm, NULL);
thr_client_alarm= SIGUSR1;
my_sigset(thr_client_alarm, thread_alarm);
sigemptyset(&s);
sigaddset(&s, THR_SERVER_ALARM);
alarm_thread=pthread_self();
#if defined(USE_ALARM_THREAD)
{
pthread_attr_t thr_attr;
pthread_attr_init(&thr_attr);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
mysql_thread_create(key_thread_alarm,
&alarm_thread, &thr_attr, alarm_handler, NULL);
pthread_attr_destroy(&thr_attr);
}
#elif defined(USE_ONE_SIGNAL_HAND)
pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
#else
my_sigset(THR_SERVER_ALARM, process_alarm);
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
#endif
DBUG_VOID_RETURN;
}
void resize_thr_alarm(uint max_alarms)
{
mysql_mutex_lock(&LOCK_alarm);
/*
It's ok not to shrink the queue as there may be more pending alarms than
than max_alarms
*/
if (alarm_queue.elements < max_alarms)
{
resize_queue(&alarm_queue,max_alarms+1);
max_used_alarms= alarm_queue.elements;
}
mysql_mutex_unlock(&LOCK_alarm);
}
/*
Request alarm after sec seconds.
SYNOPSIS
thr_alarm()
alrm Pointer to alarm detection
alarm_data Structure to store in alarm queue
NOTES
This function can't be called from the alarm-handling thread.
RETURN VALUES
0 ok
1 If no more alarms are allowed (aborted by process)
Stores in first argument a pointer to a non-zero int which is set to 0
when the alarm has been given
*/
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
{
time_t now, next;
#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
#endif
my_bool reschedule;
struct st_my_thread_var *current_my_thread_var= my_thread_var;
DBUG_ENTER("thr_alarm");
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
if (my_disable_thr_alarm)
{
(*alrm)= &alarm_data->alarmed;
alarm_data->alarmed= 1; /* Abort if interrupted */
DBUG_RETURN(0);
}
if (unlikely(alarm_aborted))
{ /* No signal thread */
DBUG_PRINT("info", ("alarm aborted"));
if (alarm_aborted > 0)
goto abort_no_unlock;
sec= 1; /* Abort mode */
}
now= my_time(0);
if (!alarm_data)
{
if (!(alarm_data=(ALARM*) my_malloc(PSI_INSTRUMENT_ME, sizeof(ALARM),
MYF(MY_WME))))
goto abort_no_unlock;
alarm_data->malloced= 1;
}
else
alarm_data->malloced= 0;
next= now + sec;
alarm_data->expire_time= next;
alarm_data->alarmed= 0;
alarm_data->thread= current_my_thread_var->pthread_self;
alarm_data->thread_id= current_my_thread_var->id;
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
mysql_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
if (alarm_queue.elements >= max_used_alarms)
{
max_used_alarms=alarm_queue.elements+1;
}
reschedule= (ulong) next_alarm_expire_time > (ulong) next;
queue_insert_safe(&alarm_queue, (uchar*) alarm_data);
assert(alarm_data->index_in_queue > 0);
/* Reschedule alarm if the current one has more than sec left */
if (unlikely(reschedule))
{
DBUG_PRINT("info", ("reschedule"));
if (pthread_equal(pthread_self(),alarm_thread))
{
alarm(sec); /* purecov: inspected */
next_alarm_expire_time= next;
}
else
reschedule_alarms(); /* Reschedule alarms */
}
mysql_mutex_unlock(&LOCK_alarm);
one_signal_hand_sigmask(SIG_SETMASK,&old_mask,NULL);
(*alrm)= &alarm_data->alarmed;
DBUG_RETURN(0);
abort_no_unlock:
*alrm= 0; /* No alarm */
DBUG_RETURN(1);
}
/*
Remove alarm from list of alarms
*/
void thr_end_alarm(thr_alarm_t *alarmed)
{
ALARM *alarm_data;
#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
#endif
DBUG_ENTER("thr_end_alarm");
if (my_disable_thr_alarm)
DBUG_VOID_RETURN;
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
mysql_mutex_lock(&LOCK_alarm);
DBUG_ASSERT(alarm_data->index_in_queue != 0);
DBUG_ASSERT((ALARM*) queue_element(&alarm_queue,
alarm_data->index_in_queue) ==
alarm_data);
queue_remove(&alarm_queue, alarm_data->index_in_queue);
mysql_mutex_unlock(&LOCK_alarm);
one_signal_hand_sigmask(SIG_SETMASK,&old_mask,NULL);
reset_index_in_queue(alarm_data);
DBUG_VOID_RETURN;
}
/*
Come here when some alarm in queue is due.
Mark all alarms with are finnished in list.
Schedule alarms to be sent again after 1-10 sec (many alarms at once)
If alarm_aborted is set then all alarms are given and resent
every second.
*/
sig_handler process_alarm(int sig __attribute__((unused)))
{
sigset_t old_mask;
/*
This must be first as we can't call DBUG inside an alarm for a normal thread
*/
/*
We have to do do the handling of the alarm in a sub function,
because otherwise we would get problems with two threads calling
DBUG_... functions at the same time (as two threads may call
process_alarm() at the same time
*/
#ifndef USE_ALARM_THREAD
pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
mysql_mutex_lock(&LOCK_alarm);
#endif
process_alarm_part2(sig);
#ifndef USE_ALARM_THREAD
#if defined(SIGNAL_HANDLER_RESET_ON_DELIVERY) && !defined(USE_ONE_SIGNAL_HAND)
my_sigset(THR_SERVER_ALARM,process_alarm);
#endif
mysql_mutex_unlock(&LOCK_alarm);
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
#endif
return;
}
static sig_handler process_alarm_part2(int sig __attribute__((unused)))
{
ALARM *alarm_data;
DBUG_ENTER("process_alarm");
DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
#if defined(MAIN) && !defined(__bsdi__)
printf("process_alarm\n"); fflush(stdout);
#endif
if (likely(alarm_queue.elements))
{
if (unlikely(alarm_aborted))
{
uint i;
for (i= queue_first_element(&alarm_queue) ;
i <= queue_last_element(&alarm_queue) ;)
{
alarm_data=(ALARM*) queue_element(&alarm_queue,i);
alarm_data->alarmed=1; /* Info to thread */
if (pthread_equal(alarm_data->thread,alarm_thread) ||
pthread_kill(alarm_data->thread, thr_client_alarm))
{
#ifdef MAIN
printf("Warning: pthread_kill couldn't find thread!!!\n");
#endif
queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
reset_index_in_queue(alarm_data);
}
else
i++; /* Signal next thread */
}
#ifndef USE_ALARM_THREAD
if (alarm_queue.elements)
alarm(1); /* Signal soon again */
#endif
}
else
{
time_t now= my_time(0);
time_t next= now+10-(now%10);
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
{
alarm_data->alarmed=1; /* Info to thread */
DBUG_PRINT("info",("sending signal to waiting thread"));
if (pthread_equal(alarm_data->thread,alarm_thread) ||
pthread_kill(alarm_data->thread, thr_client_alarm))
{
#ifdef MAIN
printf("Warning: pthread_kill couldn't find thread!!!\n");
#endif /* MAIN */
queue_remove_top(&alarm_queue); /* No thread. Remove alarm */
reset_index_in_queue(alarm_data);
if (!alarm_queue.elements)
break;
}
else
{
alarm_data->expire_time=next;
queue_replace_top(&alarm_queue);
}
}
#ifndef USE_ALARM_THREAD
if (alarm_queue.elements)
{
#ifdef __bsdi__
alarm(0); /* Remove old alarm */
#endif
alarm((uint) (alarm_data->expire_time-now));
next_alarm_expire_time= alarm_data->expire_time;
}
#endif
}
}
else
{
/*
Ensure that next time we call thr_alarm(), we will schedule a new alarm
*/
next_alarm_expire_time= ~(time_t) 0;
}
DBUG_VOID_RETURN;
}
/*
Schedule all alarms now and optionally free all structures
SYNPOSIS
end_thr_alarm()
free_structures Set to 1 if we should free memory used for
the alarm queue.
When we call this we should KNOW that there
is no active alarms
IMPLEMENTATION
Set alarm_abort to -1 which will change the behavior of alarms as follows:
- All old alarms will be rescheduled at once
- All new alarms will be rescheduled to one second
*/
void end_thr_alarm(my_bool free_structures)
{
DBUG_ENTER("end_thr_alarm");
if (alarm_aborted != 1) /* If memory not freed */
{
mysql_mutex_lock(&LOCK_alarm);
DBUG_PRINT("info",("Rescheduling %d waiting alarms",alarm_queue.elements));
alarm_aborted= -1; /* mark aborted */
if (alarm_queue.elements || (alarm_thread_running && free_structures))
{
if (pthread_equal(pthread_self(),alarm_thread))
alarm(1); /* Shut down everything soon */
else
reschedule_alarms();
}
if (free_structures)
{
struct timespec abstime;
DBUG_ASSERT(!alarm_queue.elements);
/* Wait until alarm thread dies */
set_timespec(abstime, 10); /* Wait up to 10 seconds */
while (alarm_thread_running)
{
int error= mysql_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime);
if (error == ETIME || error == ETIMEDOUT)
break; /* Don't wait forever */
}
delete_queue(&alarm_queue);
alarm_aborted= 1;
mysql_mutex_unlock(&LOCK_alarm);
if (!alarm_thread_running) /* Safety */
{
mysql_mutex_destroy(&LOCK_alarm);
mysql_cond_destroy(&COND_alarm);
}
}
else
mysql_mutex_unlock(&LOCK_alarm);
}
DBUG_VOID_RETURN;
}
/*
Remove another thread from the alarm
*/
void thr_alarm_kill(my_thread_id thread_id)
{
uint i;
DBUG_ENTER("thr_alarm_kill");
if (alarm_aborted)
return;
mysql_mutex_lock(&LOCK_alarm);
for (i= queue_first_element(&alarm_queue) ;
i <= queue_last_element(&alarm_queue);
i++)
{
ALARM *element= (ALARM*) queue_element(&alarm_queue,i);
if (element->thread_id == thread_id)
{
DBUG_PRINT("info", ("found thread; Killing it"));
element->expire_time= 0;
queue_replace(&alarm_queue, i);
reschedule_alarms();
break;
}
}
mysql_mutex_unlock(&LOCK_alarm);
DBUG_VOID_RETURN;
}
void thr_alarm_info(ALARM_INFO *info)
{
mysql_mutex_lock(&LOCK_alarm);
info->next_alarm_time= 0;
info->max_used_alarms= max_used_alarms;
if ((info->active_alarms= alarm_queue.elements))
{
time_t now= my_time(0);
long time_diff;
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
time_diff= (long) (alarm_data->expire_time - now);
info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff);
}
mysql_mutex_unlock(&LOCK_alarm);
}
/*
This is here for thread to get interruptet from read/write/fcntl
ARGSUSED
*/
static sig_handler thread_alarm(int sig __attribute__((unused)))
{
#ifdef MAIN
printf("thread_alarm\n"); fflush(stdout);
#endif
#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
my_sigset(sig,thread_alarm); /* int. thread system calls */
#endif
}
#ifdef HAVE_TIMESPEC_TS_SEC
#define tv_sec ts_sec
#define tv_nsec ts_nsec
#endif
/* set up a alarm thread with uses 'sleep' to sleep between alarms */
#ifdef USE_ALARM_THREAD
static void *alarm_handler(void *arg __attribute__((unused)))
{
int error;
struct timespec abstime;
#ifdef MAIN
puts("Starting alarm thread");
#endif
my_thread_init();
alarm_thread_running= 1;
mysql_mutex_lock(&LOCK_alarm);
for (;;)
{
if (alarm_queue.elements)
{
time_t sleep_time,now= my_time(0);
if (alarm_aborted)
sleep_time=now+1;
else
sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
if (sleep_time > now)
{
abstime.tv_sec=sleep_time;
abstime.tv_nsec=0;
next_alarm_expire_time= sleep_time;
if ((error= mysql_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime)) &&
error != ETIME && error != ETIMEDOUT)
{
#ifdef MAIN
printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
error,errno);
#endif
}
}
}
else if (alarm_aborted == -1)
break;
else
{
next_alarm_expire_time= ~ (time_t) 0;
if ((error= mysql_cond_wait(&COND_alarm, &LOCK_alarm)))
{
#ifdef MAIN
printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
error,errno);
#endif
}
}
process_alarm(0);
}
bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
alarm_thread_running= 0;
mysql_cond_signal(&COND_alarm);
mysql_mutex_unlock(&LOCK_alarm);
pthread_exit(0);
return 0; /* Impossible */
}
#endif /* USE_ALARM_THREAD */
#endif
/****************************************************************************
Handling of test case (when compiled with -DMAIN)
***************************************************************************/
#ifdef MAIN
#if !defined(DONT_USE_THR_ALARM)
static mysql_cond_t COND_thread_count;
static mysql_mutex_t LOCK_thread_count;
static uint thread_count;
#ifdef HPUX10
typedef int * fd_set_ptr;
#else
typedef fd_set * fd_set_ptr;
#endif /* HPUX10 */
static void *test_thread(void *arg)
{
int i,param=*((int*) arg),wait_time,retry;
time_t start_time;
thr_alarm_t got_alarm;
fd_set fd;
FD_ZERO(&fd);
my_thread_init();
printf("Thread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
for (i=1 ; i <= 10 ; i++)
{
wait_time=param ? 11-i : i;
start_time= my_time(0);
if (thr_alarm(&got_alarm,wait_time,0))
{
printf("Thread: %s Alarms aborted\n",my_thread_name());
break;
}
if (wait_time == 3)
{
printf("Thread: %s Simulation of no alarm needed\n",my_thread_name());
fflush(stdout);
}
else
{
for (retry=0 ; !thr_got_alarm(&got_alarm) && retry < 10 ; retry++)
{
printf("Thread: %s Waiting %d sec\n",my_thread_name(),wait_time);
select(0,(fd_set_ptr) &fd,0,0,0);
}
if (!thr_got_alarm(&got_alarm))
{
printf("Thread: %s didn't get an alarm. Aborting!\n",
my_thread_name());
break;
}
if (wait_time == 7)
{ /* Simulate alarm-miss */
fd_set readFDs;
uint max_connection=fileno(stdin);
FD_ZERO(&readFDs);
FD_SET(max_connection,&readFDs);
retry=0;
for (;;)
{
printf("Thread: %s Simulating alarm miss\n",my_thread_name());
fflush(stdout);
if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
{
if (errno == EINTR)
break; /* Got new interrupt */
printf("Got errno: %d from select. Retrying..\n",errno);
if (retry++ >= 3)
{
printf("Warning: Interrupt of select() doesn't set errno!\n");
break;
}
}
else /* This shouldn't happen */
{
if (!FD_ISSET(max_connection,&readFDs))
{
printf("Select interrupted, but errno not set\n");
fflush(stdout);
if (retry++ >= 3)
break;
continue;
}
(void) getchar(); /* Somebody was playing */
}
}
}
}
printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
(int) (my_time(0)-start_time), wait_time); fflush(stdout);
thr_end_alarm(&got_alarm);
fflush(stdout);
}
mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */
mysql_mutex_unlock(&LOCK_thread_count);
my_thread_end();
return 0;
}
static void *signal_hand(void *arg __attribute__((unused)))
{
sigset_t set;
int sig,error,err_count=0;;
my_thread_init();
pthread_detach_this_thread();
init_thr_alarm(10); /* Setup alarm handler */
mysql_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */
mysql_mutex_unlock(&LOCK_thread_count);
sigemptyset(&set); /* Catch all signals */
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
#ifdef USE_ONE_SIGNAL_HAND
sigaddset(&set,THR_SERVER_ALARM); /* For alarms */
puts("Starting signal and alarm handling thread");
#else
puts("Starting signal handling thread");
#endif
printf("server alarm: %d thread alarm: %d\n",
THR_SERVER_ALARM, thr_client_alarm);
DBUG_PRINT("info",("Starting signal and alarm handling thread"));
for(;;)
{
int code;
while ((error=my_sigwait(&set,&sig,&code)) == EINTR)
printf("sigwait restarted\n");
if (error)
{
fprintf(stderr,"Got error %d from sigwait\n",error);
if (err_count++ > 5)
exit(1); /* Too many errors in test */
continue;
}
#ifdef USE_ONE_SIGNAL_HAND
if (sig != THR_SERVER_ALARM)
#endif
printf("Main thread: Got signal %d\n",sig);
switch (sig) {
case SIGINT:
case SIGQUIT:
case SIGTERM:
case SIGHUP:
printf("Aborting nicely\n");
end_thr_alarm(0);
break;
#ifdef SIGTSTP
case SIGTSTP:
printf("Aborting\n");
exit(1);
return 0; /* Keep some compilers happy */
#endif
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
process_alarm(sig);
break;
#endif
}
}
}
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
pthread_t tid;
pthread_attr_t thr_attr;
int i, param[2], error;
sigset_t set;
ALARM_INFO alarm_info;
MY_INIT(argv[0]);
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
{
DBUG_PUSH(argv[1]+2);
}
mysql_mutex_init(0, &LOCK_thread_count, MY_MUTEX_INIT_FAST);
mysql_cond_init(0, &COND_thread_count, NULL);
/* Start a alarm handling thread */
sigemptyset(&set);
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
signal(SIGTERM,SIG_DFL); /* If it's blocked by parent */
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
sigaddset(&set,THR_SERVER_ALARM);
sigdelset(&set, thr_client_alarm);
(void) pthread_sigmask(SIG_SETMASK,&set,NULL);
pthread_attr_init(&thr_attr);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&thr_attr,65536L);
/* Start signal thread and wait for it to start */
mysql_mutex_lock(&LOCK_thread_count);
mysql_thread_create(0, &tid, &thr_attr, signal_hand, NULL);
mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
mysql_mutex_unlock(&LOCK_thread_count);
DBUG_PRINT("info",("signal thread created"));
thr_setconcurrency(3);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
printf("Main thread: %s\n",my_thread_name());
for (i=0 ; i < 2 ; i++)
{
param[i]= i;
mysql_mutex_lock(&LOCK_thread_count);
if ((error= mysql_thread_create(0,
&tid, &thr_attr, test_thread,
(void*) &param[i])))
{
printf("Can't create thread %d, error: %d\n",i,error);
exit(1);
}
thread_count++;
mysql_mutex_unlock(&LOCK_thread_count);
}
pthread_attr_destroy(&thr_attr);
mysql_mutex_lock(&LOCK_thread_count);
thr_alarm_info(&alarm_info);
printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
alarm_info.active_alarms, alarm_info.max_used_alarms,
alarm_info.next_alarm_time);
while (thread_count)
{
mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
if (thread_count == 1)
{
printf("Calling end_thr_alarm. This should cancel the last thread\n");
end_thr_alarm(0);
}
}
mysql_mutex_unlock(&LOCK_thread_count);
thr_alarm_info(&alarm_info);
end_thr_alarm(1);
printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
alarm_info.active_alarms, alarm_info.max_used_alarms,
alarm_info.next_alarm_time);
printf("Test succeeded\n");
mysql_cond_destroy(&COND_thread_count);
mysql_mutex_destroy(&LOCK_thread_count);
my_end(MY_CHECK_ERROR);
return 0;
}
#else /* !defined(DONT_USE_ALARM_THREAD) */
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");
exit(1);
}
#endif /* !defined(DONT_USE_ALARM_THREAD) */
#endif /* WIN */
#endif /* MAIN */

View file

@ -20,7 +20,6 @@
#error You have already included an client_settings.h and it should not be included twice
#endif /* CLIENT_SETTINGS_INCLUDED */
#include <thr_alarm.h>
#include <sql_common.h>
/*

View file

@ -113,7 +113,6 @@
#include <sys/prctl.h>
#endif
#include <thr_alarm.h>
#include <ft_global.h>
#include <errmsg.h>
#include "sp_rcontext.h"
@ -1670,10 +1669,11 @@ static void break_connect_loop()
int UNINIT_VAR(error);
DBUG_PRINT("info",("Waiting for select thread"));
#ifndef DONT_USE_THR_ALARM
if (pthread_kill(select_thread, thr_client_alarm))
break; // allready dead
#endif
for(size_t i=0; i < listen_sockets.size(); i++)
{
int fd=mysql_socket_getfd(listen_sockets.at(i));
shutdown(fd, SHUT_RDWR);
}
set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 && select_thread_in_use; tmp++)
{
@ -1765,8 +1765,6 @@ static void close_connections(void)
listen_sockets.free_memory();
mysql_mutex_unlock(&LOCK_start_thread);
end_thr_alarm(0); // Abort old alarms.
while (CONNECT::count)
my_sleep(100);
@ -1877,10 +1875,6 @@ extern "C" sig_handler print_signal_warning(int sig)
#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
#if !defined(_WIN32)
if (sig == SIGALRM)
alarm(2); /* reschedule alarm */
#endif
}
#ifdef _WIN32
@ -2027,7 +2021,6 @@ static void clean_up(bool print_message)
multi_keycache_free();
sp_cache_end();
free_status_vars();
end_thr_alarm(1); /* Free allocated memory */
end_thr_timer();
my_free_open_file_info();
if (defaults_argv)
@ -3110,8 +3103,6 @@ void init_signals(void)
struct sigaction sa;
DBUG_ENTER("init_signals");
my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (opt_stack_trace || (test_flags & TEST_CORE_ON_SIGNAL))
{
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
@ -3159,7 +3150,6 @@ void init_signals(void)
sa.sa_flags = 0;
sa.sa_handler = print_signal_warning;
sigaction(SIGHUP, &sa, (struct sigaction*) 0);
sigaddset(&set,THR_SERVER_ALARM);
if (test_flags & TEST_SIGINT)
{
/* Allow SIGINT to break mysqld. This is for debugging with --gdb */
@ -3220,7 +3210,7 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
#endif
/** This threads handles all signals and alarms. */
/** This threads handles all signals */
/* ARGSUSED */
pthread_handler_t signal_hand(void *arg __attribute__((unused)))
{
@ -3230,13 +3220,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
DBUG_ENTER("signal_hand");
signal_thread_in_use= 1;
/*
Setup alarm handler
This should actually be '+ max_number_of_slaves' instead of +10,
but the +10 should be quite safe.
*/
init_thr_alarm(thread_scheduler->max_threads + extra_max_connections +
global_system_variables.max_insert_delayed_threads + 10);
if (test_flags & TEST_SIGINT)
{
/* Allow SIGINT to break mysqld. This is for debugging with --gdb */
@ -3245,9 +3228,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
(void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
}
(void) sigemptyset(&set); // Setup up SIGINT for debug
#ifdef USE_ONE_SIGNAL_HAND
(void) sigaddset(&set,THR_SERVER_ALARM); // For alarms
#endif
#ifndef IGNORE_SIGHUP_SIGQUIT
(void) sigaddset(&set,SIGQUIT);
(void) sigaddset(&set,SIGHUP);
@ -3311,7 +3291,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
error);
#else
my_sigset(sig, SIG_IGN);
break_connect_loop(); // MIT THREAD has a alarm thread
break_connect_loop();
#endif
}
break;
@ -3341,11 +3321,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
opt_log ? fixed_log_output_options : LOG_NONE);
}
break;
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
process_alarm(sig); // Trigger alarms.
break;
#endif
default:
#ifdef EXTRA_DEBUG
sql_print_warning("Got signal: %d error: %d",sig,error); /* purecov: tested */
@ -5854,7 +5829,7 @@ int mysqld_main(int argc, char **argv)
#endif
/*
init signals & alarm
init signals
After this we can't quit by a simple unireg_abort
*/
start_signal_handler(); // Creates pidfile

View file

@ -47,6 +47,8 @@
#include "probes_mysql.h"
#include <debug_sync.h>
#include "proxy_protocol.h"
#include <mysql_com_server.h>
#include <mysqld.h>
PSI_memory_key key_memory_NET_buff;
PSI_memory_key key_memory_NET_compress_packet;
@ -62,13 +64,9 @@ PSI_memory_key key_memory_NET_compress_packet;
*/
#ifdef EXTRA_DEBUG
#define EXTRA_DEBUG_fprintf fprintf
#define EXTRA_DEBUG_fflush fflush
#define EXTRA_DEBUG_ASSERT DBUG_ASSERT
#else
static void inline EXTRA_DEBUG_fprintf(...) {}
#ifndef MYSQL_SERVER
static int inline EXTRA_DEBUG_fflush(...) { return 0; }
#endif
#endif /* EXTRA_DEBUG */
#ifdef MYSQL_SERVER
@ -92,22 +90,6 @@ static void inline MYSQL_SERVER_my_error(...) {}
the client should have a bigger max_allowed_packet.
*/
#if defined(_WIN32) || !defined(MYSQL_SERVER)
/* The following is because alarms doesn't work on windows. */
#ifndef NO_ALARM
#define NO_ALARM
#endif
#endif
#ifndef NO_ALARM
#include "my_pthread.h"
void sql_print_error(const char *format,...);
#else
#define DONT_USE_THR_ALARM
#endif /* NO_ALARM */
#include "thr_alarm.h"
#ifdef MYSQL_SERVER
/*
The following variables/functions should really not be declared
@ -158,22 +140,18 @@ my_bool my_net_init(NET *net, Vio *vio, void *thd, uint my_flags)
net->last_errno=0;
net->thread_specific_malloc= MY_TEST(my_flags & MY_THREAD_SPECIFIC);
net->thd= 0;
#ifdef MYSQL_SERVER
net->extension= NULL;
net->thd= thd;
#endif
if (vio)
{
/* For perl DBI/DBD. */
net->fd= vio_fd(vio);
#if defined(MYSQL_SERVER) && !defined(_WIN32)
if (!(test_flags & TEST_BLOCKING))
{
my_bool old_mode;
vio_blocking(vio, FALSE, &old_mode);
}
#endif
vio_fastsend(vio);
}
DBUG_RETURN(0);
@ -646,12 +624,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
{
size_t length;
const uchar *pos,*end;
thr_alarm_t alarmed;
#ifndef NO_ALARM
ALARM alarm_buff;
#endif
uint retry_count=0;
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
#if defined(MYSQL_SERVER)
@ -707,62 +680,21 @@ net_real_write(NET *net,const uchar *packet, size_t len)
#ifdef DEBUG_DATA_PACKETS
DBUG_DUMP("data_written", packet, len);
#endif
#ifndef NO_ALARM
thr_alarm_init(&alarmed);
if (net_blocking)
thr_alarm(&alarmed, net->write_timeout, &alarm_buff);
#else
alarmed=0;
/* Write timeout is set in my_net_set_write_timeout */
#endif /* NO_ALARM */
pos= packet;
end=pos+len;
while (pos != end)
{
if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
length= vio_write(net->vio, pos, (size_t) (end - pos));
if (ssize_t(length) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
#if !defined(_WIN32)
if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
bool interrupted= vio_should_retry(net->vio);
if (interrupted || !length)
{
if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff))
{ /* Always true for client */
my_bool old_mode;
while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
{
if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
continue;
EXTRA_DEBUG_fprintf(stderr,
"%s: my_net_write: fcntl returned error %d, aborting thread\n",
my_progname,vio_errno(net->vio));
net->error= 2; /* Close socket */
net->last_errno= ER_NET_PACKET_TOO_LARGE;
MYSQL_SERVER_my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
goto end;
}
retry_count=0;
continue;
}
if (retry_count++ < net->retry_count)
continue;
}
else
#endif /* !defined(_WIN32) */
if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
interrupted)
{
if (retry_count++ < net->retry_count)
continue;
EXTRA_DEBUG_fprintf(stderr, "%s: write looped, aborting thread\n",
my_progname);
}
#ifndef MYSQL_SERVER
if (vio_errno(net->vio) == SOCKET_EINTR)
{
DBUG_PRINT("warning",("Interrupted write. Retrying..."));
continue;
}
#endif /* !defined(MYSQL_SERVER) */
EXTRA_DEBUG_fprintf(stderr, "%s: write looped, aborting thread\n",
my_progname);
net->error= 2; /* Close socket */
net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
ER_NET_ERROR_ON_WRITE);
@ -772,112 +704,14 @@ net_real_write(NET *net,const uchar *packet, size_t len)
pos+=length;
update_statistics(thd_increment_bytes_sent(net->thd, length));
}
#ifndef _WIN32
end:
#endif
#ifdef HAVE_COMPRESS
if (net->compress)
my_free((void*) packet);
#endif
if (thr_alarm_in_use(&alarmed))
{
my_bool old_mode;
thr_end_alarm(&alarmed);
if (!net_blocking)
vio_blocking(net->vio, net_blocking, &old_mode);
}
net->reading_or_writing=0;
DBUG_RETURN(((int) (pos != end)));
net->reading_or_writing= 0;
DBUG_RETURN(pos != end);
}
/*****************************************************************************
** Read something from server/clinet
*****************************************************************************/
#ifndef NO_ALARM
static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
thr_alarm_t *alarmed)
{
uint retry_count=0;
while (length > 0)
{
size_t tmp;
if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(alarmed) && interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < net->retry_count)
continue;
}
return 1;
}
length-= tmp;
buff+= tmp;
}
return 0;
}
/**
Help function to clear the commuication buffer when we get a too big packet.
@param net Communication handle
@param remain Bytes to read
@param alarmed Parameter for thr_alarm()
@param alarm_buff Parameter for thr_alarm()
@retval
0 Was able to read the whole packet
@retval
1 Got mailformed packet from client
*/
static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
ALARM *alarm_buff)
{
longlong limit= net->max_packet_size*net->net_skip_rest_factor;
uint32 old=remain;
DBUG_ENTER("my_net_skip_rest");
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
/* The following is good for debugging */
update_statistics(thd_increment_net_big_packet_count(net->thd, 1));
if (!thr_alarm_in_use(alarmed))
{
my_bool old_mode;
if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
vio_blocking(net->vio, TRUE, &old_mode) < 0)
DBUG_RETURN(1); /* Can't setup, abort */
}
for (;;)
{
while (remain > 0)
{
size_t length= MY_MIN(remain, net->max_packet);
if (net_safe_read(net, net->buff, length, alarmed))
DBUG_RETURN(1);
update_statistics(thd_increment_bytes_received(net->thd, length));
remain -= (uint32) length;
limit-= length;
if (limit < 0)
DBUG_RETURN(1);
}
if (old != MAX_PACKET_LENGTH)
break;
if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
DBUG_RETURN(1);
limit-= NET_HEADER_SIZE;
old=remain= uint3korr(net->buff);
net->pkt_nr++;
}
DBUG_RETURN(0);
}
#endif /* NO_ALARM */
/**
Try to parse and process proxy protocol header.
@ -951,26 +785,17 @@ static handle_proxy_header_result handle_proxy_header(NET *net)
Returns length of packet.
*/
static ulong
my_real_read(NET *net, size_t *complen,
my_bool header __attribute__((unused)))
static ulong my_real_read(NET *net, size_t *complen,
my_bool header __attribute__((unused)))
{
uchar *pos;
size_t length;
uint i,retry_count=0;
ulong len=packet_error;
my_bool expect_error_packet __attribute__((unused))= 0;
thr_alarm_t alarmed;
#ifndef NO_ALARM
ALARM alarm_buff;
#endif
retry:
my_bool net_blocking=vio_is_blocking(net->vio);
uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
NET_HEADER_SIZE);
#ifdef MYSQL_SERVER
size_t count= remain;
struct st_net_server *server_extension= 0;
@ -983,254 +808,143 @@ retry:
server_extension->m_before_header(net, user_data, count);
}
}
#endif
*complen = 0;
net->reading_or_writing=1;
thr_alarm_init(&alarmed);
#ifndef NO_ALARM
if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
#else
/* Read timeout is set in my_net_set_read_timeout */
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
for (i=0 ; i < 2 ; i++)
pos = net->buff + net->where_b;
for (i=0; i < 2 ; i++)
{
while (remain > 0)
{
while (remain > 0)
length= vio_read(net->vio, pos, remain);
if ((ssize_t) length <= 0)
{
/* First read is done with non blocking mode */
if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
DBUG_PRINT("info", ("vio_read returned %lld errno: %d",
(long long) length, vio_errno(net->vio)));
if (i == 0 && unlikely(thd_net_is_killed((THD *) net->thd)))
{
my_bool interrupted = vio_should_retry(net->vio);
DBUG_PRINT("info",("vio_read returned %ld errno: %d",
(long) length, vio_errno(net->vio)));
if (i== 0 && unlikely(thd_net_is_killed((THD*) net->thd)))
{
DBUG_PRINT("info", ("thd is killed"));
len= packet_error;
net->error= 0;
net->last_errno= ER_CONNECTION_KILLED;
MYSQL_SERVER_my_error(net->last_errno, MYF(0));
goto end;
}
#if !defined(_WIN32) && defined(MYSQL_SERVER)
/*
We got an error that there was no data on the socket. We now set up
an alarm to not 'read forever', change the socket to the blocking
mode and try again
*/
if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
{
if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
{
my_bool old_mode;
while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
{
if (vio_should_retry(net->vio) &&
retry_count++ < net->retry_count)
continue;
DBUG_PRINT("error",
("fcntl returned error %d, aborting thread",
vio_errno(net->vio)));
EXTRA_DEBUG_fprintf(stderr,
"%s: read: fcntl returned error %d, aborting thread\n",
my_progname,vio_errno(net->vio));
len= packet_error;
net->error= 2; /* Close socket */
net->last_errno= ER_NET_FCNTL_ERROR;
MYSQL_SERVER_my_error(ER_NET_FCNTL_ERROR, MYF(0));
goto end;
}
retry_count=0;
continue;
}
}
#endif /* (!defined(_WIN32) && defined(MYSQL_SERVER) */
if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < net->retry_count)
continue;
EXTRA_DEBUG_fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
my_progname,vio_errno(net->vio));
}
#ifndef MYSQL_SERVER
if (length != 0 && vio_errno(net->vio) == SOCKET_EINTR)
{
DBUG_PRINT("warning",("Interrupted read. Retrying..."));
continue;
}
#endif
DBUG_PRINT("error",("Couldn't read packet: remain: %u errno: %d length: %ld",
remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2; /* Close socket */
net->last_errno= (vio_was_timeout(net->vio) ?
ER_NET_READ_INTERRUPTED :
ER_NET_READ_ERROR);
DBUG_PRINT("info", ("thd is killed"));
len= packet_error;
net->error= 0;
net->last_errno= ER_CONNECTION_KILLED;
MYSQL_SERVER_my_error(net->last_errno, MYF(0));
goto end;
}
remain -= (uint32) length;
pos+= length;
update_statistics(thd_increment_bytes_received(net->thd, length));
goto end;
}
if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
continue;
EXTRA_DEBUG_fprintf(stderr,
"%s: read looped with error %d, aborting thread\n",
my_progname, vio_errno(net->vio));
DBUG_PRINT("error",
("Couldn't read packet: remain: %u errno: %d length: %ld",
remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2;
net->last_errno= (vio_was_timeout(net->vio) ? ER_NET_READ_INTERRUPTED
: ER_NET_READ_ERROR);
MYSQL_SERVER_my_error(net->last_errno, MYF(0));
goto end;
}
remain-= (uint32) length;
pos+= length;
update_statistics(thd_increment_bytes_received(net->thd, length));
}
#ifdef DEBUG_DATA_PACKETS
DBUG_DUMP("data_read", net->buff+net->where_b, length);
DBUG_DUMP("data_read", net->buff + net->where_b, length);
#endif
if (i == 0)
{ /* First parts is packet length */
size_t helping;
if (i == 0)
{
/* First part is packet length */
size_t helping;
#ifndef DEBUG_DATA_PACKETS
DBUG_DUMP("packet_header", net->buff+net->where_b,
NET_HEADER_SIZE);
#endif
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
{
#ifndef MYSQL_SERVER
if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1))
{
/*
If the server was killed then the server may have missed the
last sent client packet and the packet numbering may be one off.
*/
DBUG_PRINT("warning", ("Found possible out of order packets"));
expect_error_packet= 1;
}
else
#endif
goto packets_out_of_order;
}
net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
/*
The following uint3korr() may read 4 bytes, so make sure we don't
read unallocated or uninitialized memory. The right-hand expression
must match the size of the buffer allocated in net_realloc().
*/
DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
/*
If the packet is compressed then complen > 0 and contains the
number of bytes in the uncompressed packet
*/
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
}
#endif
len=uint3korr(net->buff+net->where_b);
if (!len) /* End of big multi-packet */
goto end;
helping = MY_MAX(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
if (net_realloc(net,helping))
{
#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
if (!net->compress &&
!my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
net->error= 3; /* Successfully skiped packet */
#endif
len= packet_error; /* Return error and close connection */
goto end;
}
}
pos=net->buff + net->where_b;
remain = (uint32) len;
#ifdef MYSQL_SERVER
if (server_extension != NULL)
{
void *user_data= server_extension->m_user_data;
server_extension->m_after_header(net, user_data, count, 0);
server_extension= NULL;
}
DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
#endif
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
{
goto packets_out_of_order;
}
#ifndef MYSQL_SERVER
else if (expect_error_packet)
net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
/*
This check is safe both for compressed and not compressed protocol
as for the compressed protocol errors are not compressed anymore.
The following uint3korr() may read 4 bytes, so make sure we don't
read unallocated or uninitialized memory. The right-hand expression
must match the size of the buffer allocated in net_realloc().
*/
if (net->buff[net->where_b] != (uchar) 255)
{
/* Restore pkt_nr to original value */
net->pkt_nr--;
goto packets_out_of_order;
}
DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
/*
If the packet is compressed then complen > 0 and contains the
number of bytes in the uncompressed packet
*/
*complen= uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
}
#endif
len= uint3korr(net->buff + net->where_b);
if (!len) /* End of big multi-packet */
goto end;
helping= MY_MAX(len, *complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
if (net_realloc(net, helping))
{
len= packet_error; /* Return error and close connection */
goto end;
}
}
pos= net->buff + net->where_b;
remain= (uint32) len;
if (server_extension != NULL)
{
void *user_data= server_extension->m_user_data;
server_extension->m_after_header(net, user_data, count, 0);
server_extension= NULL;
}
}
}
end:
if (thr_alarm_in_use(&alarmed))
{
my_bool old_mode;
thr_end_alarm(&alarmed);
if (!net_blocking)
vio_blocking(net->vio, net_blocking, &old_mode);
}
net->reading_or_writing=0;
#ifdef DEBUG_DATA_PACKETS
if (len != packet_error)
DBUG_DUMP("data_read", net->buff+net->where_b, len);
#endif
#ifdef MYSQL_SERVER
if (server_extension != NULL)
{
void *user_data= server_extension->m_user_data;
server_extension->m_after_header(net, user_data, count, 1);
DBUG_ASSERT(len == packet_error || len == 0);
}
#endif
return(len);
packets_out_of_order:
packets_out_of_order :
switch (handle_proxy_header(net))
{
switch (handle_proxy_header(net)) {
case ABORT:
/* error happened, message is already written. */
len= packet_error;
goto end;
case RETRY:
goto retry;
case IGNORE:
break;
}
DBUG_PRINT("error",
("Packets out of order (Found: %d, expected %u)",
(int) net->buff[net->where_b + 3],
net->pkt_nr));
EXTRA_DEBUG_ASSERT(0);
/*
We don't make noise server side, since the client is expected
to break the protocol for e.g. --send LOAD DATA .. LOCAL where
the server expects the client to send a file, but the client
may reply with a new command instead.
*/
#ifndef MYSQL_SERVER
EXTRA_DEBUG_fflush(stdout);
EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
(int) net->buff[net->where_b + 3],
(uint) (uchar) net->pkt_nr);
EXTRA_DEBUG_fflush(stderr);
#endif
case ABORT:
/* error happened, message is already written. */
len= packet_error;
MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
goto end;
case RETRY:
goto retry;
case IGNORE:
break;
}
DBUG_PRINT("error", ("Packets out of order (Found: %d, expected %u)",
(int) net->buff[net->where_b + 3], net->pkt_nr));
EXTRA_DEBUG_ASSERT(0);
/*
We don't make noise server side, since the client is expected
to break the protocol for e.g. --send LOAD DATA .. LOCAL where
the server expects the client to send a file, but the client
may reply with a new command instead.
*/
len= packet_error;
MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
goto end;
}

View file

@ -36,7 +36,6 @@
#include "rpl_filter.h"
#include "repl_failsafe.h"
#include "transaction.h"
#include <thr_alarm.h>
#include <my_dir.h>
#include <sql_common.h>
#include <errmsg.h>
@ -1075,24 +1074,11 @@ terminate_slave_thread(THD *thd,
mysql_mutex_lock(&thd->LOCK_thd_kill);
mysql_mutex_lock(&thd->LOCK_thd_data);
#ifndef DONT_USE_THR_ALARM
/*
Error codes from pthread_kill are:
EINVAL: invalid signal number (can't happen)
ESRCH: thread already killed (can happen, should be ignored)
*/
int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm);
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake_no_mutex(NOT_KILLED);
mysql_mutex_unlock(&thd->LOCK_thd_kill);
mysql_mutex_unlock(&thd->LOCK_thd_data);
/*
There is a small chance that slave thread might miss the first
alarm. To protect againts it, resend the signal until it reacts
*/
struct timespec abstime;
set_timespec(abstime,2);
error= mysql_cond_timedwait(term_cond, term_lock, &abstime);

View file

@ -48,7 +48,6 @@
#include "sql_audit.h"
#include <m_ctype.h>
#include <sys/stat.h>
#include <thr_alarm.h>
#include <mysys_err.h>
#include <limits.h>
@ -1903,9 +1902,6 @@ void THD::awake_no_mutex(killed_state state_to_set)
}
#endif
/* Mark the target thread's alarm request expired, and signal alarm. */
thr_alarm_kill(thread_id);
/* Send an event to the scheduler that a thread should be killed. */
if (!slave_thread)
MYSQL_CALLBACK(scheduler, post_kill_notification, (this));

View file

@ -26,7 +26,6 @@
#include "keycaches.h"
#include "my_json_writer.h"
#include <hash.h>
#include <thr_alarm.h>
#include "sql_connect.h"
#include "thread_cache.h"
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
@ -611,17 +610,6 @@ Open streams: %10lu\n",
my_file_opened,
my_stream_opened);
#ifndef DONT_USE_THR_ALARM
ALARM_INFO alarm_info;
thr_alarm_info(&alarm_info);
printf("\nAlarm status:\n\
Active alarms: %u\n\
Max used alarms: %u\n\
Next alarm time: %lu\n",
alarm_info.active_alarms,
alarm_info.max_used_alarms,
(ulong)alarm_info.next_alarm_time);
#endif
display_table_locks();
#if defined(HAVE_MALLINFO2)
struct mallinfo2 info = mallinfo2();

View file

@ -38,7 +38,6 @@
#include "my_sys.h"
#include "events.h"
#include <thr_alarm.h>
#include "slave.h"
#include "rpl_mi.h"
#include "rpl_filter.h"
@ -1735,10 +1734,6 @@ Sys_max_binlog_size(
static bool fix_max_connections(sys_var *self, THD *thd, enum_var_type type)
{
#ifndef EMBEDDED_LIBRARY
resize_thr_alarm(max_connections + extra_max_connections +
global_system_variables.max_insert_delayed_threads + 10);
#endif
return false;
}
@ -6753,13 +6748,6 @@ static Sys_var_enum Sys_histogram_type(
SESSION_VAR(histogram_type), CMD_LINE(REQUIRED_ARG),
histogram_types, DEFAULT(2));
static Sys_var_mybool Sys_no_thread_alarm(
"debug_no_thread_alarm",
"Disable system thread alarm calls. Disabling it may be useful "
"in debugging or testing, never do it in production",
READ_ONLY GLOBAL_VAR(my_disable_thr_alarm), CMD_LINE(OPT_ARG),
DEFAULT(FALSE));
static Sys_var_mybool Sys_query_cache_strip_comments(
"query_cache_strip_comments",
"Strip all comments from a query before storing it "