17 #define FORCE_DBUG_OFF
18 #include "mysys_priv.h"
19 #include <my_global.h>
21 #if !defined(DONT_USE_THR_ALARM)
23 #include <my_pthread.h>
28 #include "thr_alarm.h"
30 #ifdef HAVE_SYS_SELECT_H
31 #include <sys/select.h>
35 #define ETIME ETIMEDOUT
38 uint thr_client_alarm;
39 static int alarm_aborted=1;
40 my_bool thr_alarm_inited= 0;
41 volatile my_bool alarm_thread_running= 0;
42 time_t next_alarm_expire_time= ~ (time_t) 0;
43 static sig_handler process_alarm_part2(
int sig);
49 static sigset_t full_signal_set;
50 static QUEUE alarm_queue;
51 static uint max_used_alarms=0;
52 pthread_t alarm_thread;
54 #define MY_THR_ALARM_QUEUE_EXTENT 10
56 #ifdef USE_ALARM_THREAD
57 static void *alarm_handler(
void *arg);
58 #define reschedule_alarms() mysql_cond_signal(&COND_alarm)
60 #define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
63 static sig_handler thread_alarm(
int sig __attribute__((unused)));
65 static int compare_ulong(
void *not_used __attribute__((unused)),
66 uchar *a_ptr,uchar* b_ptr)
68 ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
69 return (a < b) ? -1 : (a == b) ? 0 : 1;
72 void init_thr_alarm(uint max_alarms)
75 DBUG_ENTER(
"init_thr_alarm");
77 next_alarm_expire_time= ~ (time_t) 0;
78 init_queue_ex(&alarm_queue, max_alarms + 1, offsetof(
ALARM,expire_time), 0,
79 compare_ulong, NullS, MY_THR_ALARM_QUEUE_EXTENT);
80 sigfillset(&full_signal_set);
83 if (thd_lib_detected == THD_LIB_LT)
84 thr_client_alarm= SIGALRM;
86 thr_client_alarm= SIGUSR1;
87 #ifndef USE_ALARM_THREAD
88 if (thd_lib_detected != THD_LIB_LT)
91 my_sigset(thr_client_alarm, thread_alarm);
94 sigaddset(&s, THR_SERVER_ALARM);
95 alarm_thread=pthread_self();
96 #if defined(USE_ALARM_THREAD)
98 pthread_attr_t thr_attr;
99 pthread_attr_init(&thr_attr);
100 pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
101 pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
102 pthread_attr_setstacksize(&thr_attr,8196);
104 &alarm_thread, &thr_attr, alarm_handler, NULL);
105 pthread_attr_destroy(&thr_attr);
107 #elif defined(USE_ONE_SIGNAL_HAND)
108 pthread_sigmask(SIG_BLOCK, &s, NULL);
109 if (thd_lib_detected == THD_LIB_LT)
111 my_sigset(thr_client_alarm, process_alarm);
112 pthread_sigmask(SIG_UNBLOCK, &s, NULL);
115 my_sigset(THR_SERVER_ALARM, process_alarm);
116 pthread_sigmask(SIG_UNBLOCK, &s, NULL);
122 void resize_thr_alarm(uint max_alarms)
129 if (alarm_queue.elements < max_alarms)
131 resize_queue(&alarm_queue,max_alarms+1);
132 max_used_alarms= alarm_queue.elements;
157 my_bool thr_alarm(thr_alarm_t *alrm, uint sec,
ALARM *alarm_data)
160 #ifndef USE_ONE_SIGNAL_HAND
165 DBUG_ENTER(
"thr_alarm");
166 DBUG_PRINT(
"enter",(
"thread: %s sec: %d",my_thread_name(),sec));
169 #ifndef USE_ONE_SIGNAL_HAND
170 pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
173 if (alarm_aborted > 0)
175 DBUG_PRINT(
"info", (
"alarm aborted"));
178 #ifndef USE_ONE_SIGNAL_HAND
179 pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
183 if (alarm_aborted < 0)
186 if (alarm_queue.elements >= max_used_alarms)
188 max_used_alarms=alarm_queue.elements+1;
190 reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
193 if (!(alarm_data=(
ALARM*) my_malloc(
sizeof(
ALARM),MYF(MY_WME))))
195 DBUG_PRINT(
"info", (
"failed my_malloc()"));
198 #ifndef USE_ONE_SIGNAL_HAND
199 pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
203 alarm_data->malloced=1;
206 alarm_data->malloced=0;
207 alarm_data->expire_time=now+sec;
208 alarm_data->alarmed=0;
209 alarm_data->thread= current_my_thread_var->pthread_self;
210 alarm_data->thread_id= current_my_thread_var->id;
211 queue_insert_safe(&alarm_queue, (uchar*) alarm_data);
216 DBUG_PRINT(
"info", (
"reschedule"));
217 if (pthread_equal(pthread_self(),alarm_thread))
220 next_alarm_expire_time= now + sec;
226 #ifndef USE_ONE_SIGNAL_HAND
227 pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
229 (*alrm)= &alarm_data->alarmed;
238 void thr_end_alarm(thr_alarm_t *alarmed)
241 #ifndef USE_ONE_SIGNAL_HAND
245 DBUG_ENTER(
"thr_end_alarm");
247 #ifndef USE_ONE_SIGNAL_HAND
248 pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
252 alarm_data= (
ALARM*) ((uchar*) *alarmed - offsetof(
ALARM,alarmed));
253 for (i=0 ; i < alarm_queue.elements ; i++)
255 if ((
ALARM*) queue_element(&alarm_queue,i) == alarm_data)
257 queue_remove(&alarm_queue,i);
258 if (alarm_data->malloced)
266 DBUG_ASSERT(!*alarmed || found == 1);
270 fprintf(stderr,
"Warning: Didn't find alarm 0x%lx in queue of %d alarms\n",
271 (
long) *alarmed, alarm_queue.elements);
272 DBUG_PRINT(
"warning",(
"Didn't find alarm 0x%lx in queue\n",
276 #ifndef USE_ONE_SIGNAL_HAND
277 pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
290 sig_handler process_alarm(
int sig __attribute__((unused)))
297 if (thd_lib_detected == THD_LIB_LT &&
298 !pthread_equal(pthread_self(),alarm_thread))
300 #if defined(MAIN) && !defined(__bsdi__)
301 printf(
"thread_alarm in process_alarm\n"); fflush(stdout);
303 #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
304 my_sigset(thr_client_alarm, process_alarm);
316 #ifndef USE_ALARM_THREAD
317 pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
320 process_alarm_part2(sig);
321 #ifndef USE_ALARM_THREAD
322 #if defined(SIGNAL_HANDLER_RESET_ON_DELIVERY) && !defined(USE_ONE_SIGNAL_HAND)
323 my_sigset(THR_SERVER_ALARM,process_alarm);
326 pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
332 static sig_handler process_alarm_part2(
int sig __attribute__((unused)))
335 DBUG_ENTER(
"process_alarm");
336 DBUG_PRINT(
"info",(
"sig: %d active alarms: %d",sig,alarm_queue.elements));
338 #if defined(MAIN) && !defined(__bsdi__)
339 printf(
"process_alarm\n"); fflush(stdout);
341 if (alarm_queue.elements)
346 for (i=0 ; i < alarm_queue.elements ;)
348 alarm_data=(
ALARM*) queue_element(&alarm_queue,i);
349 alarm_data->alarmed=1;
350 if (pthread_equal(alarm_data->thread,alarm_thread) ||
351 pthread_kill(alarm_data->thread, thr_client_alarm))
354 printf(
"Warning: pthread_kill couldn't find thread!!!\n");
356 queue_remove(&alarm_queue,i);
361 #ifndef USE_ALARM_THREAD
362 if (alarm_queue.elements)
368 ulong now=(ulong) my_time(0);
369 ulong next=now+10-(now%10);
370 while ((alarm_data=(
ALARM*) queue_top(&alarm_queue))->expire_time <= now)
372 alarm_data->alarmed=1;
373 DBUG_PRINT(
"info",(
"sending signal to waiting thread"));
374 if (pthread_equal(alarm_data->thread,alarm_thread) ||
375 pthread_kill(alarm_data->thread, thr_client_alarm))
378 printf(
"Warning: pthread_kill couldn't find thread!!!\n");
380 queue_remove(&alarm_queue,0);
381 if (!alarm_queue.elements)
386 alarm_data->expire_time=next;
387 queue_replaced(&alarm_queue);
390 #ifndef USE_ALARM_THREAD
391 if (alarm_queue.elements)
396 alarm((uint) (alarm_data->expire_time-now));
397 next_alarm_expire_time= alarm_data->expire_time;
407 next_alarm_expire_time= ~(time_t) 0;
428 void end_thr_alarm(my_bool free_structures)
430 DBUG_ENTER(
"end_thr_alarm");
431 if (alarm_aborted != 1)
434 DBUG_PRINT(
"info",(
"Resheduling %d waiting alarms",alarm_queue.elements));
436 if (alarm_queue.elements || (alarm_thread_running && free_structures))
438 if (pthread_equal(pthread_self(),alarm_thread))
447 DBUG_ASSERT(!alarm_queue.elements);
450 set_timespec(abstime, 10);
451 while (alarm_thread_running)
454 if (error == ETIME || error == ETIMEDOUT)
457 delete_queue(&alarm_queue);
460 if (!alarm_thread_running)
477 void thr_alarm_kill(my_thread_id thread_id)
483 for (i=0 ; i < alarm_queue.elements ; i++)
485 if (((
ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
487 ALARM *tmp=(
ALARM*) queue_remove(&alarm_queue,i);
489 queue_insert(&alarm_queue,(uchar*) tmp);
501 info->next_alarm_time= 0;
502 info->max_used_alarms= max_used_alarms;
503 if ((info->active_alarms= alarm_queue.elements))
505 ulong now=(ulong) my_time(0);
507 ALARM *alarm_data= (
ALARM*) queue_top(&alarm_queue);
508 time_diff= (long) (alarm_data->expire_time - now);
509 info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff);
520 static sig_handler thread_alarm(
int sig __attribute__((unused)))
523 printf(
"thread_alarm\n"); fflush(stdout);
525 #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
526 my_sigset(sig,thread_alarm);
531 #ifdef HAVE_TIMESPEC_TS_SEC
532 #define tv_sec ts_sec
533 #define tv_nsec ts_nsec
538 #ifdef USE_ALARM_THREAD
539 static void *alarm_handler(
void *arg __attribute__((unused)))
544 puts(
"Starting alarm thread");
547 alarm_thread_running= 1;
551 if (alarm_queue.elements)
553 ulong sleep_time,now= my_time(0);
557 sleep_time= ((
ALARM*) queue_top(&alarm_queue))->expire_time;
558 if (sleep_time > now)
560 abstime.tv_sec=sleep_time;
562 next_alarm_expire_time= sleep_time;
564 error != ETIME && error != ETIMEDOUT)
567 printf(
"Got error: %d from ptread_cond_timedwait (errno: %d)\n",
573 else if (alarm_aborted == -1)
577 next_alarm_expire_time= ~ (time_t) 0;
581 printf(
"Got error: %d from ptread_cond_wait (errno: %d)\n",
588 memset(&alarm_thread, 0,
sizeof(alarm_thread));
589 alarm_thread_running= 0;
603 void thr_alarm_kill(my_thread_id thread_id)
608 sig_handler process_alarm(
int sig __attribute__((unused)))
614 my_bool thr_alarm(thr_alarm_t *alrm, uint sec,
ALARM *alarm)
616 (*alrm)= &alarm->alarmed;
619 alarm->alarmed.crono=0;
622 if (!(alarm->alarmed.crono=SetTimer((HWND) NULL,0, sec*1000,
629 my_bool thr_got_alarm(thr_alarm_t *alrm_ptr)
631 thr_alarm_t alrm= *alrm_ptr;
635 PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE) ;
636 if (msg.message == WM_TIMER || alarm_aborted)
638 KillTimer(NULL, alrm->crono);
642 return !alrm->crono || alarm_aborted;
646 void thr_end_alarm(thr_alarm_t *alrm_ptr)
648 thr_alarm_t alrm= *alrm_ptr;
650 if (alrm && alrm->crono)
653 KillTimer(NULL, alrm->crono);
658 void end_thr_alarm(my_bool free_structures)
660 DBUG_ENTER(
"end_thr_alarm");
665 void init_thr_alarm(uint max_alarm)
667 DBUG_ENTER(
"init_thr_alarm");
674 memset(info, 0,
sizeof(*info));
677 void resize_thr_alarm(uint max_alarms)
690 #if !defined(DONT_USE_THR_ALARM)
694 static uint thread_count;
697 typedef int * fd_set_ptr;
699 typedef fd_set * fd_set_ptr;
702 static void *test_thread(
void *arg)
704 int i,param=*((
int*) arg),wait_time,retry;
706 thr_alarm_t got_alarm;
710 printf(
"Thread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
711 for (i=1 ; i <= 10 ; i++)
713 wait_time=param ? 11-i :
i;
714 start_time= my_time(0);
715 if (thr_alarm(&got_alarm,wait_time,0))
717 printf(
"Thread: %s Alarms aborted\n",my_thread_name());
722 printf(
"Thread: %s Simulation of no alarm needed\n",my_thread_name());
727 for (retry=0 ; !thr_got_alarm(&got_alarm) && retry < 10 ; retry++)
729 printf(
"Thread: %s Waiting %d sec\n",my_thread_name(),wait_time);
730 select(0,(fd_set_ptr) &fd,0,0,0);
732 if (!thr_got_alarm(&got_alarm))
734 printf(
"Thread: %s didn't get an alarm. Aborting!\n",
741 uint max_connection=fileno(stdin);
743 FD_SET(max_connection,&readFDs);
747 printf(
"Thread: %s Simulating alarm miss\n",my_thread_name());
749 if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
753 printf(
"Got errno: %d from select. Retrying..\n",errno);
756 printf(
"Warning: Interrupt of select() doesn't set errno!\n");
762 if (!FD_ISSET(max_connection,&readFDs))
764 printf(
"Select interrupted, but errno not set\n");
775 printf(
"Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
776 (
int) (my_time(0)-start_time), wait_time); fflush(stdout);
777 thr_end_alarm(&got_alarm);
788 #ifdef USE_ONE_SIGNAL_HAND
789 static sig_handler print_signal_warning(
int sig)
791 printf(
"Warning: Got signal %d from thread %s\n",sig,my_thread_name());
793 #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
794 my_sigset(sig,print_signal_warning);
802 static void *signal_hand(
void *arg __attribute__((unused)))
805 int sig,error,err_count=0;;
808 pthread_detach_this_thread();
815 sigaddset(&
set,SIGINT);
816 sigaddset(&
set,SIGQUIT);
817 sigaddset(&
set,SIGTERM);
818 sigaddset(&
set,SIGHUP);
820 sigaddset(&
set,SIGTSTP);
822 #ifdef USE_ONE_SIGNAL_HAND
823 sigaddset(&
set,THR_SERVER_ALARM);
824 puts(
"Starting signal and alarm handling thread");
826 puts(
"Starting signal handling thread");
828 printf(
"server alarm: %d thread alarm: %d\n",
829 THR_SERVER_ALARM, thr_client_alarm);
830 DBUG_PRINT(
"info",(
"Starting signal and alarm handling thread"));
833 while ((error=my_sigwait(&
set,&sig)) == EINTR)
834 printf(
"sigwait restarted\n");
837 fprintf(stderr,
"Got error %d from sigwait\n",error);
842 #ifdef USE_ONE_SIGNAL_HAND
843 if (sig != THR_SERVER_ALARM)
845 printf(
"Main thread: Got signal %d\n",sig);
851 printf(
"Aborting nicely\n");
856 printf(
"Aborting\n");
860 #ifdef USE_ONE_SIGNAL_HAND
861 case THR_SERVER_ALARM:
870 int main(
int argc __attribute__((unused)),
char **argv __attribute__((unused)))
873 pthread_attr_t thr_attr;
879 if (argc > 1 && argv[1][0] ==
'-' && argv[1][1] ==
'#')
881 DBUG_PUSH(argv[1]+2);
888 sigaddset(&
set,SIGINT);
889 sigaddset(&
set,SIGQUIT);
890 sigaddset(&
set,SIGTERM);
891 sigaddset(&
set,SIGHUP);
892 signal(SIGTERM,SIG_DFL);
894 sigaddset(&
set,SIGTSTP);
896 sigaddset(&
set,THR_SERVER_ALARM);
897 sigdelset(&
set, thr_client_alarm);
898 (void) pthread_sigmask(SIG_SETMASK,&
set,NULL);
900 pthread_attr_init(&thr_attr);
901 pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
902 pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
903 pthread_attr_setstacksize(&thr_attr,65536L);
908 &tid, &thr_attr, signal_hand, NULL);
911 DBUG_PRINT(
"info",(
"signal thread created"));
913 thr_setconcurrency(3);
914 pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
915 printf(
"Main thread: %s\n",my_thread_name());
916 for (i=0 ; i < 2 ; i++)
918 param=(
int*) malloc(
sizeof(
int));
922 &tid, &thr_attr, test_thread,
925 printf(
"Can't create thread %d, error: %d\n",i,error);
932 pthread_attr_destroy(&thr_attr);
934 thr_alarm_info(&alarm_info);
935 printf(
"Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
936 alarm_info.active_alarms, alarm_info.max_used_alarms,
937 alarm_info.next_alarm_time);
941 if (thread_count == 1)
943 printf(
"Calling end_thr_alarm. This should cancel the last thread\n");
948 thr_alarm_info(&alarm_info);
950 printf(
"Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
951 alarm_info.active_alarms, alarm_info.max_used_alarms,
952 alarm_info.next_alarm_time);
953 printf(
"Test succeeded\n");
959 int main(
int argc __attribute__((unused)),
char **argv __attribute__((unused)))
961 printf(
"thr_alarm disabled with DONT_USE_THR_ALARM\n");