Back to index

glibc  2.9
Defines | Functions | Variables
timer_routines.c File Reference
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sysdep.h>
#include <time.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "posix-timer.h"

Go to the source code of this file.

Defines

#define THREAD_MAXNODES   16

Functions

static void list_init (struct list_links *list)
static void list_append (struct list_links *list, struct list_links *newp)
static void list_insbefore (struct list_links *list, struct list_links *newp)
static void list_unlink (struct list_links *list)
static struct list_linkslist_first (struct list_links *list)
static struct list_linkslist_null (struct list_links *list)
static struct list_linkslist_next (struct list_links *list)
static int list_isempty (struct list_links *list)
static struct thread_nodethread_links2ptr (struct list_links *list)
static struct timer_nodetimer_links2ptr (struct list_links *list)
static void thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
static void init_module (void)
static void reinit_after_fork (void)
void __timer_init_once (void)
static void thread_deinit (struct thread_node *thread)
struct thread_node__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
void __timer_thread_dealloc (struct thread_node *thread)
static void thread_cleanup (void *val)
static void thread_expire_timer (struct thread_node *self, struct timer_node *timer)
static void __attribute__ ((noreturn))
int __timer_thread_queue_timer (struct thread_node *thread, struct timer_node *insert)
int __timer_thread_start (struct thread_node *thread)
void __timer_thread_wakeup (struct thread_node *thread)
static int thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
struct thread_node__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t desired_clock_id)
struct timer_node__timer_alloc (void)
void __timer_dealloc (struct timer_node *timer)
void __timer_mutex_cancel_handler (void *arg)

Variables

static struct thread_node [THREAD_MAXNODES]
pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER
pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT
int __timer_init_failed

Define Documentation

#define THREAD_MAXNODES   16

Definition at line 36 of file timer_routines.c.


Function Documentation

static void __attribute__ ( (noreturn)  ) [static]

Definition at line 354 of file timer_routines.c.

{
  struct thread_node *self = arg;

  /* Register cleanup handler, in case rogue application terminates
     this thread.  (This cannot happen to __timer_signal_thread, which
     doesn't invoke application callbacks). */

  pthread_cleanup_push (thread_cleanup, self);

  pthread_mutex_lock (&__timer_mutex);

  while (1)
    {
      struct list_links *first;
      struct timer_node *timer = NULL;

      /* While the timer queue is not empty, inspect the first node.  */
      first = list_first (&self->timer_queue);
      if (first != list_null (&self->timer_queue))
       {
         struct timespec now;

         timer = timer_links2ptr (first);

         /* This assumes that the elements of the list of one thread
            are all for the same clock.  */
         clock_gettime (timer->clock, &now);

         while (1)
           {
             /* If the timer is due or overdue, remove it from the queue.
               If it's a periodic timer, re-compute its new time and
               requeue it.  Either way, perform the timer expiry. */
             if (timespec_compare (&now, &timer->expirytime) < 0)
              break;

             list_unlink_ip (first);

             if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0
                || timer->value.it_interval.tv_nsec != 0)
              {
                timer->overrun_count = 0;
                timespec_add (&timer->expirytime, &timer->expirytime,
                            &timer->value.it_interval);
                while (timespec_compare (&timer->expirytime, &now) < 0)
                  {
                    timespec_add (&timer->expirytime, &timer->expirytime,
                                &timer->value.it_interval);
                    if (timer->overrun_count < DELAYTIMER_MAX)
                     ++timer->overrun_count;
                  }
                __timer_thread_queue_timer (self, timer);
              }

             thread_expire_timer (self, timer);

             first = list_first (&self->timer_queue);
             if (first == list_null (&self->timer_queue))
              break;

             timer = timer_links2ptr (first);
           }
       }

      /* If the queue is not empty, wait until the expiry time of the
        first node.  Otherwise wait indefinitely.  Insertions at the
        head of the queue must wake up the thread by broadcasting
        this condition variable.  */
      if (timer != NULL)
       pthread_cond_timedwait (&self->cond, &__timer_mutex,
                            &timer->expirytime);
      else
       pthread_cond_wait (&self->cond, &__timer_mutex);
    }
  /* This macro will never be executed since the while loop loops
     forever - but we have to add it for proper nesting.  */
  pthread_cleanup_pop (1);
}

Here is the call graph for this function:

struct timer_node* __timer_alloc ( void  ) [read]

Definition at line 539 of file timer_routines.c.

{
  struct list_links *node = list_first (&timer_free_list);

  if (node != list_null (&timer_free_list))
    {
      struct timer_node *timer = timer_links2ptr (node);
      list_unlink_ip (node);
      timer->inuse = TIMER_INUSE;
      timer->refcount = 1;
      return timer;
    }

  return NULL;
}
void __timer_dealloc ( struct timer_node timer)

