diff options
Diffstat (limited to 'mysys/thr_alarm.c')
-rw-r--r-- | mysys/thr_alarm.c | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c new file mode 100644 index 00000000..b98775e1 --- /dev/null +++ b/mysys/thr_alarm.c @@ -0,0 +1,845 @@ +/* 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*) ¶m[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 */ |