~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
16
/* To avoid problems with alarms in debug code, we disable DBUG here */
17
#define FORCE_DBUG_OFF
18
#include <my_global.h>
19
28.1.35 by Monty Taylor
Removed all references to THREAD.
20
#if !defined(DONT_USE_THR_ALARM)
1 by brian
clean slate
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
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);
43
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;
50
51
#ifdef USE_ALARM_THREAD
52
static void *alarm_handler(void *arg);
53
#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
54
#else
55
#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
56
#endif
57
58
static sig_handler thread_alarm(int sig __attribute__((unused)));
59
60
static int compare_ulong(void *not_used __attribute__((unused)),
61
			 uchar *a_ptr,uchar* b_ptr)
62
{
63
  ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
64
  return (a < b) ? -1  : (a == b) ? 0 : 1;
65
}
66
67
void init_thr_alarm(uint max_alarms)
68
{
69
  sigset_t s;
70
  DBUG_ENTER("init_thr_alarm");
71
  alarm_aborted=0;
72
  next_alarm_expire_time= ~ (time_t) 0;
73
  init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
74
	     compare_ulong,NullS);
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;
80
  else
81
    thr_client_alarm= SIGUSR1;
82
#ifndef USE_ALARM_THREAD
83
  if (thd_lib_detected != THD_LIB_LT)
84
#endif
85
  {
86
    my_sigset(thr_client_alarm, thread_alarm);
87
  }
88
  sigemptyset(&s);
89
  sigaddset(&s, THR_SERVER_ALARM);
90
  alarm_thread=pthread_self();
91
#if defined(USE_ALARM_THREAD)
92
  {
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);
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 (thd_lib_detected == THD_LIB_LT)
106
  {
107
    my_sigset(thr_client_alarm, process_alarm);        /* Linuxthreads */
108
    pthread_sigmask(SIG_UNBLOCK, &s, NULL);
109
  }
110
#else
111
  my_sigset(THR_SERVER_ALARM, process_alarm);
112
  pthread_sigmask(SIG_UNBLOCK, &s, NULL);
113
#endif /* USE_ALARM_THREAD */
114
  DBUG_VOID_RETURN;
115
}
116
117
118
void resize_thr_alarm(uint max_alarms)
119
{
120
  pthread_mutex_lock(&LOCK_alarm);
121
  /*
122
    It's ok not to shrink the queue as there may be more pending alarms than
123
    than max_alarms
124
  */
125
  if (alarm_queue.elements < max_alarms)
126
    resize_queue(&alarm_queue,max_alarms+1);
127
  pthread_mutex_unlock(&LOCK_alarm);
128
}
129
130
131
/*
132
  Request alarm after sec seconds.
133
134
  SYNOPSIS
135
    thr_alarm()
136
    alrm		Pointer to alarm detection
137
    alarm_data		Structure to store in alarm queue
138
139
  NOTES
140
    This function can't be called from the alarm-handling thread.
141
142
  RETURN VALUES
143
    0 ok
144
    1 If no more alarms are allowed (aborted by process)
145
146
    Stores in first argument a pointer to a non-zero int which is set to 0
147
    when the alarm has been given
148
*/
149
150
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
151
{
152
  time_t now;
153
#ifndef USE_ONE_SIGNAL_HAND
154
  sigset_t old_mask;
155
#endif
156
  my_bool reschedule;
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));
160
161
  now= my_time(0);
162
#ifndef USE_ONE_SIGNAL_HAND
163
  pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
164
#endif
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);
173
#endif
174
    DBUG_RETURN(1);
175
  }
176
  if (alarm_aborted < 0)
177
    sec= 1;					/* Abort mode */
178
179
  if (alarm_queue.elements >= max_used_alarms)
180
  {
181
    if (alarm_queue.elements == alarm_queue.max_elements)
182
    {
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);
189
#endif
190
      DBUG_RETURN(1);
191
    }
192
    max_used_alarms=alarm_queue.elements+1;
193
  }
194
  reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
195
  if (!alarm_data)
196
  {
197
    if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
198
    {
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);
204
#endif
205
      DBUG_RETURN(1);
206
    }
207
    alarm_data->malloced=1;
208
  }
209
  else
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);
216
217
  /* Reschedule alarm if the current one has more than sec left */
218
  if (reschedule)
219
  {
220
    DBUG_PRINT("info", ("reschedule"));
221
    if (pthread_equal(pthread_self(),alarm_thread))
222
    {
223
      alarm(sec);				/* purecov: inspected */
224
      next_alarm_expire_time= now + sec;
225
    }
226
    else
227
      reschedule_alarms();			/* Reschedule alarms */
228
  }
