~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_alarm.c

  • Committer: Brian Aker
  • Date: 2009-10-16 10:27:33 UTC
  • mfrom: (1183.1.4 merge)
  • Revision ID: brian@gaz-20091016102733-b10po5oup0hjlilh
MergeĀ EngineĀ changes.

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