~drizzle-trunk/drizzle/development

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