Blame sysdeps/pthread/timer_routines.c

Packit Service 82fcde
/* Helper code for POSIX timer implementation on NPTL.
Packit Service 82fcde
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public License as
Packit Service 82fcde
   published by the Free Software Foundation; either version 2.1 of the
Packit Service 82fcde
   License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit Service 82fcde
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
#include <time.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/syscall.h>
Packit Service 82fcde
Packit Service 82fcde
#include "posix-timer.h"
Packit Service 82fcde
#include <timer_routines.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef DELAYTIMER_MAX
Packit Service 82fcde
# define DELAYTIMER_MAX INT_MAX
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Number of threads used.  */
Packit Service 82fcde
#define THREAD_MAXNODES	16
Packit Service 82fcde
Packit Service 82fcde
/* Array containing the descriptors for the used threads.  */
Packit Service 82fcde
static struct thread_node thread_array[THREAD_MAXNODES];
Packit Service 82fcde
Packit Service 82fcde
/* Static array with the structures for all the timers.  */
Packit Service 82fcde
struct timer_node __timer_array[TIMER_MAX];
Packit Service 82fcde
Packit Service 82fcde
/* Global lock to protect operation on the lists.  */
Packit Service 82fcde
pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit Service 82fcde
Packit Service 82fcde
/* Variable to protext initialization.  */
Packit Service 82fcde
pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
Packit Service 82fcde
Packit Service 82fcde
/* Nonzero if initialization of timer implementation failed.  */
Packit Service 82fcde
int __timer_init_failed;
Packit Service 82fcde
Packit Service 82fcde
/* Node for the thread used to deliver signals.  */
Packit Service 82fcde
struct thread_node __timer_signal_thread_rclk;
Packit Service 82fcde
Packit Service 82fcde
/* Lists to keep free and used timers and threads.  */
Packit Service 82fcde
static struct list_head timer_free_list;
Packit Service 82fcde
static struct list_head thread_free_list;
Packit Service 82fcde
static struct list_head thread_active_list;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#ifdef __NR_rt_sigqueueinfo
Packit Service 82fcde
extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* List handling functions.  */
Packit Service 82fcde
static inline void
Packit Service 82fcde
list_append (struct list_head *list, struct list_head *newp)
Packit Service 82fcde
{
Packit Service 82fcde
  newp->prev = list->prev;
Packit Service 82fcde
  newp->next = list;
Packit Service 82fcde
  list->prev->next = newp;
Packit Service 82fcde
  list->prev = newp;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline void
Packit Service 82fcde
list_insbefore (struct list_head *list, struct list_head *newp)
Packit Service 82fcde
{
Packit Service 82fcde
  list_append (list, newp);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/*
Packit Service 82fcde
 * Like list_unlink_ip, except that calling it on a node that
Packit Service 82fcde
 * is already unlinked is disastrous rather than a noop.
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
static inline void
Packit Service 82fcde
list_unlink (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list_head *lnext = list->next, *lprev = list->prev;
Packit Service 82fcde
Packit Service 82fcde
  lnext->prev = lprev;
Packit Service 82fcde
  lprev->next = lnext;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline struct list_head *
Packit Service 82fcde
list_first (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->next;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline struct list_head *
Packit Service 82fcde
list_null (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline struct list_head *
Packit Service 82fcde
list_next (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->next;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline int
Packit Service 82fcde
list_isempty (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->next == list;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Functions build on top of the list functions.  */
Packit Service 82fcde
static inline struct thread_node *
Packit Service 82fcde
thread_links2ptr (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return (struct thread_node *) ((char *) list
Packit Service 82fcde
				 - offsetof (struct thread_node, links));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline struct timer_node *
Packit Service 82fcde
timer_links2ptr (struct list_head *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return (struct timer_node *) ((char *) list
Packit Service 82fcde
				- offsetof (struct timer_node, links));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Initialize a newly allocated thread structure.  */
Packit Service 82fcde
static void
Packit Service 82fcde
thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
Packit Service 82fcde
{
Packit Service 82fcde
  if (attr != NULL)
Packit Service 82fcde
    thread->attr = *attr;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      pthread_attr_init (&thread->attr);
Packit Service 82fcde
      pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  thread->exists = 0;
Packit Service 82fcde
  INIT_LIST_HEAD (&thread->timer_queue);
Packit Service 82fcde
  pthread_cond_init (&thread->cond, 0);
Packit Service 82fcde
  thread->current_timer = 0;
Packit Service 82fcde
  thread->captured = pthread_self ();
Packit Service 82fcde
  thread->clock_id = clock_id;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Initialize the global lists, and acquire global resources.  Error
Packit Service 82fcde
   reporting is done by storing a non-zero value to the global variable
Packit Service 82fcde
   timer_init_failed.  */
Packit Service 82fcde
static void
Packit Service 82fcde
init_module (void)
Packit Service 82fcde
{
Packit Service 82fcde
  int i;
Packit Service 82fcde
Packit Service 82fcde
  INIT_LIST_HEAD (&timer_free_list);
Packit Service 82fcde
  INIT_LIST_HEAD (&thread_free_list);
Packit Service 82fcde
  INIT_LIST_HEAD (&thread_active_list);
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < TIMER_MAX; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      list_append (&timer_free_list, &__timer_array[i].links);
Packit Service 82fcde
      __timer_array[i].inuse = TIMER_FREE;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < THREAD_MAXNODES; ++i)
Packit Service 82fcde
    list_append (&thread_free_list, &thread_array[i].links);
Packit Service 82fcde
Packit Service 82fcde
  thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This is a handler executed in a child process after a fork()
Packit Service 82fcde
   occurs.  It reinitializes the module, resetting all of the data
Packit Service 82fcde
   structures to their initial state.  The mutex is initialized in
Packit Service 82fcde
   case it was locked in the parent process.  */
Packit Service 82fcde
static void
Packit Service 82fcde
reinit_after_fork (void)
Packit Service 82fcde
{
Packit Service 82fcde
  init_module ();
Packit Service 82fcde
  pthread_mutex_init (&__timer_mutex, 0);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Called once form pthread_once in timer_init. This initializes the
Packit Service 82fcde
   module and ensures that reinit_after_fork will be executed in any
Packit Service 82fcde
   child process.  */
Packit Service 82fcde
void
Packit Service 82fcde
__timer_init_once (void)
Packit Service 82fcde
{
Packit Service 82fcde
  init_module ();
Packit Service 82fcde
  pthread_atfork (0, 0, reinit_after_fork);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Deinitialize a thread that is about to be deallocated.  */
Packit Service 82fcde
static void
Packit Service 82fcde
thread_deinit (struct thread_node *thread)
Packit Service 82fcde
{
Packit Service 82fcde
  assert (list_isempty (&thread->timer_queue));
Packit Service 82fcde
  pthread_cond_destroy (&thread->cond);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Allocate a thread structure from the global free list.  Global
Packit Service 82fcde
   mutex lock must be held by caller.  The thread is moved to
Packit Service 82fcde
   the active list. */
Packit Service 82fcde
struct thread_node *
Packit Service 82fcde
__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list_head *node = list_first (&thread_free_list);
Packit Service 82fcde
Packit Service 82fcde
  if (node != list_null (&thread_free_list))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct thread_node *thread = thread_links2ptr (node);
Packit Service 82fcde
      list_unlink (node);
Packit Service 82fcde
      thread_init (thread, desired_attr, clock_id);
Packit Service 82fcde
      list_append (&thread_active_list, node);
Packit Service 82fcde
      return thread;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return a thread structure to the global free list.  Global lock
Packit Service 82fcde
   must be held by caller.  */
Packit Service 82fcde
void
Packit Service 82fcde
__timer_thread_dealloc (struct thread_node *thread)
Packit Service 82fcde
{
Packit Service 82fcde
  thread_deinit (thread);
Packit Service 82fcde
  list_unlink (&thread->links);
Packit Service 82fcde
  list_append (&thread_free_list, &thread->links);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Each of our threads which terminates executes this cleanup
Packit Service 82fcde
   handler. We never terminate threads ourselves; if a thread gets here
Packit Service 82fcde
   it means that the evil application has killed it.  If the thread has
Packit Service 82fcde
   timers, these require servicing and so we must hire a replacement
Packit Service 82fcde
   thread right away.  We must also unblock another thread that may
Packit Service 82fcde
   have been waiting for this thread to finish servicing a timer (see
Packit Service 82fcde
   timer_delete()).  */
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
thread_cleanup (void *val)
Packit Service 82fcde
{
Packit Service 82fcde
  if (val != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct thread_node *thread = val;
Packit Service 82fcde
Packit Service 82fcde
      /* How did the signal thread get killed?  */
Packit Service 82fcde
      assert (thread != &__timer_signal_thread_rclk);
Packit Service 82fcde
Packit Service 82fcde
      pthread_mutex_lock (&__timer_mutex);
Packit Service 82fcde
Packit Service 82fcde
      thread->exists = 0;
Packit Service 82fcde
Packit Service 82fcde
      /* We are no longer processing a timer event.  */
Packit Service 82fcde
      thread->current_timer = 0;
Packit Service 82fcde
Packit Service 82fcde
      if (list_isempty (&thread->timer_queue))
Packit Service 82fcde
	__timer_thread_dealloc (thread);
Packit Service 82fcde
      else
Packit Service 82fcde
	(void) __timer_thread_start (thread);
Packit Service 82fcde
Packit Service 82fcde
      pthread_mutex_unlock (&__timer_mutex);
Packit Service 82fcde
Packit Service 82fcde
      /* Unblock potentially blocked timer_delete().  */
Packit Service 82fcde
      pthread_cond_broadcast (&thread->cond);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Handle a timer which is supposed to go off now.  */
Packit Service 82fcde
static void
Packit Service 82fcde
thread_expire_timer (struct thread_node *self, struct timer_node *timer)
Packit Service 82fcde
{
Packit Service 82fcde
  self->current_timer = timer; /* Lets timer_delete know timer is running. */
Packit Service 82fcde
Packit Service 82fcde
  pthread_mutex_unlock (&__timer_mutex);
Packit Service 82fcde
Packit Service 82fcde
  switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL))
Packit Service 82fcde
    {
Packit Service 82fcde
    case SIGEV_NONE:
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case SIGEV_SIGNAL:
Packit Service 82fcde
#ifdef __NR_rt_sigqueueinfo
Packit Service 82fcde
      {
Packit Service 82fcde
	siginfo_t info;
Packit Service 82fcde
Packit Service 82fcde
	/* First, clear the siginfo_t structure, so that we don't pass our
Packit Service 82fcde
	   stack content to other tasks.  */
Packit Service 82fcde
	memset (&info, 0, sizeof (siginfo_t));
Packit Service 82fcde
	/* We must pass the information about the data in a siginfo_t
Packit Service 82fcde
           value.  */
Packit Service 82fcde
	info.si_signo = timer->event.sigev_signo;
Packit Service 82fcde
	info.si_code = SI_TIMER;
Packit Service 82fcde
	info.si_pid = timer->creator_pid;
Packit Service 82fcde
	info.si_uid = getuid ();
Packit Service 82fcde
	info.si_value = timer->event.sigev_value;
Packit Service 82fcde
Packit Service 82fcde
	INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info;;
Packit Service 82fcde
      }
Packit Service 82fcde
#else
Packit Service 82fcde
      if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
Packit Service 82fcde
	    abort ();
Packit Service 82fcde
        }
Packit Service 82fcde
#endif
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case SIGEV_THREAD:
Packit Service 82fcde
      timer->event.sigev_notify_function (timer->event.sigev_value);
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    default:
Packit Service 82fcde
      assert (! "unknown event");
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_mutex_lock (&__timer_mutex);
Packit Service 82fcde
Packit Service 82fcde
  self->current_timer = 0;
Packit Service 82fcde
Packit Service 82fcde
  pthread_cond_broadcast (&self->cond);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Thread function; executed by each timer thread. The job of this
Packit Service 82fcde
   function is to wait on the thread's timer queue and expire the
Packit Service 82fcde
   timers in chronological order as close to their scheduled time as
Packit Service 82fcde
   possible.  */
Packit Service 82fcde
static void
Packit Service 82fcde
__attribute__ ((noreturn))
Packit Service 82fcde
thread_func (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  struct thread_node *self = arg;
Packit Service 82fcde
Packit Service 82fcde
  /* Register cleanup handler, in case rogue application terminates
Packit Service 82fcde
     this thread.  (This cannot happen to __timer_signal_thread, which
Packit Service 82fcde
     doesn't invoke application callbacks). */
Packit Service 82fcde
Packit Service 82fcde
  pthread_cleanup_push (thread_cleanup, self);
Packit Service 82fcde
Packit Service 82fcde
  pthread_mutex_lock (&__timer_mutex);
Packit Service 82fcde
Packit Service 82fcde
  while (1)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct list_head *first;
Packit Service 82fcde
      struct timer_node *timer = NULL;
Packit Service 82fcde
Packit Service 82fcde
      /* While the timer queue is not empty, inspect the first node.  */
Packit Service 82fcde
      first = list_first (&self->timer_queue);
Packit Service 82fcde
      if (first != list_null (&self->timer_queue))
Packit Service 82fcde
	{
Packit Service 82fcde
	  struct timespec now;
Packit Service 82fcde
Packit Service 82fcde
	  timer = timer_links2ptr (first);
Packit Service 82fcde
Packit Service 82fcde
	  /* This assumes that the elements of the list of one thread
Packit Service 82fcde
	     are all for the same clock.  */
Packit Service 82fcde
	  __clock_gettime (timer->clock, &now;;
Packit Service 82fcde
Packit Service 82fcde
	  while (1)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* If the timer is due or overdue, remove it from the queue.
Packit Service 82fcde
		 If it's a periodic timer, re-compute its new time and
Packit Service 82fcde
		 requeue it.  Either way, perform the timer expiry. */
Packit Service 82fcde
	      if (timespec_compare (&now, &timer->expirytime) < 0)
Packit Service 82fcde
		break;
Packit Service 82fcde
Packit Service 82fcde
	      list_unlink_ip (first);
Packit Service 82fcde
Packit Service 82fcde
	      if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0
Packit Service 82fcde
		  || timer->value.it_interval.tv_nsec != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  timer->overrun_count = 0;
Packit Service 82fcde
		  timespec_add (&timer->expirytime, &timer->expirytime,
Packit Service 82fcde
				&timer->value.it_interval);
Packit Service 82fcde
		  while (timespec_compare (&timer->expirytime, &now) < 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      timespec_add (&timer->expirytime, &timer->expirytime,
Packit Service 82fcde
				    &timer->value.it_interval);
Packit Service 82fcde
		      if (timer->overrun_count < DELAYTIMER_MAX)
Packit Service 82fcde
			++timer->overrun_count;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  __timer_thread_queue_timer (self, timer);
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      thread_expire_timer (self, timer);
Packit Service 82fcde
Packit Service 82fcde
	      first = list_first (&self->timer_queue);
Packit Service 82fcde
	      if (first == list_null (&self->timer_queue))
Packit Service 82fcde
		break;
Packit Service 82fcde
Packit Service 82fcde
	      timer = timer_links2ptr (first);
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* If the queue is not empty, wait until the expiry time of the
Packit Service 82fcde
	 first node.  Otherwise wait indefinitely.  Insertions at the
Packit Service 82fcde
	 head of the queue must wake up the thread by broadcasting
Packit Service 82fcde
	 this condition variable.  */
Packit Service 82fcde
      if (timer != NULL)
Packit Service 82fcde
	pthread_cond_timedwait (&self->cond, &__timer_mutex,
Packit Service 82fcde
				&timer->expirytime);
Packit Service 82fcde
      else
Packit Service 82fcde
	pthread_cond_wait (&self->cond, &__timer_mutex);
Packit Service 82fcde
    }
Packit Service 82fcde
  /* This macro will never be executed since the while loop loops
Packit Service 82fcde
     forever - but we have to add it for proper nesting.  */
Packit Service 82fcde
  pthread_cleanup_pop (1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Enqueue a timer in wakeup order in the thread's timer queue.
Packit Service 82fcde
   Returns 1 if the timer was inserted at the head of the queue,
Packit Service 82fcde
   causing the queue's next wakeup time to change. */
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
__timer_thread_queue_timer (struct thread_node *thread,
Packit Service 82fcde
			    struct timer_node *insert)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list_head *iter;
Packit Service 82fcde
  int athead = 1;
Packit Service 82fcde
Packit Service 82fcde
  for (iter = list_first (&thread->timer_queue);
Packit Service 82fcde
       iter != list_null (&thread->timer_queue);
Packit Service 82fcde
        iter = list_next (iter))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct timer_node *timer = timer_links2ptr (iter);
Packit Service 82fcde
Packit Service 82fcde
      if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
Packit Service 82fcde
	  break;
Packit Service 82fcde
      athead = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  list_insbefore (iter, &insert->links);
Packit Service 82fcde
  return athead;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Start a thread and associate it with the given thread node.  Global
Packit Service 82fcde
   lock must be held by caller.  */
Packit Service 82fcde
int
Packit Service 82fcde
__timer_thread_start (struct thread_node *thread)
Packit Service 82fcde
{
Packit Service 82fcde
  int retval = 1;
Packit Service 82fcde
  sigset_t set, oset;
Packit Service 82fcde
Packit Service 82fcde
  assert (!thread->exists);
Packit Service 82fcde
  thread->exists = 1;
Packit Service 82fcde
Packit Service 82fcde
  sigfillset (&set);
Packit Service 82fcde
  pthread_sigmask (SIG_SETMASK, &set, &oset);
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_create (&thread->id, &thread->attr,
Packit Service 82fcde
		      (void *(*) (void *)) thread_func, thread) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      thread->exists = 0;
Packit Service 82fcde
      retval = -1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_sigmask (SIG_SETMASK, &oset, NULL);
Packit Service 82fcde
Packit Service 82fcde
  return retval;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__timer_thread_wakeup (struct thread_node *thread)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_cond_broadcast (&thread->cond);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Search the list of active threads and find one which has matching
Packit Service 82fcde
   attributes.  Global mutex lock must be held by caller.  */
Packit Service 82fcde
struct thread_node *
Packit Service 82fcde
__timer_thread_find_matching (const pthread_attr_t *desired_attr,
Packit Service 82fcde
			      clockid_t desired_clock_id)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list_head *iter = list_first (&thread_active_list);
Packit Service 82fcde
Packit Service 82fcde
  while (iter != list_null (&thread_active_list))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct thread_node *candidate = thread_links2ptr (iter);
Packit Service 82fcde
Packit Service 82fcde
      if (thread_attr_compare (desired_attr, &candidate->attr)
Packit Service 82fcde
	  && desired_clock_id == candidate->clock_id)
Packit Service 82fcde
	return candidate;
Packit Service 82fcde
Packit Service 82fcde
      iter = list_next (iter);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Grab a free timer structure from the global free list.  The global
Packit Service 82fcde
   lock must be held by the caller.  */
Packit Service 82fcde
struct timer_node *
Packit Service 82fcde
__timer_alloc (void)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list_head *node = list_first (&timer_free_list);
Packit Service 82fcde
Packit Service 82fcde
  if (node != list_null (&timer_free_list))
Packit Service 82fcde
    {
Packit Service 82fcde
      struct timer_node *timer = timer_links2ptr (node);
Packit Service 82fcde
      list_unlink_ip (node);
Packit Service 82fcde
      timer->inuse = TIMER_INUSE;
Packit Service 82fcde
      timer->refcount = 1;
Packit Service 82fcde
      return timer;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return a timer structure to the global free list.  The global lock
Packit Service 82fcde
   must be held by the caller.  */
Packit Service 82fcde
void
Packit Service 82fcde
__timer_dealloc (struct timer_node *timer)
Packit Service 82fcde
{
Packit Service 82fcde
  assert (timer->refcount == 0);
Packit Service 82fcde
  timer->thread = NULL;	/* Break association between timer and thread.  */
Packit Service 82fcde
  timer->inuse = TIMER_FREE;
Packit Service 82fcde
  list_append (&timer_free_list, &timer->links);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Thread cancellation handler which unlocks a mutex.  */
Packit Service 82fcde
void
Packit Service 82fcde
__timer_mutex_cancel_handler (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_mutex_unlock (arg);
Packit Service 82fcde
}