Commit e61dea1b authored by unknown's avatar unknown

Fix wait_timeout (and kill) handling on Mac OS X by cleaning up how

signal handlers are set up, the blocking flags for sockets are set,
and which thread-related functions are used. (Bug #8731)


configure.in:
  Fix flags for Darwin 6 and later. Simplify Darwin 7-9 blocks to simply
  be a catch-all for *darwin* so that future Darwin releases get the
  latest flags.
include/config-win.h:
  Define my_sigset() instead of sigset().
include/my_pthread.h:
  Define my_sigset() instead of trying to monkey with sigset(), and favor
  an implementation based on sigaction().
mysys/my_pthread.c:
  Remove pthread_signal(), which is identical to the new my_sigset() macro.
mysys/thr_alarm.c:
  Use my_sigset() instead of sigset().
sql/mysqld.cc:
  Use my_sigset() instead of signal() and sigset(), remove unnecessary
  definition of sigset on __amiga__. Remove unused THREAD_SPECIFIC_SIGPIPE
  code.
  
  A future improvement would be to re-assess the use of sigaction() here
  and convert its usage to use my_sigset().
vio/vio.c:
  Always call fcntl() to initialize flags of socket in initialization to
  avoid problems on systems that don't report the flags on a socket
  correctly right after it has been returned from accept(), such as
  FreeBSD, Mac OS X, and possibly other BSD-derived systems.
vio/viosocket.c:
  If fcntl() fails in vio_blocking(), restore the flags stored in the
  vio struct.
mysql-test/r/wait_timeout.result:
  New BitKeeper file ``mysql-test/r/wait_timeout.result''
mysql-test/t/wait_timeout-master.opt:
  New BitKeeper file ``mysql-test/t/wait_timeout-master.opt''
mysql-test/t/wait_timeout.test:
  New BitKeeper file ``mysql-test/t/wait_timeout.test''
parent 78f5997a
......@@ -1102,7 +1102,7 @@ case $SYSTEM_TYPE in
*darwin5*)
if test "$ac_cv_prog_gcc" = "yes"
then
FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
FLAGS="-traditional-cpp -DHAVE_DARWIN5_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
CFLAGS="$CFLAGS $FLAGS"
CXXFLAGS="$CXXFLAGS $FLAGS"
MAX_C_OPTIMIZE="-O"
......@@ -1112,23 +1112,13 @@ case $SYSTEM_TYPE in
*darwin6*)
if test "$ac_cv_prog_gcc" = "yes"
then
FLAGS="-DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
CFLAGS="$CFLAGS $FLAGS"
CXXFLAGS="$CXXFLAGS $FLAGS"
MAX_C_OPTIMIZE="-O"
fi
;;
*darwin[[7-8]]*)
# don't forget to escape [] like above
if test "$ac_cv_prog_gcc" = "yes"
then
FLAGS="-DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT"
CFLAGS="$CFLAGS $FLAGS"
CXXFLAGS="$CXXFLAGS $FLAGS"
MAX_C_OPTIMIZE="-O"
fi
;;
*darwin9*)
*darwin*)
if test "$ac_cv_prog_gcc" = "yes"
then
FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT"
......
......@@ -192,7 +192,7 @@ typedef uint rf_SetTimer;
/* Convert some simple functions to Posix */
#define sigset(A,B) signal((A),(B))
#define my_sigset(A,B) signal((A),(B))
#define finite(A) _finite(A)
#define sleep(A) Sleep((A)*1000)
#define popen(A) popen(A,B) _popen((A),(B))
......
......@@ -289,8 +289,6 @@ extern int my_pthread_create_detached;
#undef HAVE_PTHREAD_RWLOCK_RDLOCK
#undef HAVE_SNPRINTF
#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B))
#define signal(A,B) pthread_signal((A),(void (*)(int)) (B))
#define my_pthread_attr_setprio(A,B)
#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */
......@@ -322,14 +320,26 @@ extern int my_pthread_cond_init(pthread_cond_t *mp,
#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX)
int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */
#endif
#if !defined(HAVE_SIGSET) && !defined(HAVE_mit_thread) && !defined(sigset)
#define sigset(A,B) do { struct sigaction s; sigset_t set; \
/*
We define my_sigset() and use that instead of the system sigset() so that
we can favor an implementation based on sigaction(). On some systems, such
as Mac OS X, sigset() results in flags such as SA_RESTART being set, and
we want to make sure that no such flags are set.
*/
#if defined(HAVE_SIGACTION) && !defined(my_sigset)
#define my_sigset(A,B) do { struct sigaction s; sigset_t set; \
sigemptyset(&set); \
s.sa_handler = (B); \
s.sa_mask = set; \
s.sa_flags = 0; \
sigaction((A), &s, (struct sigaction *) NULL); \
} while (0)
#elif defined(HAVE_SIGSET) && !defined(my_sigset)
#define my_sigset(A,B) sigset((A),(B))
#elif !defined(my_sigset)
#define my_sigset(A,B) signal((A),(B))
#endif
#ifndef my_pthread_setprio
......@@ -409,16 +419,13 @@ struct tm *gmtime_r(const time_t *clock, struct tm *res);
#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
#endif
#ifdef HAVE_DARWIN_THREADS
#ifdef HAVE_DARWIN5_THREADS
#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
#define pthread_kill(A,B) pthread_dummy(0)
#define pthread_condattr_init(A) pthread_dummy(0)
#define pthread_condattr_destroy(A) pthread_dummy(0)
#define pthread_signal(A,B) pthread_dummy(0)
#undef pthread_detach_this_thread
#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(tmp); }
#undef sigset
#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B))
#endif
#if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER)
......
select 1;
1
1
select 2;
ERROR HY000: MySQL server has gone away
select 3;
3
3
#
# Bug #8731: wait_timeout does not work on Mac OS X
#
--disable_reconnect
select 1;
# wait_timeout is 2, so we should get disconnected now
--sleep 5
--error 2006
select 2;
--enable_reconnect
select 3;
......@@ -404,23 +404,6 @@ int sigwait(sigset_t *setp, int *sigp)
#endif /* DONT_USE_SIGSUSPEND */
#endif /* HAVE_SIGWAIT */
/*****************************************************************************
** Implement pthread_signal for systems that can't use signal() with threads
** Currently this is only used with BSDI 3.0
*****************************************************************************/
#ifdef USE_PTHREAD_SIGNAL
int pthread_signal(int sig, void (*func)())
{
struct sigaction sact;
sact.sa_flags= 0;
sact.sa_handler= func;
sigemptyset(&sact.sa_mask);
sigaction(sig, &sact, (struct sigaction*) 0);
return 0;
}
#endif
/****************************************************************************
The following functions fixes that all pthread functions should work
......
......@@ -80,17 +80,7 @@ void init_thr_alarm(uint max_alarms)
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_alarm,NULL);
#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
#if defined(HAVE_mit_thread)
sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */
#else
{
struct sigaction sact;
sact.sa_flags = 0;
bzero((char*) &sact, sizeof(sact));
sact.sa_handler = thread_alarm;
sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0);
}
#endif
my_sigset(THR_CLIENT_ALARM,thread_alarm);
#endif
sigemptyset(&s);
sigaddset(&s, THR_SERVER_ALARM);
......@@ -110,12 +100,12 @@ void init_thr_alarm(uint max_alarms)
#elif defined(USE_ONE_SIGNAL_HAND)
pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
#if THR_SERVER_ALARM == THR_CLIENT_ALARM
sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */
my_sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
#endif
#else
my_sigset(THR_SERVER_ALARM, process_alarm);
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
sigset(THR_SERVER_ALARM,process_alarm);
#endif
DBUG_VOID_RETURN;
}
......@@ -290,7 +280,7 @@ sig_handler process_alarm(int sig __attribute__((unused)))
printf("thread_alarm\n"); fflush(stdout);
#endif
#ifdef DONT_REMEMBER_SIGNAL
sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
my_sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
#endif
return;
}
......@@ -310,7 +300,7 @@ sig_handler process_alarm(int sig __attribute__((unused)))
process_alarm_part2(sig);
#ifndef USE_ALARM_THREAD
#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
sigset(THR_SERVER_ALARM,process_alarm);
my_sigset(THR_SERVER_ALARM,process_alarm);
#endif
pthread_mutex_unlock(&LOCK_alarm);
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
......@@ -512,7 +502,7 @@ static sig_handler thread_alarm(int sig)
printf("thread_alarm\n"); fflush(stdout);
#endif
#ifdef DONT_REMEMBER_SIGNAL
sigset(sig,thread_alarm); /* int. thread system calls */
my_sigset(sig,thread_alarm); /* int. thread system calls */
#endif
}
#endif
......@@ -916,7 +906,7 @@ static sig_handler print_signal_warning(int sig)
printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
fflush(stdout);
#ifdef DONT_REMEMBER_SIGNAL
sigset(sig,print_signal_warning); /* int. thread system calls */
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
#ifndef OS2
if (sig == SIGALRM)
......
......@@ -846,7 +846,7 @@ static void __cdecl kill_server(int sig_ptr)
RETURN_FROM_KILL_SERVER;
kill_in_progress=TRUE;
abort_loop=1; // This should be set
signal(sig,SIG_IGN);
my_sigset(sig,SIG_IGN);
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
......@@ -894,11 +894,6 @@ extern "C" pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
}
#endif
#if defined(__amiga__)
#undef sigset
#define sigset signal
#endif
extern "C" sig_handler print_signal_warning(int sig)
{
if (!DBUG_IN_USE)
......@@ -908,7 +903,7 @@ extern "C" sig_handler print_signal_warning(int sig)
sig,my_thread_id());
}
#ifdef DONT_REMEMBER_SIGNAL
sigset(sig,print_signal_warning); /* int. thread system calls */
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
if (sig == SIGALRM)
......@@ -1570,23 +1565,6 @@ void flush_thread_cache()
}
/*
Aborts a thread nicely. Commes here on SIGPIPE
TODO: One should have to fix that thr_alarm know about this
thread too.
*/
#ifdef THREAD_SPECIFIC_SIGPIPE
extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
{
THD *thd=current_thd;
DBUG_ENTER("abort_thread");
if (thd)
thd->killed=1;
DBUG_VOID_RETURN;
}
#endif
/******************************************************************************
Setup a signal thread with handles all signals.
Because Linux doesn't support schemas use a mutex to check that
......@@ -2002,8 +1980,8 @@ static void init_signals(void)
DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
sigset(THR_KILL_SIGNAL,end_thread_signal);
sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
my_sigset(THR_KILL_SIGNAL,end_thread_signal);
my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
......@@ -2037,13 +2015,8 @@ static void init_signals(void)
}
#endif
(void) sigemptyset(&set);
#ifdef THREAD_SPECIFIC_SIGPIPE
sigset(SIGPIPE,abort_thread);
sigaddset(&set,SIGPIPE);
#else
(void) signal(SIGPIPE,SIG_IGN); // Can't know which thread
my_sigset(SIGPIPE,SIG_IGN);
sigaddset(&set,SIGPIPE);
#endif
sigaddset(&set,SIGINT);
#ifndef IGNORE_SIGHUP_SIGQUIT
sigaddset(&set,SIGQUIT);
......
......@@ -136,10 +136,18 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
vio->sd);
#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
#if !defined(NO_FCNTL_NONBLOCK)
#if defined(__FreeBSD__)
fcntl(sd, F_SETFL, vio->fcntl_mode); /* Yahoo! FreeBSD patch */
#endif
vio->fcntl_mode = fcntl(sd, F_GETFL);
/*
We call fcntl() to set the flags and then immediately read them back
to make sure that we and the system are in agreement on the state of
things.
An example of why we need to do this is FreeBSD (and apparently some
other BSD-derived systems, like Mac OS X), where the system sometimes
reports that the socket is set for non-blocking when it really will
block.
*/
fcntl(sd, F_SETFL, vio->fcntl_mode);
vio->fcntl_mode= fcntl(sd, F_GETFL);
#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
/* Non blocking sockets doesn't work good on HPUX 11.0 */
(void) ioctl(sd,FIOSNBIO,0);
......
......@@ -92,7 +92,14 @@ int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode,
else
vio->fcntl_mode |= O_NONBLOCK; /* set bit */
if (old_fcntl != vio->fcntl_mode)
r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
{
r= fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
if (r == -1)
{
DBUG_PRINT("info", ("fcntl failed, errno %d", errno));
vio->fcntl_mode= old_fcntl;
}
}
}
#else
r= set_blocking_mode ? 0 : 1;
......
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