Definition at line 559 of file timer_routines.c.

{
  assert (timer->refcount == 0);
  timer->thread = NULL;     /* Break association between timer and thread.  */
  timer->inuse = TIMER_FREE;
  list_append (&timer_free_list, &timer->links);
}
void __timer_init_once ( void  ) [read]

Definition at line 206 of file timer_routines.c.

void __timer_mutex_cancel_handler ( void *  arg)

Definition at line 570 of file timer_routines.c.

Here is the call graph for this function:

struct thread_node* __timer_thread_alloc ( const pthread_attr_t desired_attr,
clockid_t  clock_id 
) [read]

Definition at line 226 of file timer_routines.c.

{
  struct list_links *node = list_first (&thread_free_list);

  if (node != list_null (&thread_free_list))
    {
      struct thread_node *thread = thread_links2ptr (node);
      list_unlink (node);
      thread_init (thread, desired_attr, clock_id);
      list_append (&thread_active_list, node);
      return thread;
    }

  return 0;
}
void __timer_thread_dealloc ( struct thread_node thread)

Definition at line 246 of file timer_routines.c.

{
  thread_deinit (thread);
  list_unlink (&thread->links);
  list_append (&thread_free_list, &thread->links);
}
struct thread_node* __timer_thread_find_matching ( const pthread_attr_t desired_attr,
clockid_t  desired_clock_id 
) [read]

Definition at line 516 of file timer_routines.c.

{
  struct list_links *iter = list_first (&thread_active_list);

  while (iter != list_null (&thread_active_list))
    {
      struct thread_node *candidate = thread_links2ptr (iter);

      if (thread_attr_compare (desired_attr, &candidate->attr)
         && desired_clock_id == candidate->clock_id)
       return candidate;

      iter = list_next (iter);
    }

  return NULL;
}
int __timer_thread_queue_timer ( struct thread_node thread,
struct timer_node insert 
)

Definition at line 441 of file timer_routines.c.

{
  struct list_links *iter;
  int athead = 1;

  for (iter = list_first (&thread->timer_queue);
       iter != list_null (&thread->timer_queue);
        iter = list_next (iter))
    {
      struct timer_node *timer = timer_links2ptr (iter);

      if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
         break;
      athead = 0;
    }

  list_insbefore (iter, &insert->links);
  return athead;
}
int __timer_thread_start ( struct thread_node thread)

Definition at line 466 of file timer_routines.c.

{
  int retval = 1;

  assert (!thread->exists);
  thread->exists = 1;

  if (pthread_create (&thread->id, &thread->attr,
                    (void *(*) (void *)) thread_func, thread) != 0)
    {
      thread->exists = 0;
      retval = -1;
    }

  return retval;
}
void __timer_thread_wakeup ( struct thread_node thread)

Definition at line 485 of file timer_routines.c.

{
  pthread_cond_broadcast (&thread->cond);
}
static void init_module ( void  ) [static]

Definition at line 169 of file timer_routines.c.

