summaryrefslogtreecommitdiff
path: root/mysys/thr_alarm.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/thr_alarm.c')
-rw-r--r--mysys/thr_alarm.c874
1 files changed, 874 insertions, 0 deletions
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
new file mode 100644
index 00000000000..a681c1b110d
--- /dev/null
+++ b/mysys/thr_alarm.c
@@ -0,0 +1,874 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include <global.h>
+#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 THREAD
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h> /* AIX needs this for fd_set */
+#endif
+
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
+static my_bool alarm_aborted=1;
+my_bool thr_alarm_inited=0;
+
+#if !defined(__WIN__) && !defined(__OS2__)
+#ifndef DONT_USE_THR_ALARM /* thr_alarm disabled */
+
+static pthread_mutex_t LOCK_alarm;
+static sigset_t full_signal_set;
+static QUEUE alarm_queue;
+pthread_t alarm_thread;
+
+#ifdef USE_ALARM_THREAD
+static pthread_cond_t COND_alarm;
+static void *alarm_handler(void *arg);
+#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
+#else
+#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
+#endif
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig __attribute__((unused)));
+#endif
+
+static int compare_ulong(void *not_used __attribute__((unused)),
+ byte *a_ptr,byte* 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;
+ init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
+ compare_ulong,NullS);
+ sigfillset(&full_signal_set); /* Neaded to block signals */
+ pthread_mutex_init(&LOCK_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;
+ sact.sa_handler = thread_alarm;
+ sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0);
+ }
+#endif
+#endif
+ 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_cond_init(&COND_alarm,NULL);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,8196);
+
+ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+ VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
+ VOID(pthread_attr_destroy(&thr_attr));
+ }
+#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 */
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+#endif
+#else
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+/*
+** Request alarm after sec seconds.
+** A pointer is returned with points to a non-zero int when the alarm has been
+** given. This can't be called from the alarm-handling thread.
+** Returns 0 if no more alarms are allowed (aborted by process)
+*/
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
+{
+ ulong now;
+ sigset_t old_mask;
+ my_bool reschedule;
+ DBUG_ENTER("thr_alarm");
+ DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
+
+ now=(ulong) time((time_t*) 0);
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
+ if (alarm_aborted)
+ { /* No signal thread */
+ DBUG_PRINT("info", ("alarm aborted"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ if (alarm_queue.elements == alarm_queue.max_elements)
+ {
+ DBUG_PRINT("info", ("alarm queue full"));
+ fprintf(stderr,"Warning: thr_alarm queue is full\n");
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ reschedule= (!alarm_queue.elements ||
+ (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) >
+ (int) sec);
+ if (!alarm_data)
+ {
+ if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
+ {
+ DBUG_PRINT("info", ("failed my_malloc()"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ alarm_data->malloced=1;
+ }
+ else
+ alarm_data->malloced=0;
+ alarm_data->expire_time=now+sec;
+ alarm_data->alarmed=0;
+ alarm_data->thread=pthread_self();
+ queue_insert(&alarm_queue,(byte*) alarm_data);
+
+ /* Reschedule alarm if the current one has more than sec left */
+ if (reschedule)
+ {
+ DBUG_PRINT("info", ("reschedule"));
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(sec); /* purecov: inspected */
+ else
+ reschedule_alarms(); /* Reschedule alarms */
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ (*alrm)= &alarm_data->alarmed;
+ DBUG_RETURN(0);
+}
+
+
+/*
+** Remove alarm from list of alarms
+*/
+
+void thr_end_alarm(thr_alarm_t *alarmed)
+{
+ ALARM *alarm_data;
+ sigset_t old_mask;
+ uint i;
+ bool found=0;
+ DBUG_ENTER("thr_end_alarm");
+
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+
+ alarm_data= (ALARM*) ((byte*) *alarmed - offsetof(ALARM,alarmed));
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
+ {
+ queue_remove(&alarm_queue,i),MYF(0);
+ if (alarm_data->malloced)
+ my_free((gptr) alarm_data,MYF(0));
+ found=1;
+ break;
+ }
+ }
+ if (!found)
+ {
+#ifdef MAIN
+ printf("Warning: Didn't find alarm %lx in queue of %d alarms\n",
+ (long) *alarmed, alarm_queue.elements);
+#endif
+ DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n",*alarmed));
+ }
+ if (alarm_aborted && !alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_VOID_RETURN;
+}
+
+ /*
+ Come here when some alarm in queue is due.
+ Mark all alarms with are finnished in list.
+ Shedule 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;
+ ALARM *alarm_data;
+ DBUG_ENTER("process_alarm");
+ DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
+
+#if THR_SERVER_ALARM == THR_CLIENT_ALARM
+ if (!pthread_equal(pthread_self(),alarm_thread))
+ {
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
+#endif
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("process_alarm\n"); fflush(stdout);
+#endif
+#ifndef USE_ALARM_THREAD
+ pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+#endif
+ if (alarm_queue.elements)
+ {
+ if (alarm_aborted)
+ {
+ uint i;
+ for (i=0 ; i < alarm_queue.elements ;)
+ {
+ 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 */
+ }
+ else
+ i++; /* Signal next thread */
+ }
+#ifndef USE_ALARM_THREAD
+ if (alarm_queue.elements)
+ alarm(1); /* Signal soon again */
+#endif
+ }
+ else
+ {
+ ulong now=(ulong) time((time_t*) 0);
+ ulong 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
+ queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
+ if (!alarm_queue.elements)
+ break;
+ }
+ else
+ {
+ alarm_data->expire_time=next;
+ queue_replaced(&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));
+ }
+#endif
+ }
+ }
+#ifndef USE_ALARM_THREAD
+#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Shedule all alarms now.
+** When all alarms are given, Free alarm memory and don't allow more alarms.
+*/
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ pthread_mutex_lock(&LOCK_alarm);
+ if (!alarm_aborted)
+ {
+ DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
+ alarm_aborted=1; /* mark aborted */
+ if (!alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(1); /* Shut down everything soon */
+ else
+ reschedule_alarms();
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Remove another thread from the alarm
+*/
+
+void thr_alarm_kill(pthread_t thread_id)
+{
+ uint i;
+ pthread_mutex_lock(&LOCK_alarm);
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
+ thread_id))
+ {
+ ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
+ tmp->expire_time=0;
+ queue_insert(&alarm_queue,(byte*) tmp);
+ reschedule_alarms();
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+}
+
+
+/*
+** This is here for thread to get interruptet from read/write/fcntl
+** ARGSUSED
+*/
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig)
+{
+#ifdef MAIN
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,thread_alarm); /* int. thread system calls */
+#endif
+}
+#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();
+ pthread_mutex_lock(&LOCK_alarm);
+ for (;;)
+ {
+ if (alarm_queue.elements)
+ {
+ ulong sleep_time,now=time((time_t*) 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;
+ if ((error=pthread_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)
+ break;
+ else if ((error=pthread_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 */
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_exit(0);
+ return 0; /* Impossible */
+}
+#endif
+
+
+#ifdef MAIN
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+
+#ifdef HPUX
+typedef int * fd_set_ptr;
+#else
+typedef fd_set * fd_set_ptr;
+#endif
+
+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("Tread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
+ for (i=1 ; i <= 10 ; i++)
+ {
+ wait_time=param ? 11-i : i;
+ start_time=time((time_t*) 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) (time((time_t*) 0)-start_time), wait_time); fflush(stdout);
+ thr_end_alarm(&got_alarm);
+ fflush(stdout);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((gptr) arg);
+ return 0;
+}
+
+#ifdef USE_ONE_SIGNAL_HAND
+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 */
+#endif
+ if (sig == SIGALRM)
+ alarm(2); /* reschedule alarm */
+}
+#endif
+
+
+
+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 */
+ pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ sigemptyset(&set); /* Catch all signals */
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+#if THR_CLIENT_ALARM != SIGHUP
+ sigaddset(&set,SIGHUP);
+#endif
+#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(;;)
+ {
+ while ((error=my_sigwait(&set,&sig)) == 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();
+ 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,error;
+ sigset_t set;
+ MY_INIT(argv[0]);
+
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ pthread_mutex_init(&LOCK_thread_count,NULL);
+ pthread_cond_init(&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);
+#ifdef NOT_USED
+ sigemptyset(&set);
+ sigaddset(&set,THR_CLIENT_ALARM);
+ VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
+#endif
+
+ 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 */
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ pthread_create(&tid,&thr_attr,signal_hand,NULL);
+ VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
+ VOID(pthread_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=(int*) malloc(sizeof(int));
+ *param= i;
+ pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ printf("Can't create thread %d, error: %d\n",i,error);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_attr_destroy(&thr_attr);
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ VOID(pthread_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();
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ printf("Test succeeded\n");
+ return 0;
+}
+#endif /* MAIN */
+
+#else /* DONT_USE_THR_ALARM */
+
+#ifdef MAIN
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");
+ exit(1);
+}
+#endif
+#endif
+
+/*****************************************************************************
+** thr_alarm for OS/2
+*****************************************************************************/
+
+#elif defined(__OS2__)
+
+#define INCL_BASE
+#define INCL_NOPMAPI
+#include <os2.h>
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ APIRET rc;
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosCreateEventSem(NULL,(HEV *)&alrm->event,DC_SEM_SHARED,FALSE)))
+ {
+ printf("Error creating event semaphore! [%d] \n",rc);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosAsyncTimer((long) sec*1000L, (HSEM) alrm->event,(HTIMER *) &alrm->crono))) {
+ printf("Error starting async timer! [%d] \n",rc);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ } /* endif */
+
+ return 1;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ APIRET rc;
+
+ if (alrm->crono)
+ {
+ rc = DosWaitEventSem((HEV) alrm->event, SEM_IMMEDIATE_RETURN);
+ if (rc == 0) {
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ } /* endif */
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ DosStopTimer((HTIMER) alrm->crono);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+void init_thr_alarm(uint max_alarm)
+{
+ DBUG_ENTER("init_thr_alarm");
+ alarm_aborted=0; /* Yes, Gimmie alarms */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MAIN
+void main()
+{
+ printf("hello world\n");
+}
+#endif
+
+/*****************************************************************************
+** thr_alarm for win95
+*****************************************************************************/
+
+#else /* __WIN__ */
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ return 1;
+ }
+ if (!(alrm->crono=SetTimer(NULL,0,(long) sec*1000L, (TIMERPROC) NULL)))
+ return 1;
+ return 0;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ MSG msg;
+ if (alrm->crono)
+ {
+ PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE) ;
+ if (msg.message == WM_TIMER || alarm_aborted)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+#endif /* __WIN__ */
+
+#endif