1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* To avoid problems with alarms in debug code, we disable DBUG here */
17
#define FORCE_DBUG_OFF
18
#include <my_global.h>
20
#if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
22
#include <my_pthread.h>
27
#include "thr_alarm.h"
29
#ifdef HAVE_SYS_SELECT_H
30
#include <sys/select.h> /* AIX needs this for fd_set */
34
#define ETIME ETIMEDOUT
37
uint thr_client_alarm;
38
static int alarm_aborted=1; /* No alarm thread */
39
my_bool thr_alarm_inited= 0;
40
volatile my_bool alarm_thread_running= 0;
41
time_t next_alarm_expire_time= ~ (time_t) 0;
42
static sig_handler process_alarm_part2(int sig);
44
static pthread_mutex_t LOCK_alarm;
45
static pthread_cond_t COND_alarm;
46
static sigset_t full_signal_set;
47
static QUEUE alarm_queue;
48
static uint max_used_alarms=0;
49
pthread_t alarm_thread;
51
#ifdef USE_ALARM_THREAD
52
static void *alarm_handler(void *arg);
53
#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
55
#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
58
static sig_handler thread_alarm(int sig __attribute__((unused)));
60
static int compare_ulong(void *not_used __attribute__((unused)),
61
uchar *a_ptr,uchar* b_ptr)
63
ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
64
return (a < b) ? -1 : (a == b) ? 0 : 1;
67
void init_thr_alarm(uint max_alarms)
70
DBUG_ENTER("init_thr_alarm");
72
next_alarm_expire_time= ~ (time_t) 0;
73
init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
75
sigfillset(&full_signal_set); /* Neaded to block signals */
76
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
77
pthread_cond_init(&COND_alarm,NULL);
78
if (thd_lib_detected == THD_LIB_LT)
79
thr_client_alarm= SIGALRM;
81
thr_client_alarm= SIGUSR1;
82
#ifndef USE_ALARM_THREAD
83
if (thd_lib_detected != THD_LIB_LT)
86
my_sigset(thr_client_alarm, thread_alarm);
89
sigaddset(&s, THR_SERVER_ALARM);
90
alarm_thread=pthread_self();
91
#if defined(USE_ALARM_THREAD)
93
pthread_attr_t thr_attr;
94
pthread_attr_init(&thr_attr);
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);
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));
103
#elif defined(USE_ONE_SIGNAL_HAND)
104
pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
105
if (thd_lib_detected == THD_LIB_LT)
107
my_sigset(thr_client_alarm, process_alarm); /* Linuxthreads */
108
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
111
my_sigset(THR_SERVER_ALARM, process_alarm);
112
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
113
#endif /* USE_ALARM_THREAD */
118
void resize_thr_alarm(uint max_alarms)
120
pthread_mutex_lock(&LOCK_alarm);
122
It's ok not to shrink the queue as there may be more pending alarms than
125
if (alarm_queue.elements < max_alarms)
126
resize_queue(&alarm_queue,max_alarms+1);
127
pthread_mutex_unlock(&LOCK_alarm);
132
Request alarm after sec seconds.
136
alrm Pointer to alarm detection
137
alarm_data Structure to store in alarm queue
140
This function can't be called from the alarm-handling thread.
144
1 If no more alarms are allowed (aborted by process)
146
Stores in first argument a pointer to a non-zero int which is set to 0
147
when the alarm has been given
150
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
153
#ifndef USE_ONE_SIGNAL_HAND
157
struct st_my_thread_var *current_my_thread_var= my_thread_var;
158
DBUG_ENTER("thr_alarm");
159
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
162
#ifndef USE_ONE_SIGNAL_HAND
163
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
165
pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
166
if (alarm_aborted > 0)
167
{ /* No signal thread */
168
DBUG_PRINT("info", ("alarm aborted"));
169
*alrm= 0; /* No alarm */
170
pthread_mutex_unlock(&LOCK_alarm);
171
#ifndef USE_ONE_SIGNAL_HAND
172
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
176
if (alarm_aborted < 0)
177
sec= 1; /* Abort mode */
179
if (alarm_queue.elements >= max_used_alarms)
181
if (alarm_queue.elements == alarm_queue.max_elements)
183
DBUG_PRINT("info", ("alarm queue full"));
184
fprintf(stderr,"Warning: thr_alarm queue is full\n");
185
*alrm= 0; /* No alarm */
186
pthread_mutex_unlock(&LOCK_alarm);
187
#ifndef USE_ONE_SIGNAL_HAND
188
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
192
max_used_alarms=alarm_queue.elements+1;
194
reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
197
if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
199
DBUG_PRINT("info", ("failed my_malloc()"));
200
*alrm= 0; /* No alarm */
201
pthread_mutex_unlock(&LOCK_alarm);
202
#ifndef USE_ONE_SIGNAL_HAND
203
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
207
alarm_data->malloced=1;
210
alarm_data->malloced=0;
211
alarm_data->expire_time=now+sec;
212
alarm_data->alarmed=0;
213
alarm_data->thread= current_my_thread_var->pthread_self;
214
alarm_data->thread_id= current_my_thread_var->id;
215
queue_insert(&alarm_queue,(uchar*) alarm_data);
217
/* Reschedule alarm if the current one has more than sec left */
220
DBUG_PRINT("info", ("reschedule"));
221
if (pthread_equal(pthread_self(),alarm_thread))
223
alarm(sec); /* purecov: inspected */
224
next_alarm_expire_time= now + sec;
227
reschedule_alarms(); /* Reschedule alarms */
229
pthread_mutex_unlock(&LOCK_alarm);
230
#ifndef USE_ONE_SIGNAL_HAND
231
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
233
(*alrm)= &alarm_data->alarmed;
239
Remove alarm from list of alarms
242
void thr_end_alarm(thr_alarm_t *alarmed)
245
#ifndef USE_ONE_SIGNAL_HAND
249
DBUG_ENTER("thr_end_alarm");
251
#ifndef USE_ONE_SIGNAL_HAND
252
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
254
pthread_mutex_lock(&LOCK_alarm);
256
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
257
for (i=0 ; i < alarm_queue.elements ; i++)
259
if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
261
queue_remove(&alarm_queue,i),MYF(0);
262
if (alarm_data->malloced)
263
my_free((uchar*) alarm_data,MYF(0));
270
DBUG_ASSERT(!*alarmed || found == 1);
274
fprintf(stderr,"Warning: Didn't find alarm 0x%lx in queue of %d alarms\n",
275
(long) *alarmed, alarm_queue.elements);
276
DBUG_PRINT("warning",("Didn't find alarm 0x%lx in queue\n",
279
pthread_mutex_unlock(&LOCK_alarm);
280
#ifndef USE_ONE_SIGNAL_HAND
281
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
287
Come here when some alarm in queue is due.
288
Mark all alarms with are finnished in list.
289
Shedule alarms to be sent again after 1-10 sec (many alarms at once)
290
If alarm_aborted is set then all alarms are given and resent
294
sig_handler process_alarm(int sig __attribute__((unused)))
298
This must be first as we can't call DBUG inside an alarm for a normal thread
301
if (thd_lib_detected == THD_LIB_LT &&
302
!pthread_equal(pthread_self(),alarm_thread))
304
#if defined(MAIN) && !defined(__bsdi__)
305
printf("thread_alarm in process_alarm\n"); fflush(stdout);
307
#ifdef DONT_REMEMBER_SIGNAL
308
my_sigset(thr_client_alarm, process_alarm); /* int. thread system calls */
314
We have to do do the handling of the alarm in a sub function,
315
because otherwise we would get problems with two threads calling
316
DBUG_... functions at the same time (as two threads may call
317
process_alarm() at the same time
320
#ifndef USE_ALARM_THREAD
321
pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
322
pthread_mutex_lock(&LOCK_alarm);
324
process_alarm_part2(sig);
325
#ifndef USE_ALARM_THREAD
326
#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
327
my_sigset(THR_SERVER_ALARM,process_alarm);
329
pthread_mutex_unlock(&LOCK_alarm);
330
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
336
static sig_handler process_alarm_part2(int sig __attribute__((unused)))
339
DBUG_ENTER("process_alarm");
340
DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
343
printf("process_alarm\n"); fflush(stdout);
345
if (alarm_queue.elements)
350
for (i=0 ; i < alarm_queue.elements ;)
352
alarm_data=(ALARM*) queue_element(&alarm_queue,i);
353
alarm_data->alarmed=1; /* Info to thread */
354
if (pthread_equal(alarm_data->thread,alarm_thread) ||
355
pthread_kill(alarm_data->thread, thr_client_alarm))
358
printf("Warning: pthread_kill couldn't find thread!!!\n");
360
queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
363
i++; /* Signal next thread */
365
#ifndef USE_ALARM_THREAD
366
if (alarm_queue.elements)
367
alarm(1); /* Signal soon again */
372
ulong now=(ulong) my_time(0);
373
ulong next=now+10-(now%10);
374
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
376
alarm_data->alarmed=1; /* Info to thread */
377
DBUG_PRINT("info",("sending signal to waiting thread"));
378
if (pthread_equal(alarm_data->thread,alarm_thread) ||
379
pthread_kill(alarm_data->thread, thr_client_alarm))
382
printf("Warning: pthread_kill couldn't find thread!!!\n");
384
queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
385
if (!alarm_queue.elements)
390
alarm_data->expire_time=next;
391
queue_replaced(&alarm_queue);
394
#ifndef USE_ALARM_THREAD
395
if (alarm_queue.elements)
397
alarm((uint) (alarm_data->expire_time-now));
398
next_alarm_expire_time= alarm_data->expire_time;
406
Ensure that next time we call thr_alarm(), we will schedule a new alarm
408
next_alarm_expire_time= ~(time_t) 0;
415
Schedule all alarms now and optionally free all structures
419
free_structures Set to 1 if we should free memory used for
421
When we call this we should KNOW that there
424
Set alarm_abort to -1 which will change the behavior of alarms as follows:
425
- All old alarms will be rescheduled at once
426
- All new alarms will be rescheduled to one second
429
void end_thr_alarm(my_bool free_structures)
431
DBUG_ENTER("end_thr_alarm");
432
if (alarm_aborted != 1) /* If memory not freed */
434
pthread_mutex_lock(&LOCK_alarm);
435
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
436
alarm_aborted= -1; /* mark aborted */
437
if (alarm_queue.elements || (alarm_thread_running && free_structures))
439
if (pthread_equal(pthread_self(),alarm_thread))
440
alarm(1); /* Shut down everything soon */
446
struct timespec abstime;
448
DBUG_ASSERT(!alarm_queue.elements);
450
/* Wait until alarm thread dies */
451
set_timespec(abstime, 10); /* Wait up to 10 seconds */
452
while (alarm_thread_running)
454
int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime);
455
if (error == ETIME || error == ETIMEDOUT)
456
break; /* Don't wait forever */
458
delete_queue(&alarm_queue);
460
pthread_mutex_unlock(&LOCK_alarm);
461
if (!alarm_thread_running) /* Safety */
463
pthread_mutex_destroy(&LOCK_alarm);
464
pthread_cond_destroy(&COND_alarm);
468
pthread_mutex_unlock(&LOCK_alarm);
475
Remove another thread from the alarm
478
void thr_alarm_kill(my_thread_id thread_id)
483
pthread_mutex_lock(&LOCK_alarm);
484
for (i=0 ; i < alarm_queue.elements ; i++)
486
if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
488
ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
490
queue_insert(&alarm_queue,(uchar*) tmp);
495
pthread_mutex_unlock(&LOCK_alarm);
499
void thr_alarm_info(ALARM_INFO *info)
501
pthread_mutex_lock(&LOCK_alarm);
502
info->next_alarm_time= 0;
503
info->max_used_alarms= max_used_alarms;
504
if ((info->active_alarms= alarm_queue.elements))
506
ulong now=(ulong) my_time(0);
508
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
509
time_diff= (long) (alarm_data->expire_time - now);
510
info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff);
512
pthread_mutex_unlock(&LOCK_alarm);
516
This is here for thread to get interruptet from read/write/fcntl
521
static sig_handler thread_alarm(int sig)
524
printf("thread_alarm\n"); fflush(stdout);
526
#ifdef DONT_REMEMBER_SIGNAL
527
my_sigset(sig,thread_alarm); /* int. thread system calls */
532
#ifdef HAVE_TIMESPEC_TS_SEC
533
#define tv_sec ts_sec
534
#define tv_nsec ts_nsec
537
/* set up a alarm thread with uses 'sleep' to sleep between alarms */
539
#ifdef USE_ALARM_THREAD
540
static void *alarm_handler(void *arg __attribute__((unused)))
543
struct timespec abstime;
545
puts("Starting alarm thread");
548
alarm_thread_running= 1;
549
pthread_mutex_lock(&LOCK_alarm);
552
if (alarm_queue.elements)
554
ulong sleep_time,now= my_time(0);
558
sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
559
if (sleep_time > now)
561
abstime.tv_sec=sleep_time;
563
next_alarm_expire_time= sleep_time;
564
if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
565
error != ETIME && error != ETIMEDOUT)
568
printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
574
else if (alarm_aborted == -1)
578
next_alarm_expire_time= ~ (time_t) 0;
579
if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
582
printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
589
bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
590
alarm_thread_running= 0;
591
pthread_cond_signal(&COND_alarm);
592
pthread_mutex_unlock(&LOCK_alarm);
594
return 0; /* Impossible */
596
#endif /* USE_ALARM_THREAD */
601
/****************************************************************************
602
Handling of test case (when compiled with -DMAIN)
603
***************************************************************************/
606
#if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
608
static pthread_cond_t COND_thread_count;
609
static pthread_mutex_t LOCK_thread_count;
610
static uint thread_count;
613
typedef int * fd_set_ptr;
615
typedef fd_set * fd_set_ptr;
618
static void *test_thread(void *arg)
620
int i,param=*((int*) arg),wait_time,retry;
622
thr_alarm_t got_alarm;
626
printf("Thread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
627
for (i=1 ; i <= 10 ; i++)
629
wait_time=param ? 11-i : i;
630
start_time= my_time(0);
631
if (thr_alarm(&got_alarm,wait_time,0))
633
printf("Thread: %s Alarms aborted\n",my_thread_name());
638
printf("Thread: %s Simulation of no alarm needed\n",my_thread_name());
643
for (retry=0 ; !thr_got_alarm(&got_alarm) && retry < 10 ; retry++)
645
printf("Thread: %s Waiting %d sec\n",my_thread_name(),wait_time);
646
select(0,(fd_set_ptr) &fd,0,0,0);
648
if (!thr_got_alarm(&got_alarm))
650
printf("Thread: %s didn't get an alarm. Aborting!\n",
655
{ /* Simulate alarm-miss */
657
uint max_connection=fileno(stdin);
659
FD_SET(max_connection,&readFDs);
663
printf("Thread: %s Simulating alarm miss\n",my_thread_name());
665
if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
668
break; /* Got new interrupt */
669
printf("Got errno: %d from select. Retrying..\n",errno);
672
printf("Warning: Interrupt of select() doesn't set errno!\n");
676
else /* This shouldn't happen */
678
if (!FD_ISSET(max_connection,&readFDs))
680
printf("Select interrupted, but errno not set\n");
686
VOID(getchar()); /* Somebody was playing */
691
printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
692
(int) (my_time(0)-start_time), wait_time); fflush(stdout);
693
thr_end_alarm(&got_alarm);
696
pthread_mutex_lock(&LOCK_thread_count);
698
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
699
pthread_mutex_unlock(&LOCK_thread_count);
704
#ifdef USE_ONE_SIGNAL_HAND
705
static sig_handler print_signal_warning(int sig)
707
printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
709
#ifdef DONT_REMEMBER_SIGNAL
710
my_sigset(sig,print_signal_warning); /* int. thread system calls */
713
alarm(2); /* reschedule alarm */
715
#endif /* USE_ONE_SIGNAL_HAND */
718
static void *signal_hand(void *arg __attribute__((unused)))
721
int sig,error,err_count=0;;
724
pthread_detach_this_thread();
725
init_thr_alarm(10); /* Setup alarm handler */
726
pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
727
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
728
pthread_mutex_unlock(&LOCK_thread_count);
730
sigemptyset(&set); /* Catch all signals */
731
sigaddset(&set,SIGINT);
732
sigaddset(&set,SIGQUIT);
733
sigaddset(&set,SIGTERM);
734
sigaddset(&set,SIGHUP);
736
sigaddset(&set,SIGTSTP);
738
#ifdef USE_ONE_SIGNAL_HAND
739
sigaddset(&set,THR_SERVER_ALARM); /* For alarms */
740
puts("Starting signal and alarm handling thread");
742
puts("Starting signal handling thread");
744
printf("server alarm: %d thread alarm: %d\n",
745
THR_SERVER_ALARM, thr_client_alarm);
746
DBUG_PRINT("info",("Starting signal and alarm handling thread"));
749
while ((error=my_sigwait(&set,&sig)) == EINTR)
750
printf("sigwait restarted\n");
753
fprintf(stderr,"Got error %d from sigwait\n",error);
755
exit(1); /* Too many errors in test */
758
#ifdef USE_ONE_SIGNAL_HAND
759
if (sig != THR_SERVER_ALARM)
761
printf("Main thread: Got signal %d\n",sig);
767
printf("Aborting nicely\n");
772
printf("Aborting\n");
774
return 0; /* Keep some compilers happy */
776
#ifdef USE_ONE_SIGNAL_HAND
777
case THR_SERVER_ALARM:
786
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
789
pthread_attr_t thr_attr;
792
ALARM_INFO alarm_info;
795
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
797
DBUG_PUSH(argv[1]+2);
799
pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
800
pthread_cond_init(&COND_thread_count,NULL);
802
/* Start a alarm handling thread */
804
sigaddset(&set,SIGINT);
805
sigaddset(&set,SIGQUIT);
806
sigaddset(&set,SIGTERM);
807
sigaddset(&set,SIGHUP);
808
signal(SIGTERM,SIG_DFL); /* If it's blocked by parent */
810
sigaddset(&set,SIGTSTP);
812
sigaddset(&set,THR_SERVER_ALARM);
813
sigdelset(&set, thr_client_alarm);
814
(void) pthread_sigmask(SIG_SETMASK,&set,NULL);
817
sigaddset(&set, thr_client_alarm);
818
VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
821
pthread_attr_init(&thr_attr);
822
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
823
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
824
pthread_attr_setstacksize(&thr_attr,65536L);
826
/* Start signal thread and wait for it to start */
827
VOID(pthread_mutex_lock(&LOCK_thread_count));
828
pthread_create(&tid,&thr_attr,signal_hand,NULL);
829
VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
830
VOID(pthread_mutex_unlock(&LOCK_thread_count));
831
DBUG_PRINT("info",("signal thread created"));
833
thr_setconcurrency(3);
834
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
835
printf("Main thread: %s\n",my_thread_name());
836
for (i=0 ; i < 2 ; i++)
838
param=(int*) malloc(sizeof(int));
840
pthread_mutex_lock(&LOCK_thread_count);
841
if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
843
printf("Can't create thread %d, error: %d\n",i,error);
847
pthread_mutex_unlock(&LOCK_thread_count);
850
pthread_attr_destroy(&thr_attr);
851
pthread_mutex_lock(&LOCK_thread_count);
852
thr_alarm_info(&alarm_info);
853
printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
854
alarm_info.active_alarms, alarm_info.max_used_alarms,
855
alarm_info.next_alarm_time);
858
VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
859
if (thread_count == 1)
861
printf("Calling end_thr_alarm. This should cancel the last thread\n");
865
pthread_mutex_unlock(&LOCK_thread_count);
866
thr_alarm_info(&alarm_info);
868
printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n",
869
alarm_info.active_alarms, alarm_info.max_used_alarms,
870
alarm_info.next_alarm_time);
871
printf("Test succeeded\n");
877
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
880
printf("thr_alarm disabled because we are not using threads\n");
882
printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");