{
  int i;

  list_init (&timer_free_list);
  list_init (&thread_free_list);
  list_init (&thread_active_list);

  for (i = 0; i < TIMER_MAX; ++i)
    {
      list_append (&timer_free_list, &__timer_array[i].links);
      __timer_array[i].inuse = TIMER_FREE;
    }

  for (i = 0; i < THREAD_MAXNODES; ++i)
    list_append (&thread_free_list, &thread_array[i].links);

  thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void list_append ( struct list_links list,
struct list_links newp 
) [inline, static]

Definition at line 75 of file timer_routines.c.

{
  newp->prev = list->prev;
  newp->next = list;
  list->prev->next = newp;
  list->prev = newp;
}

Here is the caller graph for this function:

static struct list_links* list_first ( struct list_links list) [static, read]

Definition at line 104 of file timer_routines.c.

{
  return list->next;
}

Here is the caller graph for this function:

static void list_init ( struct list_links list) [inline, static]

Definition at line 69 of file timer_routines.c.

{
  list->next = list->prev = list;
}

Here is the caller graph for this function:

static void list_insbefore ( struct list_links list,
struct list_links newp 
) [inline, static]

Definition at line 84 of file timer_routines.c.

{
  list_append (list, newp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int list_isempty ( struct list_links list) [inline, static]

Definition at line 122 of file timer_routines.c.

{
  return list->next == list;
}

Here is the caller graph for this function:

static struct list_links* list_next ( struct list_links list) [static, read]

Definition at line 116 of file timer_routines.c.

{
  return list->next;
}

Here is the caller graph for this function:

static struct list_links* list_null ( struct list_links list) [static, read]

Definition at line 110 of file timer_routines.c.

{
  return list;
}

Here is the caller graph for this function:

static void list_unlink ( struct list_links list) [inline, static]

Definition at line 95 of file timer_routines.c.

{
  struct list_links *lnext = list->next, *lprev = list->prev;

  lnext->prev = lprev;
  lprev->next = lnext;
}

Here is the caller graph for this function:

static void reinit_after_fork ( void  ) [static]

Definition at line 195 of file timer_routines.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static int thread_attr_compare ( const pthread_attr_t left,
const pthread_attr_t right 
) [static]

Definition at line 497 of file timer_routines.c.

{
  return (left->__detachstate == right->__detachstate
         && left->__schedpolicy == right->__schedpolicy
         && left->__guardsize == right->__guardsize
         && (left->__schedparam.sched_priority
             == right->__schedparam.sched_priority)
         && left->__inheritsched == right->__inheritsched
         && left->__scope == right->__scope
         && left->__stacksize == right->__stacksize
         && left->__stackaddr_set == right->__stackaddr_set
         && (left->__stackaddr_set
             || left->__stackaddr == right->__stackaddr));
}

Here is the caller graph for this function:

static void thread_cleanup ( void *  val) [static]

Definition at line 263 of file timer_routines.c.

{
  if (val != NULL)
    {
      struct thread_node *thread = val;

      /* How did the signal thread get killed?  */
      assert (thread != &__timer_signal_thread_rclk);

      pthread_mutex_lock (&__timer_mutex);

      thread->exists = 0;

      /* We are no longer processing a timer event.  */
      thread->current_timer = 0;

      if (list_isempty (&thread->timer_queue))
         __timer_thread_dealloc (thread);
      else
       (void) __timer_thread_start (thread);

      pthread_mutex_unlock (&__timer_mutex);

      /* Unblock potentially blocked timer_delete().  */
      pthread_cond_broadcast (&thread->cond);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void thread_deinit ( struct thread_node thread) [static]

Definition at line 215 of file timer_routines.c.

{
  assert (list_isempty (&thread->timer_queue));
  pthread_cond_destroy (&thread->cond);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void thread_expire_timer ( struct thread_node self,
struct timer_node timer 
) [static]

Definition at line 294 of file timer_routines.c.

{
  self->current_timer = timer; /* Lets timer_delete know timer is running. */

  pthread_mutex_unlock (&__timer_mutex);

  switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL))
    {
    case SIGEV_NONE:
      break;

    case SIGEV_SIGNAL:
#ifdef __NR_rt_sigqueueinfo
      {
       siginfo_t info;

       /* First, clear the siginfo_t structure, so that we don't pass our
          stack content to other tasks.  */
       memset (&info, 0, sizeof (siginfo_t));
       /* We must pass the information about the data in a siginfo_t
           value.  */
       info.si_signo = timer->event.sigev_signo;
       info.si_code = SI_TIMER;
       info.si_pid = timer->creator_pid;
       info.si_uid = getuid ();
       info.si_value = timer->event.sigev_value;

       INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info);
      }
#else
      if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
       {
         if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
           abort ();
        }
#endif
      break;

    case SIGEV_THREAD:
      timer->event.sigev_notify_function (timer->event.sigev_value);
      break;

    default:
      assert (! "unknown event");
      break;
    }

  pthread_mutex_lock (&__timer_mutex);

  self->current_timer = 0;

  pthread_cond_broadcast (&self->cond);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void thread_init ( struct thread_node thread,
const pthread_attr_t attr,
clockid_t  clock_id 
) [static]

Definition at line 146 of file timer_routines.c.

{
  if (attr != NULL)
    thread->attr = *attr;
  else
    {
      pthread_attr_init (&thread->attr);
      pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
    }

  thread->exists = 0;
  list_init (&thread->timer_queue);
  pthread_cond_init (&thread->cond, 0);
  thread->current_timer = 0;
  thread->captured = pthread_self ();
  thread->clock_id = clock_id;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct thread_node* thread_links2ptr ( struct list_links list) [static, read]

Definition at line 130 of file timer_routines.c.

{
  return (struct thread_node *) ((char *) list
                             - offsetof (struct thread_node, links));
}

Here is the caller graph for this function:

static struct timer_node* timer_links2ptr ( struct list_links list) [static, read]

Definition at line 137 of file timer_routines.c.

{
  return (struct timer_node *) ((char *) list
                            - offsetof (struct timer_node, links));
}

Here is the caller graph for this function:


Variable Documentation

Definition at line 51 of file timer_routines.c.

Definition at line 48 of file timer_routines.c.

Definition at line 45 of file timer_routines.c.

struct thread_node[THREAD_MAXNODES] [static]

Definition at line 39 of file timer_routines.c.