Update.
[platform/upstream/glibc.git] / resolv / getaddrinfo_a.c
1 /* Copyright (C) 2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <netdb.h>
22 #include <pthread.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include "gai_misc.h"
27
28
29 /* We need this special structure to handle asynchronous I/O.  */
30 struct async_waitlist
31   {
32     int counter;
33     struct sigevent sigev;
34     struct waitlist list[0];
35   };
36
37
38 int
39 getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
40 {
41   struct sigevent defsigev;
42   struct requestlist *requests[ent];
43   int cnt;
44   volatile int total = 0;
45   int result = 0;
46
47   /* Check arguments.  */
48   if (mode != GAI_WAIT && mode != GAI_NOWAIT)
49     {
50       __set_errno (EINVAL);
51       return EAI_SYSTEM;
52     }
53
54   if (sig == NULL)
55     {
56       defsigev.sigev_notify = SIGEV_NONE;
57       sig = &defsigev;
58     }
59
60   /* Request the mutex.  */
61   pthread_mutex_lock (&__gai_requests_mutex);
62
63   /* Now we can enqueue all requests.  Since we already acquired the
64      mutex the enqueue function need not do this.  */
65   for (cnt = 0; cnt < ent; ++cnt)
66     if (list[cnt] != NULL)
67       {
68         requests[cnt] = __gai_enqueue_request (list[cnt]);
69
70         if (requests[cnt] != NULL)
71           /* Successfully enqueued.  */
72           ++total;
73         else
74           /* Signal that we've seen an error.  `errno' and the error code
75              of the gaicb will tell more.  */
76           result = EAI_SYSTEM;
77       }
78     else
79       requests[cnt] = NULL;
80
81   if (total == 0)
82     {
83       /* We don't have anything to do except signalling if we work
84          asynchronously.  */
85
86       /* Release the mutex.  We do this before raising a signal since the
87          signal handler might do a `siglongjmp' and then the mutex is
88          locked forever.  */
89       pthread_mutex_unlock (&__gai_requests_mutex);
90
91       if (mode == GAI_NOWAIT)
92         __gai_notify_only (sig,
93                            sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
94
95       return result;
96     }
97   else if (mode == GAI_WAIT)
98     {
99       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
100       struct waitlist waitlist[ent];
101       int oldstate;
102
103       total = 0;
104       for (cnt = 0; cnt < ent; ++cnt)
105         if (requests[cnt] != NULL)
106           {
107             waitlist[cnt].cond = &cond;
108             waitlist[cnt].next = requests[cnt]->waiting;
109             waitlist[cnt].counterp = &total;
110             waitlist[cnt].sigevp = NULL;
111             waitlist[cnt].caller_pid = 0;       /* Not needed.  */
112             requests[cnt]->waiting = &waitlist[cnt];
113             ++total;
114           }
115
116       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
117          points we must be careful.  We added entries to the waiting lists
118          which we must remove.  So defer cancelation for now.  */
119       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
120
121       while (total > 0)
122         pthread_cond_wait (&cond, &__gai_requests_mutex);
123
124       /* Now it's time to restore the cancelation state.  */
125       pthread_setcancelstate (oldstate, NULL);
126
127       /* Release the conditional variable.  */
128       if (pthread_cond_destroy (&cond) != 0)
129         /* This must never happen.  */
130         abort ();
131     }
132   else
133     {
134       struct async_waitlist *waitlist;
135
136       waitlist = (struct async_waitlist *)
137         malloc (sizeof (struct async_waitlist)
138                 + (ent * sizeof (struct waitlist)));
139
140       if (waitlist == NULL)
141         result = EAI_AGAIN;
142       else
143         {
144           pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
145           total = 0;
146
147           for (cnt = 0; cnt < ent; ++cnt)
148             if (requests[cnt] != NULL)
149               {
150                 waitlist->list[cnt].cond = NULL;
151                 waitlist->list[cnt].next = requests[cnt]->waiting;
152                 waitlist->list[cnt].counterp = &waitlist->counter;
153                 waitlist->list[cnt].sigevp = &waitlist->sigev;
154                 waitlist->list[cnt].caller_pid = caller_pid;
155                 requests[cnt]->waiting = &waitlist->list[cnt];
156                 ++total;
157               }
158
159           waitlist->counter = total;
160           waitlist->sigev = *sig;
161         }
162     }
163
164   /* Release the mutex.  */
165   pthread_mutex_unlock (&__gai_requests_mutex);
166
167   return result;
168 }