thr_alarm.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:28k
源码类别:

MySQL数据库

开发平台:

Visual C++

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