229
  pthread_mutex_unlock(&LOCK_alarm);
230
#ifndef USE_ONE_SIGNAL_HAND
231
  pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
232
#endif
233
  (*alrm)= &alarm_data->alarmed;
234
  DBUG_RETURN(0);
235
}
236
237
238
/*
239
  Remove alarm from list of alarms
240
*/
241
242
void thr_end_alarm(thr_alarm_t *alarmed)
243
{
244
  ALARM *alarm_data;
245
#ifndef USE_ONE_SIGNAL_HAND
246
  sigset_t old_mask;
247
#endif
248
  uint i, found=0;
249
  DBUG_ENTER("thr_end_alarm");
250
251
#ifndef USE_ONE_SIGNAL_HAND
252
  pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
253
#endif
254
  pthread_mutex_lock(&LOCK_alarm);
255
256
  alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
257
  for (i=0 ; i < alarm_queue.elements ; i++)
258
  {
259
    if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
260
    {
261
      queue_remove(&alarm_queue,i),MYF(0);
262
      if (alarm_data->malloced)
263
	my_free((uchar*) alarm_data,MYF(0));
264
      found++;
265
#ifdef DBUG_OFF
266
      break;
267
#endif
268
    }
269
  }
270
  DBUG_ASSERT(!*alarmed || found == 1);
271
  if (!found)
272
  {
273
    if (*alarmed)
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",
277
			  (long) *alarmed));
278
  }
279
  pthread_mutex_unlock(&LOCK_alarm);
280
#ifndef USE_ONE_SIGNAL_HAND
281
  pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
282
#endif
283
  DBUG_VOID_RETURN;
284
}
285
286
/*
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
291
  every second.
292
*/
293
294
sig_handler process_alarm(int sig __attribute__((unused)))
295
{
296
  sigset_t old_mask;
297
/*
298
  This must be first as we can't call DBUG inside an alarm for a normal thread
299
*/
300
301
  if (thd_lib_detected == THD_LIB_LT &&
302
      !pthread_equal(pthread_self(),alarm_thread))
303
  {
304
#if defined(MAIN) && !defined(__bsdi__)
305
    printf("thread_alarm in process_alarm\n"); fflush(stdout);
306
#endif
307
#ifdef DONT_REMEMBER_SIGNAL
308
    my_sigset(thr_client_alarm, process_alarm);	/* int. thread system calls */
309
#endif
310
    return;
311
  }
312
313
  /*
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
318
  */
319
320
#ifndef USE_ALARM_THREAD
321
  pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
322
  pthread_mutex_lock(&LOCK_alarm);
323
#endif
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);
328
#endif
329
  pthread_mutex_unlock(&LOCK_alarm);
330
  pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
331
#endif
332
  return;
333
}
334
335
336
static sig_handler process_alarm_part2(int sig __attribute__((unused)))
337
{
338
  ALARM *alarm_data;
339
  DBUG_ENTER("process_alarm");
340
  DBUG_PRINT("info",("sig: %d  active alarms: %d",sig,alarm_queue.elements));
341
342
#if defined(MAIN)
343
  printf("process_alarm\n"); fflush(stdout);
344
#endif
345
  if (alarm_queue.elements)
346
  {
347
    if (alarm_aborted)
348
    {
349
      uint i;
350
      for (i=0 ; i < alarm_queue.elements ;)
351
      {
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))
356
	{
357
#ifdef MAIN
358
	  printf("Warning: pthread_kill couldn't find thread!!!\n");
359
#endif
360
	  queue_remove(&alarm_queue,i);		/* No thread. Remove alarm */
361
	}
362
	else
363
	  i++;					/* Signal next thread */
364
      }
365
#ifndef USE_ALARM_THREAD
366
      if (alarm_queue.elements)
367
	alarm(1);				/* Signal soon again */
368
#endif
369
    }
370
    else
371
    {
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)
375
      {
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))
380
	{
381
#ifdef MAIN
382
	  printf("Warning: pthread_kill couldn't find thread!!!\n");
383
#endif
384
	  queue_remove(&alarm_queue,0);		/* No thread. Remove alarm */
385
	  if (!alarm_queue.elements)
386
	    break;
387
	}
388
	else
389
	{
390
	  alarm_data->expire_time=next;
391
	  queue_replaced(&alarm_queue);
392
	}
393
      }
394
#ifndef USE_ALARM_THREAD
395
      if (alarm_queue.elements)
