home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / mysys / thr_alarm.c < prev    next >
C/C++ Source or Header  |  2000-08-31  |  23KB  |  874 lines

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