Back to index

glibc  2.9
getaddrinfo_a.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 <unistd.h>
00025 
00026 #include <gai_misc.h>
00027 
00028 
00029 /* We need this special structure to handle asynchronous I/O.  */
00030 struct async_waitlist
00031   {
00032     int counter;
00033     struct sigevent sigev;
00034     struct waitlist list[0];
00035   };
00036 
00037 
00038 int
00039 getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
00040 {
00041   struct sigevent defsigev;
00042   struct requestlist *requests[ent];
00043   int cnt;
00044   volatile int total = 0;
00045   int result = 0;
00046 
00047   /* Check arguments.  */
00048   if (mode != GAI_WAIT && mode != GAI_NOWAIT)
00049     {
00050       __set_errno (EINVAL);
00051       return EAI_SYSTEM;
00052     }
00053 
00054   if (sig == NULL)
00055     {
00056       defsigev.sigev_notify = SIGEV_NONE;
00057       sig = &defsigev;
00058     }
00059 
00060   /* Request the mutex.  */
00061   pthread_mutex_lock (&__gai_requests_mutex);
00062 
00063   /* Now we can enqueue all requests.  Since we already acquired the
00064      mutex the enqueue function need not do this.  */
00065   for (cnt = 0; cnt < ent; ++cnt)
00066     if (list[cnt] != NULL)
00067       {
00068        requests[cnt] = __gai_enqueue_request (list[cnt]);
00069 
00070        if (requests[cnt] != NULL)
00071          /* Successfully enqueued.  */
00072          ++total;
00073        else
00074          /* Signal that we've seen an error.  `errno' and the error code
00075             of the gaicb will tell more.  */
00076          result = EAI_SYSTEM;
00077       }
00078     else
00079       requests[cnt] = NULL;
00080 
00081   if (total == 0)
00082     {
00083       /* We don't have anything to do except signalling if we work
00084         asynchronously.  */
00085 
00086       /* Release the mutex.  We do this before raising a signal since the
00087         signal handler might do a `siglongjmp' and then the mutex is
00088         locked forever.  */
00089       pthread_mutex_unlock (&__gai_requests_mutex);
00090 
00091       if (mode == GAI_NOWAIT)
00092        __gai_notify_only (sig,
00093                         sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
00094 
00095       return result;
00096     }
00097   else if (mode == GAI_WAIT)
00098     {
00099 #ifndef DONT_NEED_GAI_MISC_COND
00100       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00101 #endif
00102       struct waitlist waitlist[ent];
00103       int oldstate;
00104 
00105       total = 0;
00106       for (cnt = 0; cnt < ent; ++cnt)
00107        if (requests[cnt] != NULL)
00108          {
00109 #ifndef DONT_NEED_GAI_MISC_COND
00110            waitlist[cnt].cond = &cond;
00111 #endif
00112            waitlist[cnt].next = requests[cnt]->waiting;
00113            waitlist[cnt].counterp = &total;
00114            waitlist[cnt].sigevp = NULL;
00115            waitlist[cnt].caller_pid = 0;  /* Not needed.  */
00116            requests[cnt]->waiting = &waitlist[cnt];
00117            ++total;
00118          }
00119 
00120       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
00121         points we must be careful.  We added entries to the waiting lists
00122         which we must remove.  So defer cancelation for now.  */
00123       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
00124 
00125       while (total > 0)
00126        {
00127 #ifdef DONT_NEED_GAI_MISC_COND
00128          int result;
00129          GAI_MISC_WAIT (result, total, NULL, 1);
00130 #else
00131          pthread_cond_wait (&cond, &__gai_requests_mutex);
00132 #endif
00133        }
00134 
00135       /* Now it's time to restore the cancelation state.  */
00136       pthread_setcancelstate (oldstate, NULL);
00137 
00138 #ifndef DONT_NEED_GAI_MISC_COND
00139       /* Release the conditional variable.  */
00140       if (pthread_cond_destroy (&cond) != 0)
00141        /* This must never happen.  */
00142        abort ();
00143 #endif
00144     }
00145   else
00146     {
00147       struct async_waitlist *waitlist;
00148 
00149       waitlist = (struct async_waitlist *)
00150        malloc (sizeof (struct async_waitlist)
00151               + (ent * sizeof (struct waitlist)));
00152 
00153       if (waitlist == NULL)
00154        result = EAI_AGAIN;
00155       else
00156        {
00157          pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
00158          total = 0;
00159 
00160          for (cnt = 0; cnt < ent; ++cnt)
00161            if (requests[cnt] != NULL)
00162              {
00163 #ifndef DONT_NEED_GAI_MISC_COND
00164               waitlist->list[cnt].cond = NULL;
00165 #endif
00166               waitlist->list[cnt].next = requests[cnt]->waiting;
00167               waitlist->list[cnt].counterp = &waitlist->counter;
00168               waitlist->list[cnt].sigevp = &waitlist->sigev;
00169               waitlist->list[cnt].caller_pid = caller_pid;
00170               requests[cnt]->waiting = &waitlist->list[cnt];
00171               ++total;
00172              }
00173 
00174          waitlist->counter = total;
00175          waitlist->sigev = *sig;
00176        }
00177     }
00178 
00179   /* Release the mutex.  */
00180   pthread_mutex_unlock (&__gai_requests_mutex);
00181 
00182   return result;
00183 }