Blame sysdeps/pthread/posix-timer.h

Packit 6c4009
/* Definitions for POSIX timer implementation on top of NPTL.
Packit 6c4009
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public License as
Packit 6c4009
   published by the Free Software Foundation; either version 2.1 of the
Packit 6c4009
   License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit 6c4009
   not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <list.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Forward declaration.  */
Packit 6c4009
struct timer_node;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Definitions for an internal thread of the POSIX timer implementation.  */
Packit 6c4009
struct thread_node
Packit 6c4009
{
Packit 6c4009
  struct list_head links;
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
  pthread_t id;
Packit 6c4009
  unsigned int exists;
Packit 6c4009
  struct list_head timer_queue;
Packit 6c4009
  pthread_cond_t cond;
Packit 6c4009
  struct timer_node *current_timer;
Packit 6c4009
  pthread_t captured;
Packit 6c4009
  clockid_t clock_id;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Internal representation of a timer.  */
Packit 6c4009
struct timer_node
Packit 6c4009
{
Packit 6c4009
  struct list_head links;
Packit 6c4009
  struct sigevent event;
Packit 6c4009
  clockid_t clock;
Packit 6c4009
  struct itimerspec value;
Packit 6c4009
  struct timespec expirytime;
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
  unsigned int abstime;
Packit 6c4009
  unsigned int armed;
Packit 6c4009
  enum {
Packit 6c4009
    TIMER_FREE, TIMER_INUSE, TIMER_DELETED
Packit 6c4009
  } inuse;
Packit 6c4009
  struct thread_node *thread;
Packit 6c4009
  pid_t creator_pid;
Packit 6c4009
  int refcount;
Packit 6c4009
  int overrun_count;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The limit is not published if we are compiled with kernel timer support.
Packit 6c4009
   But we still compiled in this implementation with its limit unless built
Packit 6c4009
   to require the kernel support.  */
Packit 6c4009
#ifndef TIMER_MAX
Packit 6c4009
# define TIMER_MAX 256
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Static array with the structures for all the timers.  */
Packit 6c4009
extern struct timer_node __timer_array[TIMER_MAX];
Packit 6c4009
Packit 6c4009
/* Global lock to protect operation on the lists.  */
Packit 6c4009
extern pthread_mutex_t __timer_mutex;
Packit 6c4009
Packit 6c4009
/* Variable to protext initialization.  */
Packit 6c4009
extern pthread_once_t __timer_init_once_control;
Packit 6c4009
Packit 6c4009
/* Nonzero if initialization of timer implementation failed.  */
Packit 6c4009
extern int __timer_init_failed;
Packit 6c4009
Packit 6c4009
/* Node for the thread used to deliver signals.  */
Packit 6c4009
extern struct thread_node __timer_signal_thread_rclk;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return pointer to timer structure corresponding to ID.  */
Packit 6c4009
#define timer_id2ptr(timerid) ((struct timer_node *) timerid)
Packit 6c4009
#define timer_ptr2id(timerid) ((timer_t) timerid)
Packit 6c4009
Packit 6c4009
/* Check whether timer is valid; global mutex must be held. */
Packit 6c4009
static inline int
Packit 6c4009
timer_valid (struct timer_node *timer)
Packit 6c4009
{
Packit 6c4009
  return timer && timer->inuse == TIMER_INUSE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Timer refcount functions; need global mutex. */
Packit 6c4009
extern void __timer_dealloc (struct timer_node *timer);
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
timer_addref (struct timer_node *timer)
Packit 6c4009
{
Packit 6c4009
  timer->refcount++;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
timer_delref (struct timer_node *timer)
Packit 6c4009
{
Packit 6c4009
  if (--timer->refcount == 0)
Packit 6c4009
    __timer_dealloc (timer);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Timespec helper routines.  */
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
timespec_compare (const struct timespec *left, const struct timespec *right)
Packit 6c4009
{
Packit 6c4009
  if (left->tv_sec < right->tv_sec)
Packit 6c4009
    return -1;
Packit 6c4009
  if (left->tv_sec > right->tv_sec)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  if (left->tv_nsec < right->tv_nsec)
Packit 6c4009
    return -1;
Packit 6c4009
  if (left->tv_nsec > right->tv_nsec)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
timespec_add (struct timespec *sum, const struct timespec *left,
Packit 6c4009
	      const struct timespec *right)
Packit 6c4009
{
Packit 6c4009
  sum->tv_sec = left->tv_sec + right->tv_sec;
Packit 6c4009
  sum->tv_nsec = left->tv_nsec + right->tv_nsec;
Packit 6c4009
Packit 6c4009
  if (sum->tv_nsec >= 1000000000)
Packit 6c4009
    {
Packit 6c4009
      ++sum->tv_sec;
Packit 6c4009
      sum->tv_nsec -= 1000000000;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
timespec_sub (struct timespec *diff, const struct timespec *left,
Packit 6c4009
	      const struct timespec *right)
Packit 6c4009
{
Packit 6c4009
  diff->tv_sec = left->tv_sec - right->tv_sec;
Packit 6c4009
  diff->tv_nsec = left->tv_nsec - right->tv_nsec;
Packit 6c4009
Packit 6c4009
  if (diff->tv_nsec < 0)
Packit 6c4009
    {
Packit 6c4009
      --diff->tv_sec;
Packit 6c4009
      diff->tv_nsec += 1000000000;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We need one of the list functions in the other modules.  */
Packit 6c4009
static inline void
Packit 6c4009
list_unlink_ip (struct list_head *list)
Packit 6c4009
{
Packit 6c4009
  struct list_head *lnext = list->next, *lprev = list->prev;
Packit 6c4009
Packit 6c4009
  lnext->prev = lprev;
Packit 6c4009
  lprev->next = lnext;
Packit 6c4009
Packit 6c4009
  /* The suffix ip means idempotent; list_unlink_ip can be called
Packit 6c4009
   * two or more times on the same node.
Packit 6c4009
   */
Packit 6c4009
Packit 6c4009
  list->next = list;
Packit 6c4009
  list->prev = list;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Functions in the helper file.  */
Packit 6c4009
extern void __timer_mutex_cancel_handler (void *arg);
Packit 6c4009
extern void __timer_init_once (void);
Packit 6c4009
extern struct timer_node *__timer_alloc (void);
Packit 6c4009
extern int __timer_thread_start (struct thread_node *thread);
Packit 6c4009
extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
Packit 6c4009
extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
Packit 6c4009
extern void __timer_thread_dealloc (struct thread_node *thread);
Packit 6c4009
extern int __timer_thread_queue_timer (struct thread_node *thread,
Packit 6c4009
				       struct timer_node *insert);
Packit 6c4009
extern void __timer_thread_wakeup (struct thread_node *thread);