thr_alarm.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public
  5.    License as published by the Free Software Foundation; either
  6.    version 2 of the License, or (at your option) any later version.
  7.    
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU Library General Public
  14.    License along with this library; if not, write to the Free
  15.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  16.    MA 02111-1307, USA */
  17. #include <global.h>
  18. #if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
  19. #include <errno.h>
  20. #include <my_pthread.h>
  21. #include <signal.h>
  22. #include <my_sys.h>
  23. #include <m_string.h>
  24. #include <queues.h>
  25. #include "thr_alarm.h"
  26. #ifdef HAVE_SYS_SELECT_H
  27. #include <sys/select.h> /* AIX needs this for fd_set */
  28. #endif
  29. #ifndef ETIME
  30. #define ETIME ETIMEDOUT
  31. #endif
  32. static my_bool alarm_aborted=1;
  33. my_bool thr_alarm_inited=0;
  34. #if !defined(__WIN__) && !defined(__EMX__)
  35. static pthread_mutex_t LOCK_alarm;
  36. static sigset_t full_signal_set;
  37. static QUEUE alarm_queue;
  38. pthread_t alarm_thread;
  39. #ifdef USE_ALARM_THREAD
  40. static pthread_cond_t COND_alarm;
  41. static void *alarm_handler(void *arg);
  42. #define reschedule_alarms() pthread_cond_signal(&COND_alarm)
  43. #else
  44. #define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
  45. #endif
  46. #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
  47. static sig_handler thread_alarm(int sig __attribute__((unused)));
  48. #endif
  49. static int compare_ulong(void *not_used __attribute__((unused)),
  50.  byte *a_ptr,byte* b_ptr)
  51. {
  52.   ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
  53.   return (a < b) ? -1  : (a == b) ? 0 : 1;
  54. }
  55. void init_thr_alarm(uint max_alarms)
  56. {
  57.   sigset_t s;
  58.   DBUG_ENTER("init_thr_alarm");
  59.   alarm_aborted=0;
  60.   init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
  61.      compare_ulong,NullS);
  62.   sigfillset(&full_signal_set); /* Neaded to block signals */
  63.   pthread_mutex_init(&LOCK_alarm,NULL);
  64. #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
  65. #if defined(HAVE_mit_thread)
  66.   sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */
  67. #else
  68.   {
  69.     struct sigaction sact;
  70.     sact.sa_flags = 0;
  71.     sact.sa_handler = thread_alarm;
  72.     sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0);
  73.   }
  74. #endif
  75. #endif
  76.   sigemptyset(&s);
  77.   sigaddset(&s, THR_SERVER_ALARM);
  78.   alarm_thread=pthread_self();
  79. #if defined(USE_ALARM_THREAD)
  80.   {
  81.     pthread_attr_t thr_attr;
  82.     pthread_attr_init(&thr_attr);
  83.     pthread_cond_init(&COND_alarm,NULL);
  84.     pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
  85.     pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
  86.     pthread_attr_setstacksize(&thr_attr,8196);
  87.     my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
  88.     VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
  89.     VOID(pthread_attr_destroy(&thr_attr));
  90.   }
  91. #elif defined(USE_ONE_SIGNAL_HAND)
  92.   pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
  93. #if THR_SERVER_ALARM == THR_CLIENT_ALARM
  94.   sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */
  95.   pthread_sigmask(SIG_UNBLOCK, &s, NULL);
  96. #endif
  97. #else
  98.   pthread_sigmask(SIG_UNBLOCK, &s, NULL);
  99.   sigset(THR_SERVER_ALARM,process_alarm);
  100. #endif
  101.   DBUG_VOID_RETURN;
  102. }
  103. /*
  104. ** Request alarm after sec seconds.
  105. ** A pointer is returned with points to a non-zero int when the alarm has been
  106. ** given. This can't be called from the alarm-handling thread.
  107. ** Returns 0 if no more alarms are allowed (aborted by process)
  108. */
  109. bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
  110. {
  111.   ulong now;
  112.   sigset_t old_mask;
  113.   my_bool reschedule;
  114.   DBUG_ENTER("thr_alarm");
  115.   DBUG_PRINT("enter",("thread: %s  sec: %d",my_thread_name(),sec));
  116.   now=(ulong) time((time_t*) 0);
  117.   pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
  118.   pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
  119.   if (alarm_aborted)
  120.   { /* No signal thread */
  121.     DBUG_PRINT("info", ("alarm aborted"));
  122.     pthread_mutex_unlock(&LOCK_alarm);
  123.     pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  124.     DBUG_RETURN(1);
  125.   }
  126.   if (alarm_queue.elements == alarm_queue.max_elements)
  127.   {
  128.     DBUG_PRINT("info", ("alarm queue full"));
  129.     fprintf(stderr,"Warning: thr_alarm queue is fulln");
  130.     pthread_mutex_unlock(&LOCK_alarm);
  131.     pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  132.     DBUG_RETURN(1);
  133.   }
  134.   reschedule= (!alarm_queue.elements ||
  135.       (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) >
  136.       (int) sec);
  137.   if (!alarm_data)
  138.   {
  139.     if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
  140.     {
  141.       DBUG_PRINT("info", ("failed my_malloc()"));
  142.       pthread_mutex_unlock(&LOCK_alarm);
  143.       pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  144.       DBUG_RETURN(1);
  145.     }
  146.     alarm_data->malloced=1;
  147.   }
  148.   else
  149.     alarm_data->malloced=0;
  150.   alarm_data->expire_time=now+sec;
  151.   alarm_data->alarmed=0;
  152.   alarm_data->thread=pthread_self();
  153.   queue_insert(&alarm_queue,(byte*) alarm_data);
  154.   /* Reschedule alarm if the current one has more than sec left */
  155.   if (reschedule)
  156.   {
  157.     DBUG_PRINT("info", ("reschedule"));
  158.     if (pthread_equal(pthread_self(),alarm_thread))
  159.       alarm(sec); /* purecov: inspected */
  160.     else
  161.       reschedule_alarms(); /* Reschedule alarms */
  162.   }
  163.   pthread_mutex_unlock(&LOCK_alarm);
  164.   pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  165.   (*alrm)= &alarm_data->alarmed;
  166.   DBUG_RETURN(0);
  167. }
  168. /*
  169. ** Remove alarm from list of alarms
  170. */
  171. void thr_end_alarm(thr_alarm_t *alarmed)
  172. {
  173.   ALARM *alarm_data;
  174.   sigset_t old_mask;
  175.   uint i;
  176.   bool found=0;
  177.   DBUG_ENTER("thr_end_alarm");
  178.   pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
  179.   pthread_mutex_lock(&LOCK_alarm);
  180.   alarm_data= (ALARM*) ((byte*) *alarmed - offsetof(ALARM,alarmed));
  181.   for (i=0 ; i < alarm_queue.elements ; i++)
  182.   {
  183.     if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
  184.     {
  185.       queue_remove(&alarm_queue,i),MYF(0);
  186.       if (alarm_data->malloced)
  187. my_free((gptr) alarm_data,MYF(0));
  188.       found=1;
  189.       break;
  190.     }
  191.   }
  192.   if (!found)
  193.   {
  194. #ifdef MAIN
  195.     printf("Warning: Didn't find alarm %lx in queue of %d alarmsn",
  196.    (long) *alarmed, alarm_queue.elements);
  197. #endif
  198.     DBUG_PRINT("warning",("Didn't find alarm %lx in queuen",*alarmed));
  199.   }
  200.   if (alarm_aborted && !alarm_queue.elements)
  201.     delete_queue(&alarm_queue);
  202.   pthread_mutex_unlock(&LOCK_alarm);
  203.   pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  204.   DBUG_VOID_RETURN;
  205. }
  206. /*
  207.   Come here when some alarm in queue is due.
  208.   Mark all alarms with are finnished in list.
  209.   Shedule alarms to be sent again after 1-10 sec (many alarms at once)
  210.   If alarm_aborted is set then all alarms are given and resent
  211.   every second.
  212.   */
  213. sig_handler process_alarm(int sig __attribute__((unused)))
  214. {
  215.   sigset_t old_mask;
  216.   ALARM *alarm_data;
  217.   DBUG_ENTER("process_alarm");
  218.   DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
  219. #if THR_SERVER_ALARM == THR_CLIENT_ALARM
  220.   if (!pthread_equal(pthread_self(),alarm_thread))
  221.   {
  222. #if defined(MAIN) && !defined(__bsdi__)
  223.     printf("thread_alarmn"); fflush(stdout);
  224. #endif
  225. #ifdef DONT_REMEMBER_SIGNAL
  226.     sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
  227. #endif
  228.     DBUG_VOID_RETURN;
  229.   }
  230. #endif
  231. #if defined(MAIN) && !defined(__bsdi__)
  232.   printf("process_alarmn"); fflush(stdout);
  233. #endif
  234. #ifndef USE_ALARM_THREAD
  235.   pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
  236.   pthread_mutex_lock(&LOCK_alarm);
  237. #endif
  238.   if (alarm_queue.elements)
  239.   {
  240.     if (alarm_aborted)
  241.     {
  242.       uint i;
  243.       for (i=0 ; i < alarm_queue.elements ;)
  244.       {
  245. alarm_data=(ALARM*) queue_element(&alarm_queue,i);
  246. alarm_data->alarmed=1; /* Info to thread */
  247. if (pthread_equal(alarm_data->thread,alarm_thread) ||
  248.     pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
  249. {
  250. #ifdef MAIN
  251.   printf("Warning: pthread_kill couldn't find thread!!!n");
  252. #endif
  253.   queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
  254. }
  255. else
  256.   i++; /* Signal next thread */
  257.       }
  258. #ifndef USE_ALARM_THREAD
  259.       if (alarm_queue.elements)
  260. alarm(1); /* Signal soon again */
  261. #endif
  262.     }
  263.     else
  264.     {
  265.       ulong now=(ulong) time((time_t*) 0);
  266.       ulong next=now+10-(now%10);
  267.       while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
  268.       {
  269. alarm_data->alarmed=1; /* Info to thread */
  270. DBUG_PRINT("info",("sending signal to waiting thread"));
  271. if (pthread_equal(alarm_data->thread,alarm_thread) ||
  272.     pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
  273. {
  274. #ifdef MAIN
  275.   printf("Warning: pthread_kill couldn't find thread!!!n");
  276. #endif
  277.   queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
  278.   if (!alarm_queue.elements)
  279.     break;
  280. }
  281. else
  282. {
  283.   alarm_data->expire_time=next;
  284.   queue_replaced(&alarm_queue);
  285. }
  286.       }
  287. #ifndef USE_ALARM_THREAD
  288.       if (alarm_queue.elements)
  289.       {
  290. #ifdef __bsdi__
  291. alarm(0); /* Remove old alarm */
  292. #endif
  293. alarm((uint) (alarm_data->expire_time-now));
  294.       }
  295. #endif
  296.     }
  297.   }
  298. #ifndef USE_ALARM_THREAD
  299. #if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
  300.   sigset(THR_SERVER_ALARM,process_alarm);
  301. #endif
  302.   pthread_mutex_unlock(&LOCK_alarm);
  303.   pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
  304. #endif
  305.   DBUG_VOID_RETURN;
  306. }
  307. /*
  308. ** Shedule all alarms now.
  309. ** When all alarms are given, Free alarm memory and don't allow more alarms.
  310. */
  311. void end_thr_alarm(void)
  312. {
  313.   DBUG_ENTER("end_thr_alarm");
  314.   pthread_mutex_lock(&LOCK_alarm);
  315.   if (!alarm_aborted)
  316.   {
  317.     DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
  318.     alarm_aborted=1; /* mark aborted */
  319.     if (!alarm_queue.elements)
  320.       delete_queue(&alarm_queue);
  321.     if (pthread_equal(pthread_self(),alarm_thread))
  322.       alarm(1); /* Shut down everything soon */
  323.     else
  324.       reschedule_alarms();
  325.   }
  326.   pthread_mutex_unlock(&LOCK_alarm);
  327.   DBUG_VOID_RETURN;
  328. }
  329. /*
  330. ** Remove another thread from the alarm
  331. */
  332. void thr_alarm_kill(pthread_t thread_id)
  333. {
  334.   uint i;
  335.   pthread_mutex_lock(&LOCK_alarm);
  336.   for (i=0 ; i < alarm_queue.elements ; i++)
  337.   {
  338.     if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
  339.       thread_id))
  340.     {
  341.       ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
  342.       tmp->expire_time=0;
  343.       queue_insert(&alarm_queue,(byte*) tmp);
  344.       reschedule_alarms();
  345.       break;
  346.     }
  347.   }
  348.   pthread_mutex_unlock(&LOCK_alarm);
  349. }
  350. /*
  351. **  This is here for thread to get interruptet from read/write/fcntl
  352. **  ARGSUSED
  353. */
  354. #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
  355. static sig_handler thread_alarm(int sig)
  356. {
  357. #ifdef MAIN
  358.   printf("thread_alarmn"); fflush(stdout);
  359. #endif
  360. #ifdef DONT_REMEMBER_SIGNAL
  361.   sigset(sig,thread_alarm); /* int. thread system calls */
  362. #endif
  363. }
  364. #endif
  365. #ifdef HAVE_TIMESPEC_TS_SEC
  366. #define tv_sec ts_sec
  367. #define tv_nsec ts_nsec
  368. #endif
  369. /* set up a alarm thread with uses 'sleep' to sleep between alarms */
  370. #ifdef USE_ALARM_THREAD
  371. static void *alarm_handler(void *arg __attribute__((unused)))
  372. {
  373.   int error;
  374.   struct timespec abstime;
  375. #ifdef MAIN
  376.   puts("Starting alarm thread");
  377. #endif
  378.   my_thread_init();
  379.   pthread_mutex_lock(&LOCK_alarm);
  380.   for (;;)
  381.   {
  382.     if (alarm_queue.elements)
  383.     {
  384.       ulong sleep_time,now=time((time_t*) 0);
  385.       if (alarm_aborted)
  386. sleep_time=now+1;
  387.       else
  388. sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
  389.       if (sleep_time > now)
  390.       {
  391. abstime.tv_sec=sleep_time;
  392. abstime.tv_nsec=0;
  393. if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
  394.     error != ETIME && error != ETIMEDOUT)
  395. {
  396. #ifdef MAIN
  397.   printf("Got error: %d from ptread_cond_timedwait (errno: %d)n",
  398.  error,errno);
  399. #endif
  400. }
  401.       }
  402.     }
  403.     else if (alarm_aborted)
  404.       break;
  405.     else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
  406.     {
  407. #ifdef MAIN
  408.       printf("Got error: %d from ptread_cond_wait (errno: %d)n",
  409.      error,errno);
  410. #endif
  411.     }
  412.     process_alarm(0);
  413.   }
  414.   bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
  415.   pthread_mutex_unlock(&LOCK_alarm);
  416.   pthread_exit(0);
  417.   return 0; /* Impossible */
  418. }
  419. #endif /* USE_ALARM_THREAD */
  420. /*****************************************************************************
  421. **  thr_alarm for OS/2
  422. *****************************************************************************/
  423. #elif defined(__EMX__)
  424. #define INCL_BASE
  425. #define INCL_NOPMAPI
  426. #include <os2.h>
  427. static pthread_mutex_t LOCK_alarm;
  428. static sigset_t full_signal_set;
  429. static QUEUE alarm_queue;
  430. pthread_t alarm_thread;
  431. #ifdef USE_ALARM_THREAD
  432. static pthread_cond_t COND_alarm;
  433. static void *alarm_handler(void *arg);
  434. #define reschedule_alarms() pthread_cond_signal(&COND_alarm)
  435. #else
  436. #define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
  437. #endif
  438. sig_handler process_alarm(int sig __attribute__((unused)))
  439. {
  440.   sigset_t old_mask;
  441.   ALARM *alarm_data;
  442.   DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
  443. }
  444. /*
  445. ** Remove another thread from the alarm
  446. */
  447. void thr_alarm_kill(pthread_t thread_id)
  448. {
  449.   uint i;
  450.   pthread_mutex_lock(&LOCK_alarm);
  451.   for (i=0 ; i < alarm_queue.elements ; i++)
  452.   {
  453.     if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
  454.       thread_id))
  455.     {
  456.       ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
  457.       tmp->expire_time=0;
  458.       queue_insert(&alarm_queue,(byte*) tmp);
  459.       reschedule_alarms();
  460.       break;
  461.     }
  462.   }
  463.   pthread_mutex_unlock(&LOCK_alarm);
  464. }
  465. bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
  466. {
  467.   APIRET rc;
  468.   if (alarm_aborted)
  469.   {
  470.     alarm->alarmed.crono=0;
  471.     alarm->alarmed.event=0;
  472.     return 1;
  473.   }
  474.   if (rc = DosCreateEventSem(NULL,(HEV *) &alarm->alarmed.event,
  475.      DC_SEM_SHARED,FALSE))
  476.   {
  477.     printf("Error creating event semaphore! [%d] n",rc);
  478.     alarm->alarmed.crono=0;
  479.     alarm->alarmed.event=0;
  480.     return 1;
  481.   }
  482.   if (rc = DosAsyncTimer((long) sec*1000L, (HSEM) alarm->alarmed.event,
  483.  (HTIMER *) &alarm->alarmed.crono))
  484.   {
  485.     printf("Error starting async timer! [%d] n",rc);
  486.     DosCloseEventSem((HEV) alarm->alarmed.event);
  487.     alarm->alarmed.crono=0;
  488.     alarm->alarmed.event=0;
  489.     return 1;
  490.   } /* endif */
  491.   (*alrm)= &alarm->alarmed;
  492.   return 1;
  493. }
  494. bool thr_got_alarm(thr_alarm_t *alrm_ptr)
  495. {
  496.   thr_alarm_t alrm= *alrm_ptr;
  497.   APIRET rc;
  498.   if (alrm->crono)
  499.   {
  500.     rc = DosWaitEventSem((HEV) alrm->event, SEM_IMMEDIATE_RETURN);
  501.     if (rc == 0) {
  502.       DosCloseEventSem((HEV) alrm->event);
  503.       alrm->crono = 0;
  504.       alrm->event = 0;
  505.     } /* endif */
  506.   }
  507.   return !alrm->crono || alarm_aborted;
  508. }
  509. void thr_end_alarm(thr_alarm_t *alrm_ptr)
  510. {
  511.   thr_alarm_t alrm= *alrm_ptr;
  512.   if (alrm->crono)
  513.   {
  514.     DosStopTimer((HTIMER) alrm->crono);
  515.     DosCloseEventSem((HEV) alrm->event);
  516.     alrm->crono = 0;
  517.     alrm->event = 0;
  518.   }
  519. }
  520. void end_thr_alarm(void)
  521. {
  522.   DBUG_ENTER("end_thr_alarm");
  523.   alarm_aborted=1; /* No more alarms */
  524.   DBUG_VOID_RETURN;
  525. }
  526. void init_thr_alarm(uint max_alarm)
  527. {
  528.   DBUG_ENTER("init_thr_alarm");
  529.   alarm_aborted=0; /* Yes, Gimmie alarms */
  530.   DBUG_VOID_RETURN;
  531. }
  532. /*****************************************************************************
  533. **  thr_alarm for win95
  534. *****************************************************************************/
  535. #else /* __WIN__ */
  536. void thr_alarm_kill(pthread_t thread_id)
  537. {
  538.   /* Can't do this yet */
  539. }
  540. sig_handler process_alarm(int sig __attribute__((unused)))
  541. {
  542.   /* Can't do this yet */
  543. }
  544. bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
  545. {
  546.   if (alarm_aborted)
  547.   {
  548.     alarm->alarmed.crono=0;
  549.     return 1;
  550.   }
  551.   if (!(alarm->alarmed.crono=SetTimer((HWND) NULL,0, sec*1000,
  552.       (TIMERPROC) NULL)))
  553.     return 1;
  554.   (*alrm)= &alarm->alarmed;
  555.   return 0;
  556. }
  557. bool thr_got_alarm(thr_alarm_t *alrm_ptr)
  558. {
  559.   thr_alarm_t alrm= *alrm_ptr;
  560.   MSG msg;
  561.   if (alrm->crono)
  562.   {
  563.     PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE) ;
  564.     if (msg.message == WM_TIMER || alarm_aborted)
  565.     {
  566.       KillTimer(NULL, alrm->crono);
  567.       alrm->crono = 0;
  568.     }
  569.   }
  570.   return !alrm->crono || alarm_aborted;
  571. }
  572. void thr_end_alarm(thr_alarm_t *alrm_ptr)
  573. {
  574.   thr_alarm_t alrm= *alrm_ptr;
  575.   if (alrm->crono)
  576.   {
  577.     KillTimer(NULL, alrm->crono);
  578.     alrm->crono = 0;
  579.   }
  580. }
  581. void end_thr_alarm(void)
  582. {
  583.   DBUG_ENTER("end_thr_alarm");
  584.   alarm_aborted=1; /* No more alarms */
  585.   DBUG_VOID_RETURN;
  586. }
  587. void init_thr_alarm(uint max_alarm)
  588. {
  589.   DBUG_ENTER("init_thr_alarm");
  590.   alarm_aborted=0; /* Yes, Gimmie alarms */
  591.   DBUG_VOID_RETURN;
  592. }
  593. #endif /* __WIN__ */
  594. #endif /* THREAD */
  595. /****************************************************************************
  596. ** Handling of MAIN
  597. ***************************************************************************/
  598. #ifdef MAIN
  599. #if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
  600. static pthread_cond_t COND_thread_count;
  601. static pthread_mutex_t LOCK_thread_count;
  602. static uint thread_count;
  603. #ifdef HPUX
  604. typedef int * fd_set_ptr;
  605. #else
  606. typedef fd_set * fd_set_ptr;
  607. #endif /* HPUX */
  608. static void *test_thread(void *arg)
  609. {
  610.   int i,param=*((int*) arg),wait_time,retry;
  611.   time_t start_time;
  612.   thr_alarm_t got_alarm;
  613.   fd_set fd;
  614.   FD_ZERO(&fd);
  615.   my_thread_init();
  616.   printf("Thread %d (%s) startedn",param,my_thread_name()); fflush(stdout);
  617.   for (i=1 ; i <= 10 ; i++)
  618.   {
  619.     wait_time=param ? 11-i : i;
  620.     start_time=time((time_t*) 0);
  621.     if (thr_alarm(&got_alarm,wait_time,0))
  622.     {
  623.       printf("Thread: %s  Alarms abortedn",my_thread_name());
  624.       break;
  625.     }
  626.     if (wait_time == 3)
  627.     {
  628.       printf("Thread: %s  Simulation of no alarm neededn",my_thread_name());
  629.       fflush(stdout);
  630.     }
  631.     else
  632.     {
  633.       for (retry=0 ; !thr_got_alarm(&got_alarm) && retry < 10 ; retry++)
  634.       {
  635. printf("Thread: %s  Waiting %d secn",my_thread_name(),wait_time);
  636. select(0,(fd_set_ptr) &fd,0,0,0);
  637.       }
  638.       if (!thr_got_alarm(&got_alarm))
  639.       {
  640. printf("Thread: %s  didn't get an alarm. Aborting!n",
  641.        my_thread_name());
  642. break;
  643.       }
  644.       if (wait_time == 7)
  645.       { /* Simulate alarm-miss */
  646. fd_set readFDs;
  647. uint max_connection=fileno(stdin);
  648. FD_ZERO(&readFDs);
  649. FD_SET(max_connection,&readFDs);
  650. retry=0;
  651. for (;;)
  652. {
  653.   printf("Thread: %s  Simulating alarm missn",my_thread_name());
  654.   fflush(stdout);
  655.   if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
  656.   {
  657.     if (errno == EINTR)
  658.       break; /* Got new interrupt */
  659.     printf("Got errno: %d from select.  Retrying..n",errno);
  660.     if (retry++ >= 3)
  661.     {
  662.       printf("Warning:  Interrupt of select() doesn't set errno!n");
  663.       break;
  664.     }
  665.   }
  666.   else /* This shouldn't happen */
  667.   {
  668.     if (!FD_ISSET(max_connection,&readFDs))
  669.     {
  670.       printf("Select interrupted, but errno not setn");
  671.       fflush(stdout);
  672.       if (retry++ >= 3)
  673. break;
  674.       continue;
  675.     }
  676.     VOID(getchar()); /* Somebody was playing */
  677.   }
  678. }
  679.       }
  680.     }
  681.     printf("Thread: %s  Slept for %d (%d) secn",my_thread_name(),
  682.    (int) (time((time_t*) 0)-start_time), wait_time); fflush(stdout);
  683.     thr_end_alarm(&got_alarm);
  684.     fflush(stdout);
  685.   }
  686.   pthread_mutex_lock(&LOCK_thread_count);
  687.   thread_count--;
  688.   VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
  689.   pthread_mutex_unlock(&LOCK_thread_count);
  690.   free((gptr) arg);
  691.   return 0;
  692. }
  693. #ifdef USE_ONE_SIGNAL_HAND
  694. static sig_handler print_signal_warning(int sig)
  695. {
  696.   printf("Warning: Got signal %d from thread %sn",sig,my_thread_name());
  697.   fflush(stdout);
  698. #ifdef DONT_REMEMBER_SIGNAL
  699.   sigset(sig,print_signal_warning); /* int. thread system calls */
  700. #endif
  701.   if (sig == SIGALRM)
  702.     alarm(2); /* reschedule alarm */
  703. }
  704. #endif /* USE_ONE_SIGNAL_HAND */
  705. static void *signal_hand(void *arg __attribute__((unused)))
  706. {
  707.   sigset_t set;
  708.   int sig,error,err_count=0;;
  709.   my_thread_init();
  710.   pthread_detach_this_thread();
  711.   init_thr_alarm(10); /* Setup alarm handler */
  712.   pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
  713.   VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
  714.   pthread_mutex_unlock(&LOCK_thread_count);
  715.   sigemptyset(&set); /* Catch all signals */
  716.   sigaddset(&set,SIGINT);
  717.   sigaddset(&set,SIGQUIT);
  718.   sigaddset(&set,SIGTERM);
  719. #if THR_CLIENT_ALARM != SIGHUP
  720.   sigaddset(&set,SIGHUP);
  721. #endif
  722. #ifdef SIGTSTP
  723.   sigaddset(&set,SIGTSTP);
  724. #endif
  725. #ifdef USE_ONE_SIGNAL_HAND
  726.   sigaddset(&set,THR_SERVER_ALARM); /* For alarms */
  727.   puts("Starting signal and alarm handling thread");
  728. #else
  729.   puts("Starting signal handling thread");
  730. #endif
  731.   printf("server alarm: %d  thread alarm: %dn",
  732.  THR_SERVER_ALARM,THR_CLIENT_ALARM);
  733.   DBUG_PRINT("info",("Starting signal and alarm handling thread"));
  734.   for(;;)
  735.   {
  736.     while ((error=my_sigwait(&set,&sig)) == EINTR)
  737.       printf("sigwait restartedn");
  738.     if (error)
  739.     {
  740.       fprintf(stderr,"Got error %d from sigwaitn",error);
  741.       if (err_count++ > 5)
  742. exit(1); /* Too many errors in test */
  743.       continue;
  744.     }
  745. #ifdef USE_ONE_SIGNAL_HAND
  746.     if (sig != THR_SERVER_ALARM)
  747. #endif
  748.       printf("Main thread: Got signal %dn",sig);
  749.     switch (sig) {
  750.     case SIGINT:
  751.     case SIGQUIT:
  752.     case SIGTERM:
  753.     case SIGHUP:
  754.       printf("Aborting nicelyn");
  755.       end_thr_alarm();
  756.       break;
  757. #ifdef SIGTSTP
  758.     case SIGTSTP:
  759.       printf("Abortingn");
  760.       exit(1);
  761.       return 0; /* Keep some compilers happy */
  762. #endif
  763. #ifdef USE_ONE_SIGNAL_HAND
  764.      case THR_SERVER_ALARM:
  765.        process_alarm(sig);
  766.       break;
  767. #endif
  768.     }
  769.   }
  770. }
  771. int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
  772. {
  773.   pthread_t tid;
  774.   pthread_attr_t thr_attr;
  775.   int i,*param,error;
  776.   sigset_t set;
  777.   MY_INIT(argv[0]);
  778.   if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
  779.     DBUG_PUSH(argv[1]+2);
  780.   pthread_mutex_init(&LOCK_thread_count,NULL);
  781.   pthread_cond_init(&COND_thread_count,NULL);
  782.   /* Start a alarm handling thread */
  783.   sigemptyset(&set);
  784.   sigaddset(&set,SIGINT);
  785.   sigaddset(&set,SIGQUIT);
  786.   sigaddset(&set,SIGTERM);
  787.   sigaddset(&set,SIGHUP);
  788.   signal(SIGTERM,SIG_DFL); /* If it's blocked by parent */
  789. #ifdef SIGTSTP
  790.   sigaddset(&set,SIGTSTP);
  791. #endif
  792.   sigaddset(&set,THR_SERVER_ALARM);
  793.   sigdelset(&set,THR_CLIENT_ALARM);
  794.   (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
  795. #ifdef NOT_USED
  796.   sigemptyset(&set);
  797.   sigaddset(&set,THR_CLIENT_ALARM);
  798.   VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
  799. #endif
  800.   pthread_attr_init(&thr_attr);
  801.   pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
  802.   pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
  803.   pthread_attr_setstacksize(&thr_attr,65536L);
  804.   /* Start signal thread and wait for it to start */
  805.   VOID(pthread_mutex_lock(&LOCK_thread_count));
  806.   pthread_create(&tid,&thr_attr,signal_hand,NULL);
  807.   VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
  808.   VOID(pthread_mutex_unlock(&LOCK_thread_count));
  809.   DBUG_PRINT("info",("signal thread created"));
  810.   thr_setconcurrency(3);
  811.   pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
  812.   printf("Main thread: %sn",my_thread_name());
  813.   for (i=0 ; i < 2 ; i++)
  814.   {
  815.     param=(int*) malloc(sizeof(int));
  816.     *param= i;
  817.     pthread_mutex_lock(&LOCK_thread_count);
  818.     if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
  819.     {
  820.       printf("Can't create thread %d, error: %dn",i,error);
  821.       exit(1);
  822.     }
  823.     thread_count++;
  824.     pthread_mutex_unlock(&LOCK_thread_count);
  825.   }
  826.   pthread_attr_destroy(&thr_attr);
  827.   pthread_mutex_lock(&LOCK_thread_count);
  828.   while (thread_count)
  829.   {
  830.     VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
  831.     if (thread_count == 1)
  832.     {
  833.       printf("Calling end_thr_alarm. This should cancel the last threadn");
  834.       end_thr_alarm();
  835.     }
  836.   }
  837.   pthread_mutex_unlock(&LOCK_thread_count);
  838.   printf("Test succeededn");
  839.   return 0;
  840. }
  841. #else /* THREAD */
  842. int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
  843. {
  844. #ifndef THREAD
  845.   printf("thr_alarm disabled because we are not using threadsn");
  846. #else
  847.   printf("thr_alarm disabled with DONT_USE_THR_ALARMn");
  848. #endif
  849.   exit(1);
  850. }
  851. #endif /* THREAD */
  852. #endif /* MAIN */