(root)/
glibc-2.38/
resolv/
gai_suspend.c
       1  /* Copyright (C) 2001-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
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the 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; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <netdb.h>
      20  #include <pthread.h>
      21  #include <stdlib.h>
      22  #include <sys/time.h>
      23  
      24  #include <gai_misc.h>
      25  
      26  int
      27  ___gai_suspend_time64 (const struct gaicb *const list[], int ent,
      28  		       const struct __timespec64 *timeout)
      29  {
      30    struct waitlist waitlist[ent];
      31    struct requestlist *requestlist[ent];
      32  #ifndef DONT_NEED_GAI_MISC_COND
      33    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      34  #endif
      35    int cnt;
      36    unsigned int cntr = 1;
      37    int none = 1;
      38    int result;
      39  
      40    /* Request the mutex.  */
      41    __pthread_mutex_lock (&__gai_requests_mutex);
      42  
      43    /* There is not yet a finished request.  Signal the request that
      44       we are working for it.  */
      45    for (cnt = 0; cnt < ent; ++cnt)
      46      if (list[cnt] != NULL && list[cnt]->__return == EAI_INPROGRESS)
      47        {
      48  	requestlist[cnt] = __gai_find_request (list[cnt]);
      49  
      50  	if (requestlist[cnt] != NULL)
      51  	  {
      52  #ifndef DONT_NEED_GAI_MISC_COND
      53  	    waitlist[cnt].cond = &cond;
      54  #endif
      55  	    waitlist[cnt].next = requestlist[cnt]->waiting;
      56  	    waitlist[cnt].counterp = &cntr;
      57  	    waitlist[cnt].sigevp = NULL;
      58  	    waitlist[cnt].caller_pid = 0;	/* Not needed.  */
      59  	    requestlist[cnt]->waiting = &waitlist[cnt];
      60  	    none = 0;
      61  	  }
      62        }
      63  
      64    struct __timespec64 ts;
      65    if (timeout != NULL)
      66      {
      67        __clock_gettime64 (CLOCK_MONOTONIC, &ts);
      68        ts.tv_sec += timeout->tv_sec;
      69        ts.tv_nsec += timeout->tv_nsec;
      70        if (ts.tv_nsec >= 1000000000)
      71  	{
      72  	  ts.tv_nsec -= 1000000000;
      73  	  ts.tv_sec++;
      74  	}
      75      }
      76  
      77    if (none)
      78      {
      79        if (cnt < ent)
      80  	/* There is an entry which is finished.  */
      81  	result = 0;
      82        else
      83  	result = EAI_ALLDONE;
      84      }
      85    else
      86      {
      87        /* There is no request done but some are still being worked on.  */
      88        int oldstate;
      89  
      90        /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
      91  	 points we must be careful.  We added entries to the waiting lists
      92  	 which we must remove.  So defer cancelation for now.  */
      93        __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
      94  
      95  #ifdef DONT_NEED_GAI_MISC_COND
      96        result = 0;
      97        GAI_MISC_WAIT (result, cntr, timeout == NULL ? NULL : &ts, 1);
      98  #else
      99        struct timespec ts32 = valid_timespec64_to_timespec (ts);
     100        result = pthread_cond_timedwait (&cond, &__gai_requests_mutex,
     101                                         timeout == NULL ? NULL : &ts32);
     102  #endif
     103  
     104        /* Now remove the entry in the waiting list for all requests
     105  	 which didn't terminate.  */
     106        for (cnt = 0; cnt < ent; ++cnt)
     107  	if (list[cnt] != NULL && list[cnt]->__return == EAI_INPROGRESS
     108  	    && requestlist[cnt] != NULL)
     109  	  {
     110  	    struct waitlist **listp = &requestlist[cnt]->waiting;
     111  
     112  	    /* There is the chance that we cannot find our entry anymore.
     113  	       This could happen if the request terminated and restarted
     114  	       again.  */
     115  	    while (*listp != NULL && *listp != &waitlist[cnt])
     116  	      listp = &(*listp)->next;
     117  
     118  	    if (*listp != NULL)
     119  	      *listp = (*listp)->next;
     120  	  }
     121  
     122        /* Now it's time to restore the cancelation state.  */
     123        __pthread_setcancelstate (oldstate, NULL);
     124  
     125  #ifndef DONT_NEED_GAI_MISC_COND
     126        /* Release the conditional variable.  */
     127        if (pthread_cond_destroy (&cond) != 0)
     128  	/* This must never happen.  */
     129  	abort ();
     130  #endif
     131  
     132        if (result != 0)
     133  	{
     134  	  /* An error occurred.  Possibly it's EINTR.  We have to translate
     135  	     the timeout error report of `pthread_cond_timedwait' to the
     136  	     form expected from `gai_suspend'.  */
     137  	  if (__glibc_likely (result == ETIMEDOUT))
     138  	    result = EAI_AGAIN;
     139  	  else if (result == EINTR)
     140  	    result = EAI_INTR;
     141  	  else
     142  	    result = EAI_SYSTEM;
     143  	}
     144      }
     145  
     146    /* Release the mutex.  */
     147    __pthread_mutex_unlock (&__gai_requests_mutex);
     148  
     149    return result;
     150  }
     151  
     152  #if __TIMESIZE == 64
     153  # if PTHREAD_IN_LIBC
     154  versioned_symbol (libc, ___gai_suspend_time64, gai_suspend, GLIBC_2_34);
     155  #  if OTHER_SHLIB_COMPAT (libanl, GLIBC_2_2_3, GLIBC_2_34)
     156  compat_symbol (libanl, ___gai_suspend_time64, gai_suspend, GLIBC_2_2_3);
     157  #  endif
     158  # else
     159  weak_alias (___gai_suspend_time64, gai_suspend)
     160  # endif /* PTHREAD_IN_LIBC */
     161  
     162  #else /* __TIMESIZE != 64 */
     163  # if PTHREAD_IN_LIBC
     164  libc_hidden_ver (___gai_suspend_time64, __gai_suspend_time64)
     165  versioned_symbol (libc, ___gai_suspend_time64, __gai_suspend_time64,
     166  		  GLIBC_2_34);
     167  # else /* !PTHREAD_IN_LIBC */
     168  # if IS_IN (libanl)
     169  hidden_ver (___gai_suspend_time64, __gai_suspend_time64)
     170  # endif
     171  #endif /* !PTHREAD_IN_LIBC */
     172  
     173  int
     174  ___gai_suspend (const struct gaicb *const list[], int ent,
     175  		const struct timespec *timeout)
     176  {
     177    struct __timespec64 ts64;
     178  
     179    if (timeout != NULL)
     180      ts64 = valid_timespec_to_timespec64 (*timeout);
     181  
     182    return __gai_suspend_time64 (list, ent, timeout != NULL ? &ts64 : NULL);
     183  }
     184  #if PTHREAD_IN_LIBC
     185  versioned_symbol (libc, ___gai_suspend, gai_suspend, GLIBC_2_34);
     186  # if OTHER_SHLIB_COMPAT (libanl, GLIBC_2_2_3, GLIBC_2_34)
     187  compat_symbol (libanl, ___gai_suspend, gai_suspend, GLIBC_2_2_3);
     188  # endif
     189  # else
     190  weak_alias (___gai_suspend, gai_suspend)
     191  # endif /* !PTHREAD_IN_LIBC */
     192  #endif /* __TIMESIZE != 64 */