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