1  /* Copyright (C) 2003-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; see the file COPYING.LIB.  If
      16     not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <pthread.h>
      19  #include <setjmp.h>
      20  #include <signal.h>
      21  #include <sys/types.h>
      22  
      23  
      24  /* Nonzero if the system calls are not available.  */
      25  extern int __no_posix_timers attribute_hidden;
      26  
      27  /* Callback to start helper thread.  */
      28  extern void __timer_start_helper_thread (void) attribute_hidden;
      29  
      30  /* Control variable for helper thread creation.  */
      31  extern pthread_once_t __timer_helper_once attribute_hidden;
      32  
      33  /* Called from fork so that the new subprocess re-creates the
      34     notification thread if necessary.  */
      35  void __timer_fork_subprocess (void) attribute_hidden;
      36  
      37  /* TID of the helper thread.  */
      38  extern pid_t __timer_helper_tid attribute_hidden;
      39  
      40  /* List of active SIGEV_THREAD timers.  */
      41  extern struct timer *__timer_active_sigev_thread attribute_hidden;
      42  
      43  /* Lock for __timer_active_sigev_thread.  */
      44  extern pthread_mutex_t __timer_active_sigev_thread_lock attribute_hidden;
      45  
      46  extern __typeof (timer_create) __timer_create;
      47  libc_hidden_proto (__timer_create)
      48  extern __typeof (timer_delete) __timer_delete;
      49  libc_hidden_proto (__timer_delete)
      50  extern __typeof (timer_getoverrun) __timer_getoverrun;
      51  libc_hidden_proto (__timer_getoverrun)
      52  
      53  /* Type of timers in the kernel.  */
      54  typedef int kernel_timer_t;
      55  
      56  /* Internal representation of SIGEV_THREAD timer.  */
      57  struct timer
      58  {
      59    kernel_timer_t ktimerid;
      60  
      61    void (*thrfunc) (sigval_t);
      62    sigval_t sival;
      63    pthread_attr_t attr;
      64  
      65    /* Next element in list of active SIGEV_THREAD timers.  */
      66    struct timer *next;
      67  };
      68  
      69  
      70  /* For !SIGEV_THREAD, the resulting 'timer_t' is the returned kernel timer
      71     identifier (kernel_timer_t), while for SIGEV_THREAD it uses the fact malloc
      72     returns at least _Alignof (max_align_t) pointers plus that valid
      73     kernel_timer_t are always positive to set the MSB bit of the returned
      74     'timer_t' to indicate the timer handles a SIGEV_THREAD.  */
      75  
      76  static inline timer_t
      77  kernel_timer_to_timerid (kernel_timer_t ktimerid)
      78  {
      79    return (timer_t) ((intptr_t) ktimerid);
      80  }
      81  
      82  static inline timer_t
      83  timer_to_timerid (struct timer *ptr)
      84  {
      85    return (timer_t) (INTPTR_MIN | (uintptr_t) ptr >> 1);
      86  }
      87  
      88  static inline bool
      89  timer_is_sigev_thread (timer_t timerid)
      90  {
      91    return (intptr_t) timerid < 0;
      92  }
      93  
      94  static inline struct timer *
      95  timerid_to_timer (timer_t timerid)
      96  {
      97    return (struct timer *)((uintptr_t) timerid << 1);
      98  }
      99  
     100  static inline kernel_timer_t
     101  timerid_to_kernel_timer (timer_t timerid)
     102  {
     103    if (timer_is_sigev_thread (timerid))
     104      return timerid_to_timer (timerid)->ktimerid;
     105    else
     106      return (kernel_timer_t) ((uintptr_t) timerid);
     107  }
     108  
     109  /* New targets use int instead of timer_t.  The difference only
     110     matters on 64-bit targets.  */
     111  #include <timer_t_was_int_compat.h>
     112  
     113  #if TIMER_T_WAS_INT_COMPAT
     114  # define OLD_TIMER_MAX 256
     115  extern timer_t __timer_compat_list[OLD_TIMER_MAX];
     116  #endif