~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_alarm.c

code clean move Item_func_ascii, Item_func_bit_count, Item_func_find_in_set, Item_func_ord  to functions directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "mysys_priv.h"
 
17
 
 
18
#if !defined(DONT_USE_THR_ALARM)
 
19
#include <errno.h>
 
20
#include <my_pthread.h>
 
21
#include <signal.h>
 
22
#include <my_sys.h>
 
23
#include <mystrings/m_string.h>
 
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
#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
 
 
43
#ifndef ETIME
 
44
#define ETIME ETIMEDOUT
 
45
#endif
 
46
 
 
47
uint32_t thr_client_alarm;
 
48
static int alarm_aborted=1;                     /* No alarm thread */
 
49
bool thr_alarm_inited= 0;
 
50
volatile bool alarm_thread_running= 0;
 
51
time_t next_alarm_expire_time= ~ (time_t) 0;
 
52
static RETSIGTYPE process_alarm_part2(int sig);
 
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;
 
58
static uint32_t max_used_alarms=0;
 
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
 
 
68
static RETSIGTYPE thread_alarm(int sig __attribute__((unused)));
 
69
 
 
70
static int compare_uint32_t(void *not_used __attribute__((unused)),
 
71
                         unsigned char *a_ptr,unsigned char* b_ptr)
 
72
{
 
73
  uint32_t a=*((uint32_t*) a_ptr),b= *((uint32_t*) b_ptr);
 
74
  return (a < b) ? -1  : (a == b) ? 0 : 1;
 
75
}
 
76
 
 
77
void init_thr_alarm(uint32_t max_alarms)
 
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,
 
83
             compare_uint32_t,NULL);
 
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 */
 
109
    pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL);
 
110
    pthread_attr_destroy(&thr_attr);
 
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 */
 
123
  return;
 
124
}
 
125
 
 
126
 
 
127
void resize_thr_alarm(uint32_t max_alarms)
 
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
 
 
159
bool thr_alarm(thr_alarm_t *alrm, uint32_t sec, ALARM *alarm_data)
 
160
{
 
161
  time_t now;
 
162
#ifndef USE_ONE_SIGNAL_HAND
 
163
  sigset_t old_mask;
 
164
#endif
 
165
  bool reschedule;
 
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
 
180
    return(1);
 
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
 
195
      return(1);
 
196
    }
 
197
    max_used_alarms=alarm_queue.elements+1;
 
198
  }
 
199
  reschedule= (uint32_t) next_alarm_expire_time > (uint32_t) now + sec;
 
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
 
209
      return(1);
 
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;
 
219
  queue_insert(&alarm_queue,(unsigned char*) alarm_data);
 
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;
 
237
  return(0);
 
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
 
251
  uint32_t i, found=0;
 
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
 
 
258
  alarm_data= (ALARM*) ((unsigned char*) *alarmed - offsetof(ALARM,alarmed));
 
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)
 
265
        free((unsigned char*) alarm_data);
 
266
      found++;
 
267
      break;
 
268
    }
 
269
  }
 
270
  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
  }
 
277
  pthread_mutex_unlock(&LOCK_alarm);
 
278
#ifndef USE_ONE_SIGNAL_HAND
 
279
  pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
 
280
#endif
 
281
  return;
 
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
 
 
292
RETSIGTYPE process_alarm(int sig __attribute__((unused)))
 
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
 
302
#ifndef HAVE_BSD_SIGNALS
 
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
 
314
#if !defined(HAVE_BSD_SIGNALS) && !defined(USE_ONE_SIGNAL_HAND)
 
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
 
 
324
static RETSIGTYPE process_alarm_part2(int sig __attribute__((unused)))
 
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
    {
 
335
      uint32_t i;
 
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
    {
 
358
      uint32_t now=(uint32_t) my_time(0);
 
359
      uint32_t next=now+10-(now%10);
 
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
  }
 
395
  return;
 
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
 
 
414
void end_thr_alarm(bool free_structures)
 
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
 
 
431
      assert(!alarm_queue.elements);
 
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
  }
 
453
  return;
 
454
}
 
455
 
 
456
 
 
457
/*
 
458
  Remove another thread from the alarm
 
459
*/
 
460
 
 
461
void thr_alarm_kill(my_thread_id thread_id)
 
462
{
 
463
  uint32_t i;
 
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;
 
473
      queue_insert(&alarm_queue,(unsigned char*) tmp);
 
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
  {
 
489
    uint32_t now=(uint32_t) my_time(0);
 
490
    long time_diff;
 
491
    ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
 
492
    time_diff= (long) (alarm_data->expire_time - now);
 
493
    info->next_alarm_time= (uint32_t) (time_diff < 0 ? 0 : time_diff);
 
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
 
 
504
static RETSIGTYPE thread_alarm(int sig)
 
505
{
 
506
#ifdef MAIN
 
507
  printf("thread_alarm\n"); fflush(stdout);
 
508
#endif
 
509
#ifndef HAVE_BSD_SIGNALS
 
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
    {
 
537
      uint32_t sleep_time,now= my_time(0);
 
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
  }
 
572
  memset(&alarm_thread, 0, sizeof(alarm_thread)); /* For easy debugging */
 
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
 
589
#if !defined(DONT_USE_THR_ALARM)
 
590
 
 
591
static pthread_cond_t COND_thread_count;
 
592
static pthread_mutex_t LOCK_thread_count;
 
593
static uint32_t thread_count;
 
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;
 
640
        uint32_t max_connection=fileno(stdin);
 
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
            }
 
669
            getchar();                  /* Somebody was playing */
 
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--;
 
681
  pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
 
682
  pthread_mutex_unlock(&LOCK_thread_count);
 
683
  free((unsigned char*) arg);
 
684
  return 0;
 
685
}
 
686
 
 
687
#ifdef USE_ONE_SIGNAL_HAND
 
688
static RETSIGTYPE print_signal_warning(int sig)
 
689
{
 
690
  printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
 
691
  fflush(stdout);
 
692
#ifndef HAVE_BSD_SIGNALS
 
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 */
 
710
  pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
 
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);
 
796
  pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0);
 
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 */
 
805
  pthread_mutex_lock(&LOCK_thread_count);
 
806
  pthread_create(&tid,&thr_attr,signal_hand,NULL);
 
807
  pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
808
  pthread_mutex_unlock(&LOCK_thread_count);
 
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
  {
 
835
    pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
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
 
 
852
#else /* DONT_USE_THR_ALARM */
 
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
 
 
860
#endif /* DONT_USE_THR_ALARM */
 
861
#endif /* MAIN */