~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_alarm.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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