(root)/
glibc-2.38/
rt/
timer_create.c
       1  /* Copyright (C) 2000-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 <errno.h>
      19  #include <signal.h>
      20  #include <pthread.h>
      21  #include <time.h>
      22  #include <unistd.h>
      23  
      24  #include "posix-timer.h"
      25  
      26  
      27  /* Create new per-process timer using CLOCK.  */
      28  int
      29  timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
      30  {
      31    int retval = -1;
      32    struct timer_node *newtimer = NULL;
      33    struct thread_node *thread = NULL;
      34  
      35    if (0
      36  #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
      37        || clock_id == CLOCK_PROCESS_CPUTIME_ID
      38  #endif
      39  #if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
      40        || clock_id == CLOCK_THREAD_CPUTIME_ID
      41  #endif
      42        )
      43      {
      44        /* We don't allow timers for CPU clocks.  At least not in the
      45  	 moment.  */
      46        __set_errno (ENOTSUP);
      47        return -1;
      48      }
      49  
      50    if (clock_id != CLOCK_REALTIME)
      51      {
      52        __set_errno (EINVAL);
      53        return -1;
      54      }
      55  
      56    pthread_once (&__timer_init_once_control, __timer_init_once);
      57  
      58    if (__timer_init_failed)
      59      {
      60        __set_errno (ENOMEM);
      61        return -1;
      62      }
      63  
      64    pthread_mutex_lock (&__timer_mutex);
      65  
      66    newtimer = __timer_alloc ();
      67    if (__glibc_unlikely (newtimer == NULL))
      68      {
      69        __set_errno (EAGAIN);
      70        goto unlock_bail;
      71      }
      72  
      73    if (evp != NULL)
      74      newtimer->event = *evp;
      75    else
      76      {
      77        newtimer->event.sigev_notify = SIGEV_SIGNAL;
      78        newtimer->event.sigev_signo = SIGALRM;
      79        newtimer->event.sigev_value.sival_ptr = newtimer;
      80        newtimer->event.sigev_notify_function = 0;
      81      }
      82  
      83    newtimer->event.sigev_notify_attributes = &newtimer->attr;
      84    newtimer->creator_pid = getpid ();
      85  
      86    switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
      87      {
      88      case SIGEV_NONE:
      89      case SIGEV_SIGNAL:
      90        /* We have a global thread for delivering timed signals.
      91  	 If it is not running, try to start it up.  */
      92        thread = &__timer_signal_thread_rclk;
      93        if (! thread->exists)
      94  	{
      95  	  if (__builtin_expect (__timer_thread_start (thread),
      96  				1) < 0)
      97  	    {
      98  	      __set_errno (EAGAIN);
      99  	      goto unlock_bail;
     100              }
     101          }
     102        break;
     103  
     104      case SIGEV_THREAD:
     105        /* Copy over thread attributes or set up default ones.  */
     106        if (evp->sigev_notify_attributes)
     107  	newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
     108        else
     109  	pthread_attr_init (&newtimer->attr);
     110  
     111        /* Ensure thread attributes call for detached thread.  */
     112        pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
     113  
     114        /* Try to find existing thread having the right attributes.  */
     115        thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
     116  
     117        /* If no existing thread has these attributes, try to allocate one.  */
     118        if (thread == NULL)
     119  	thread = __timer_thread_alloc (&newtimer->attr, clock_id);
     120  
     121        /* Out of luck; no threads are available.  */
     122        if (__glibc_unlikely (thread == NULL))
     123  	{
     124  	  __set_errno (EAGAIN);
     125  	  goto unlock_bail;
     126  	}
     127  
     128        /* If the thread is not running already, try to start it.  */
     129        if (! thread->exists
     130  	  && __builtin_expect (! __timer_thread_start (thread), 0))
     131  	{
     132  	  __set_errno (EAGAIN);
     133  	  goto unlock_bail;
     134  	}
     135        break;
     136  
     137      default:
     138        __set_errno (EINVAL);
     139        goto unlock_bail;
     140      }
     141  
     142    newtimer->clock = clock_id;
     143    newtimer->abstime = 0;
     144    newtimer->armed = 0;
     145    newtimer->thread = thread;
     146  
     147    *timerid = timer_ptr2id (newtimer);
     148    retval = 0;
     149  
     150    if (__builtin_expect (retval, 0) == -1)
     151      {
     152      unlock_bail:
     153        if (thread != NULL)
     154  	__timer_thread_dealloc (thread);
     155        if (newtimer != NULL)
     156  	{
     157  	  timer_delref (newtimer);
     158  	  __timer_dealloc (newtimer);
     159  	}
     160      }
     161  
     162    pthread_mutex_unlock (&__timer_mutex);
     163  
     164    return retval;
     165  }