Back to index

glibc  2.9
gai_suspend.c
Go to the documentation of this file.
00001 /* Copyright (C) 2001, 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <netdb.h>
00022 #include <pthread.h>
00023 #include <stdlib.h>
00024 #include <sys/time.h>
00025 
00026 #include <gai_misc.h>
00027 
00028 
00029 int
00030 gai_suspend (const struct gaicb *const list[], int ent,
00031             const struct timespec *timeout)
00032 {
00033   struct waitlist waitlist[ent];
00034   struct requestlist *requestlist[ent];
00035 #ifndef DONT_NEED_GAI_MISC_COND
00036   pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00037 #endif
00038   int cnt;
00039   int cntr = 1;
00040   int none = 1;
00041   int result;
00042 
00043   /* Request the mutex.  */
00044   pthread_mutex_lock (&__gai_requests_mutex);
00045 
00046   /* There is not yet a finished request.  Signal the request that
00047      we are working for it.  */
00048   for (cnt = 0; cnt < ent; ++cnt)
00049     if (list[cnt] != NULL && list[cnt]->__return == EAI_INPROGRESS)
00050       {
00051        requestlist[cnt] = __gai_find_request (list[cnt]);
00052 
00053        if (requestlist[cnt] != NULL)
00054          {
00055 #ifndef DONT_NEED_GAI_MISC_COND
00056            waitlist[cnt].cond = &cond;
00057 #endif
00058            waitlist[cnt].next = requestlist[cnt]->waiting;
00059            waitlist[cnt].counterp = &cntr;
00060            waitlist[cnt].sigevp = NULL;
00061            waitlist[cnt].caller_pid = 0;  /* Not needed.  */
00062            requestlist[cnt]->waiting = &waitlist[cnt];
00063            none = 0;
00064          }
00065       }
00066 
00067   if (none)
00068     {
00069       if (cnt < ent)
00070        /* There is an entry which is finished.  */
00071        result = 0;
00072       else
00073        result = EAI_ALLDONE;
00074     }
00075   else
00076     {
00077       /* There is no request done but some are still being worked on.  */
00078       int oldstate;
00079 
00080       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
00081         points we must be careful.  We added entries to the waiting lists
00082         which we must remove.  So defer cancelation for now.  */
00083       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
00084 
00085 #ifdef DONT_NEED_GAI_MISC_COND
00086       result = 0;
00087       GAI_MISC_WAIT (result, cntr, timeout, 1);
00088 #else
00089       if (timeout == NULL)
00090        result = pthread_cond_wait (&cond, &__gai_requests_mutex);
00091       else
00092        {
00093          /* We have to convert the relative timeout value into an
00094             absolute time value with pthread_cond_timedwait expects.  */
00095          struct timeval now;
00096          struct timespec abstime;
00097 
00098          __gettimeofday (&now, NULL);
00099          abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
00100          abstime.tv_sec = timeout->tv_sec + now.tv_sec;
00101          if (abstime.tv_nsec >= 1000000000)
00102            {
00103              abstime.tv_nsec -= 1000000000;
00104              abstime.tv_sec += 1;
00105            }
00106 
00107          result = pthread_cond_timedwait (&cond, &__gai_requests_mutex,
00108                                       &abstime);
00109        }
00110 #endif
00111 
00112       /* Now remove the entry in the waiting list for all requests
00113         which didn't terminate.  */
00114       for (cnt = 0; cnt < ent; ++cnt)
00115        if (list[cnt] != NULL && list[cnt]->__return == EAI_INPROGRESS
00116            && requestlist[cnt] != NULL)
00117          {
00118            struct waitlist **listp = &requestlist[cnt]->waiting;
00119 
00120            /* There is the chance that we cannot find our entry anymore.
00121               This could happen if the request terminated and restarted
00122               again.  */
00123            while (*listp != NULL && *listp != &waitlist[cnt])
00124              listp = &(*listp)->next;
00125 
00126            if (*listp != NULL)
00127              *listp = (*listp)->next;
00128          }
00129 
00130       /* Now it's time to restore the cancelation state.  */
00131       pthread_setcancelstate (oldstate, NULL);
00132 
00133 #ifndef DONT_NEED_GAI_MISC_COND
00134       /* Release the conditional variable.  */
00135       if (pthread_cond_destroy (&cond) != 0)
00136        /* This must never happen.  */
00137        abort ();
00138 #endif
00139 
00140       if (result != 0)
00141        {
00142          /* An error occurred.  Possibly it's EINTR.  We have to translate
00143             the timeout error report of `pthread_cond_timedwait' to the
00144             form expected from `gai_suspend'.  */
00145          if (__builtin_expect (result, ETIMEDOUT) == ETIMEDOUT)
00146            result = EAI_AGAIN;
00147          else if (result == EINTR)
00148            result = EAI_INTR;
00149          else
00150            result = EAI_SYSTEM;
00151        }
00152     }
00153 
00154   /* Release the mutex.  */
00155   pthread_mutex_unlock (&__gai_requests_mutex);
00156 
00157   return result;
00158 }