396
      {
397
	alarm((uint) (alarm_data->expire_time-now));
398
        next_alarm_expire_time= alarm_data->expire_time;
399
      }
400
#endif
401
    }
402
  }
403
  else
404
  {
405
    /*
406
      Ensure that next time we call thr_alarm(), we will schedule a new alarm
407
    */
408
    next_alarm_expire_time= ~(time_t) 0;
409
  }
410
  DBUG_VOID_RETURN;
411
}
412
413
414
/*
415
  Schedule all alarms now and optionally free all structures
416
417
  SYNPOSIS
418
    end_thr_alarm()
419
      free_structures		Set to 1 if we should free memory used for
420
				the alarm queue.
421
				When we call this we should KNOW that there
422
				is no active alarms
423
  IMPLEMENTATION
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
427
*/
428
429
void end_thr_alarm(my_bool free_structures)
430
{
431
  DBUG_ENTER("end_thr_alarm");
432
  if (alarm_aborted != 1)			/* If memory not freed */
433
  {
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))
438
    {
439
      if (pthread_equal(pthread_self(),alarm_thread))
440
	alarm(1);				/* Shut down everything soon */
441
      else
442
	reschedule_alarms();
443
    }
444
    if (free_structures)
445
    {
446
      struct timespec abstime;
447
448
      DBUG_ASSERT(!alarm_queue.elements);
449
450
      /* Wait until alarm thread dies */
451
      set_timespec(abstime, 10);		/* Wait up to 10 seconds */
452
      while (alarm_thread_running)
453
      {
454
	int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime);
455
	if (error == ETIME || error == ETIMEDOUT)
456
	  break;				/* Don't wait forever */
457
      }
458
      delete_queue(&alarm_queue);
459
      alarm_aborted= 1;
460
      pthread_mutex_unlock(&LOCK_alarm);
461
      if (!alarm_thread_running)              /* Safety */
462
      {
463
        pthread_mutex_destroy(&LOCK_alarm);
464
        pthread_cond_destroy(&COND_alarm);
465
      }
466
    }
467
    else
468
      pthread_mutex_unlock(&LOCK_alarm);
469
  }
470
  DBUG_VOID_RETURN;
471
}
472
473
474
/*
475
  Remove another thread from the alarm
476
*/
477
478
void thr_alarm_kill(my_thread_id thread_id)
479
{
480
  uint i;
481
  if (alarm_aborted)
482
    return;
483
  pthread_mutex_lock(&LOCK_alarm);
484
  for (i=0 ; i < alarm_queue.elements ; i++)
485
  {
486
    if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
487
    {
488
      ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
489
      tmp->expire_time=0;
490
      queue_insert(&alarm_queue,(uchar*) tmp);
491
      reschedule_alarms();
492
      break;
493
    }
494
  }
495
  pthread_mutex_unlock(&LOCK_alarm);
496
}
497
498
499
void thr_alarm_info(ALARM_INFO *info)
500
{
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))
505
  {
506
    ulong now=(ulong) my_time(0);
507
    long time_diff;
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);
511
  }
512
  pthread_mutex_unlock(&LOCK_alarm);
513
}
514
515
/*
516
  This is here for thread to get interruptet from read/write/fcntl
517
  ARGSUSED
518
*/
519
520
521
static sig_handler thread_alarm(int sig)
522
{
523
#ifdef MAIN
524
  printf("thread_alarm\n"); fflush(stdout);
525
#endif
526
#ifdef DONT_REMEMBER_SIGNAL
527
  my_sigset(sig,thread_alarm);		/* int. thread system calls */
528
#endif
529
}
530
531
532
#ifdef HAVE_TIMESPEC_TS_SEC
533
#define tv_sec ts_sec
534
#define tv_nsec ts_nsec
535
#endif
536
537
/* set up a alarm thread with uses 'sleep' to sleep between alarms */
538
539
#ifdef USE_ALARM_THREAD
540
static void *alarm_handler(void *arg __attribute__((unused)))
541
{
542
  int error;
543
  struct timespec abstime;
544
#ifdef MAIN
545
  puts("Starting alarm thread");
546
#endif
547
  my_thread_init();
548
  alarm_thread_running= 1;
549
  pthread_mutex_lock(&LOCK_alarm);
550
  for (;;)
551
  {
552
    if (alarm_queue.elements)
553
    {
554
      ulong sleep_time,now= my_time(0);
555
      if (alarm_aborted)
556
	sleep_time=now+1;
557
      else
558
	sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
559
      if (sleep_time > now)
560
      {
561
	abstime.tv_sec=sleep_time;
562
	abstime.tv_nsec=0;
563
        next_alarm_expire_time= sleep_time;
564
	if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
565
	    error != ETIME && error != ETIMEDOUT)
566
	{
567
#ifdef MAIN
568
	  printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
569
		 error,errno);
570
#endif
571
	}
572
      }
573
    }
