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