(root)/
glibc-2.38/
rt/
timer_settime.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 <pthread.h>
      20  #include <time.h>
      21  
      22  #include "posix-timer.h"
      23  
      24  
      25  /* Set timer TIMERID to VALUE, returning old value in OVLAUE.  */
      26  int
      27  timer_settime (timer_t timerid, int flags, const struct itimerspec *value,
      28  	       struct itimerspec *ovalue)
      29  {
      30    struct timer_node *timer;
      31    struct thread_node *thread = NULL;
      32    struct timespec now;
      33    int have_now = 0, need_wakeup = 0;
      34    int retval = -1;
      35  
      36    timer = timer_id2ptr (timerid);
      37    if (timer == NULL)
      38      {
      39        __set_errno (EINVAL);
      40        goto bail;
      41      }
      42  
      43    if (! valid_nanoseconds (value->it_interval.tv_nsec)
      44        || ! valid_nanoseconds (value->it_value.tv_nsec))
      45      {
      46        __set_errno (EINVAL);
      47        goto bail;
      48      }
      49  
      50    /* Will need to know current time since this is a relative timer;
      51       might as well make the system call outside of the lock now! */
      52  
      53    if ((flags & TIMER_ABSTIME) == 0)
      54      {
      55        __clock_gettime (timer->clock, &now);
      56        have_now = 1;
      57      }
      58  
      59    pthread_mutex_lock (&__timer_mutex);
      60    timer_addref (timer);
      61  
      62    /* One final check of timer validity; this one is possible only
      63       until we have the mutex, because it accesses the inuse flag. */
      64  
      65    if (! timer_valid(timer))
      66      {
      67        __set_errno (EINVAL);
      68        goto unlock_bail;
      69      }
      70  
      71    if (ovalue != NULL)
      72      {
      73        ovalue->it_interval = timer->value.it_interval;
      74  
      75        if (timer->armed)
      76  	{
      77  	  if (! have_now)
      78  	    {
      79  	      pthread_mutex_unlock (&__timer_mutex);
      80  	      __clock_gettime (timer->clock, &now);
      81  	      have_now = 1;
      82  	      pthread_mutex_lock (&__timer_mutex);
      83  	      timer_addref (timer);
      84  	    }
      85  
      86  	  timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
      87  	}
      88        else
      89  	{
      90  	  ovalue->it_value.tv_sec = 0;
      91  	  ovalue->it_value.tv_nsec = 0;
      92  	}
      93      }
      94  
      95    timer->value = *value;
      96  
      97    list_unlink_ip (&timer->links);
      98    timer->armed = 0;
      99  
     100    thread = timer->thread;
     101  
     102    /* A value of { 0, 0 } causes the timer to be stopped. */
     103    if (value->it_value.tv_sec != 0
     104        || __builtin_expect (value->it_value.tv_nsec != 0, 1))
     105      {
     106        if ((flags & TIMER_ABSTIME) != 0)
     107  	/* The user specified the expiration time.  */
     108  	timer->expirytime = value->it_value;
     109        else
     110  	timespec_add (&timer->expirytime, &now, &value->it_value);
     111  
     112        /* Only need to wake up the thread if timer is inserted
     113  	 at the head of the queue. */
     114        if (thread != NULL)
     115  	need_wakeup = __timer_thread_queue_timer (thread, timer);
     116        timer->armed = 1;
     117      }
     118  
     119    retval = 0;
     120  
     121  unlock_bail:
     122    timer_delref (timer);
     123    pthread_mutex_unlock (&__timer_mutex);
     124  
     125  bail:
     126    if (thread != NULL && need_wakeup)
     127      __timer_thread_wakeup (thread);
     128  
     129    return retval;
     130  }