574
    else if (alarm_aborted == -1)
575
      break;
576
    else
577
    {
578
      next_alarm_expire_time= ~ (time_t) 0;
579
      if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
580
      {
581
#ifdef MAIN
582
        printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
583
               error,errno);
584
#endif
585
      }
586
    }
587
    process_alarm(0);
588
  }
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);
593
  pthread_exit(0);
594
  return 0;					/* Impossible */
595
}
596
#endif /* USE_ALARM_THREAD */
597
598
#endif /* THREAD */
599
600
601
/****************************************************************************
602
  Handling of test case (when compiled with -DMAIN)
603
***************************************************************************/
604
605
#ifdef MAIN
28.1.35 by Monty Taylor
Removed all references to THREAD.
606
#if !defined(DONT_USE_THR_ALARM)
1 by brian
clean slate
607
608
static pthread_cond_t COND_thread_count;
609
static pthread_mutex_t LOCK_thread_count;
610
static uint thread_count;
611
612
#ifdef HPUX10
613
typedef int * fd_set_ptr;
614
#else
615
typedef fd_set * fd_set_ptr;
616
#endif /* HPUX10 */
617
618
static void *test_thread(void *arg)
619
{
620
  int i,param=*((int*) arg),wait_time,retry;
621
  time_t start_time;
622
  thr_alarm_t got_alarm;
623
  fd_set fd;
624
  FD_ZERO(&fd);
625
  my_thread_init();
626
  printf("Thread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
627
  for (i=1 ; i <= 10 ; i++)
628
  {
629
    wait_time=param ? 11-i : i;
630
    start_time= my_time(0);
631
    if (thr_alarm(&got_alarm,wait_time,0))
632
    {
633
      printf("Thread: %s  Alarms aborted\n",my_thread_name());
634
      break;
635
    }
636
    if (wait_time == 3)
637
    {
638
      printf("Thread: %s  Simulation of no alarm needed\n",my_thread_name());
639
      fflush(stdout);
640
    }
641
    else
642
    {
643
      for (retry=0 ; !thr_got_alarm(&got_alarm) && retry < 10 ; retry++)
644
      {
645
	printf("Thread: %s  Waiting %d sec\n",my_thread_name(),wait_time);
646
	select(0,(fd_set_ptr) &fd,0,0,0);
647
      }
648
      if (!thr_got_alarm(&got_alarm))
649
      {
650
	printf("Thread: %s  didn't get an alarm. Aborting!\n",
651
	       my_thread_name());
652
	break;
653
      }
654
      if (wait_time == 7)
655
      {						/* Simulate alarm-miss */
656
	fd_set readFDs;
657
	uint max_connection=fileno(stdin);
658
	FD_ZERO(&readFDs);
659
	FD_SET(max_connection,&readFDs);
660
	retry=0;
661
	for (;;)
662
	{
663
	  printf("Thread: %s  Simulating alarm miss\n",my_thread_name());
664
	  fflush(stdout);
665
	  if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
666
	  {
667
	    if (errno == EINTR)
668
	      break;				/* Got new interrupt */
669
	    printf("Got errno: %d from select.  Retrying..\n",errno);
670
	    if (retry++ >= 3)
671
	    {
672
	      printf("Warning:  Interrupt of select() doesn't set errno!\n");
673
	      break;
674
	    }
675
	  }
676
	  else					/* This shouldn't happen */
677
	  {
678
	    if (!FD_ISSET(max_connection,&readFDs))
679
	    {
680
	      printf("Select interrupted, but errno not set\n");
681
	      fflush(stdout);
682
	      if (retry++ >= 3)
683
		break;
684
	      continue;
685
	    }
686
	    VOID(getchar());			/* Somebody was playing */
687
	  }
688
	}
689
      }
690
    }
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);
694
    fflush(stdout);
695
  }
696
  pthread_mutex_lock(&LOCK_thread_count);
697
  thread_count--;
698
  VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
699
  pthread_mutex_unlock(&LOCK_thread_count);
700
  free((uchar*) arg);
701
  return 0;
702
}
703
704
#ifdef USE_ONE_SIGNAL_HAND
705
static sig_handler print_signal_warning(int sig)
706
{
707
  printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
708
  fflush(stdout);
709
#ifdef DONT_REMEMBER_SIGNAL
710
  my_sigset(sig,print_signal_warning);		/* int. thread system calls */
711
#endif
712
  if (sig == SIGALRM)
713
    alarm(2);					/* reschedule alarm */
714
}
715
#endif /* USE_ONE_SIGNAL_HAND */
716
717
718
static void *signal_hand(void *arg __attribute__((unused)))
719
{
720
  sigset_t set;
721
  int sig,error,err_count=0;;
722
723
  my_thread_init();
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);
729
730
  sigemptyset(&set);				/* Catch all signals */
