(root)/
glibc-2.38/
inet/
deadline.c
       1  /* Computing deadlines for timeouts.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <net-internal.h>
      20  
      21  #include <assert.h>
      22  #include <limits.h>
      23  #include <stdio.h>
      24  #include <stdint.h>
      25  #include <time.h>
      26  
      27  struct deadline_current_time
      28  __deadline_current_time (void)
      29  {
      30    struct deadline_current_time result;
      31    if (__clock_gettime64 (CLOCK_MONOTONIC, &result.current) != 0)
      32      __clock_gettime64 (CLOCK_REALTIME, &result.current);
      33    assert (result.current.tv_sec >= 0);
      34    return result;
      35  }
      36  
      37  /* A special deadline value for which __deadline_is_infinite is
      38     true.  */
      39  static inline struct deadline
      40  infinite_deadline (void)
      41  {
      42    return (struct deadline) { { -1, -1 } };
      43  }
      44  
      45  struct deadline
      46  __deadline_from_timeval (struct deadline_current_time current,
      47                           struct timeval tv)
      48  {
      49    assert (__is_timeval_valid_timeout (tv));
      50  
      51    /* Compute second-based deadline.  Perform the addition in
      52       uintmax_t, which is unsigned, to simply overflow detection.  */
      53    uintmax_t sec = current.current.tv_sec;
      54    sec += tv.tv_sec;
      55    if (sec < (uintmax_t) tv.tv_sec)
      56      return infinite_deadline ();
      57  
      58    /* Compute nanosecond deadline.  */
      59    int nsec = current.current.tv_nsec + tv.tv_usec * 1000;
      60    if (nsec >= 1000 * 1000 * 1000)
      61      {
      62        /* Carry nanosecond overflow to seconds.  */
      63        nsec -= 1000 * 1000 * 1000;
      64        if (sec + 1 < sec)
      65          return infinite_deadline ();
      66        ++sec;
      67      }
      68    /* This uses a GCC extension, otherwise these casts for detecting
      69       overflow would not be defined.  */
      70    if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec)
      71      return infinite_deadline ();
      72  
      73    return (struct deadline) { { sec, nsec } };
      74  }
      75  
      76  int
      77  __deadline_to_ms (struct deadline_current_time current,
      78                    struct deadline deadline)
      79  {
      80    if (__deadline_is_infinite (deadline))
      81      return INT_MAX;
      82  
      83    if (current.current.tv_sec > deadline.absolute.tv_sec
      84        || (current.current.tv_sec == deadline.absolute.tv_sec
      85            && current.current.tv_nsec >= deadline.absolute.tv_nsec))
      86      return 0;
      87    time_t sec = deadline.absolute.tv_sec - current.current.tv_sec;
      88    if (sec >= INT_MAX)
      89      /* This value will overflow below.  */
      90      return INT_MAX;
      91    int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec;
      92    if (nsec < 0)
      93      {
      94        /* Borrow from the seconds field.  */
      95        assert (sec > 0);
      96        --sec;
      97        nsec += 1000 * 1000 * 1000;
      98      }
      99  
     100    /* Prepare for rounding up to milliseconds.  */
     101    nsec += 999999;
     102    if (nsec > 1000 * 1000 * 1000)
     103      {
     104        assert (sec < INT_MAX);
     105        ++sec;
     106        nsec -= 1000 * 1000 * 1000;
     107      }
     108  
     109    unsigned int msec = nsec / (1000 * 1000);
     110    if (sec > INT_MAX / 1000)
     111      return INT_MAX;
     112    msec += sec * 1000;
     113    if (msec > INT_MAX)
     114      return INT_MAX;
     115    return msec;
     116  }