731
  sigaddset(&set,SIGINT);
732
  sigaddset(&set,SIGQUIT);
733
  sigaddset(&set,SIGTERM);
734
  sigaddset(&set,SIGHUP);
735
#ifdef SIGTSTP
736
  sigaddset(&set,SIGTSTP);
737
#endif
738
#ifdef USE_ONE_SIGNAL_HAND
739
  sigaddset(&set,THR_SERVER_ALARM);		/* For alarms */
740
  puts("Starting signal and alarm handling thread");
741
#else
742
  puts("Starting signal handling thread");
743
#endif
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"));
747
  for(;;)
748
  {
749
    while ((error=my_sigwait(&set,&sig)) == EINTR)
750
      printf("sigwait restarted\n");
751
    if (error)
752
    {
753
      fprintf(stderr,"Got error %d from sigwait\n",error);
754
      if (err_count++ > 5)
755
	exit(1);				/* Too many errors in test */
756
      continue;
757
    }
758
#ifdef USE_ONE_SIGNAL_HAND
759
    if (sig != THR_SERVER_ALARM)
760
#endif
761
      printf("Main thread: Got signal %d\n",sig);
762
    switch (sig) {
763
    case SIGINT:
764
    case SIGQUIT:
765
    case SIGTERM:
766
    case SIGHUP:
767
      printf("Aborting nicely\n");
768
      end_thr_alarm(0);
769
      break;
770
#ifdef SIGTSTP
771
    case SIGTSTP:
772
      printf("Aborting\n");
773
      exit(1);
774
      return 0;					/* Keep some compilers happy */
775
#endif
776
#ifdef USE_ONE_SIGNAL_HAND
777
     case THR_SERVER_ALARM:
778
       process_alarm(sig);
779
      break;
780
#endif
781
    }
782
  }
783
}
784
785
786
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
787
{
788
  pthread_t tid;
789
  pthread_attr_t thr_attr;
790
  int i,*param,error;
791
  sigset_t set;
792
  ALARM_INFO alarm_info;
793
  MY_INIT(argv[0]);
794
795
  if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
796
  {
797
    DBUG_PUSH(argv[1]+2);
798
  }
799
  pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
800
  pthread_cond_init(&COND_thread_count,NULL);
801
802
  /* Start a alarm handling thread */
803
  sigemptyset(&set);
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 */
809
#ifdef SIGTSTP
810
  sigaddset(&set,SIGTSTP);
811
#endif
812
  sigaddset(&set,THR_SERVER_ALARM);
813
  sigdelset(&set, thr_client_alarm);
814
  (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
815
#ifdef NOT_USED
816
  sigemptyset(&set);
817
  sigaddset(&set, thr_client_alarm);
818
  VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
819
#endif
820
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);
825
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"));
832
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++)
837
  {
838
    param=(int*) malloc(sizeof(int));
839
    *param= i;
840
    pthread_mutex_lock(&LOCK_thread_count);
841
    if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
842
    {
843
      printf("Can't create thread %d, error: %d\n",i,error);
844
      exit(1);
845
    }
846
    thread_count++;
847
    pthread_mutex_unlock(&LOCK_thread_count);
848
  }
849
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);
856
  while (thread_count)
857
  {
858
    VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
859
    if (thread_count == 1)
860
    {
861
      printf("Calling end_thr_alarm. This should cancel the last thread\n");
862
      end_thr_alarm(0);
863
    }
864
  }
865
  pthread_mutex_unlock(&LOCK_thread_count);
866
  thr_alarm_info(&alarm_info);
867
  end_thr_alarm(1);
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");
872
  return 0;
873
}
874
28.1.35 by Monty Taylor
Removed all references to THREAD.
875
#else /* DONT_USE_THR_ALARM */
1 by brian
clean slate
876
877
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
878
{
879
  printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");
880
  exit(1);
881
}
882
28.1.35 by Monty Taylor
Removed all references to THREAD.
883
#endif /* DONT_USE_THR_ALARM */
1 by brian
clean slate
884
#endif /* MAIN */