Let tst-swscanf find its locale
[platform/upstream/glibc.git] / resolv / getaddrinfo_a.c
1 /* Copyright (C) 2001-2013 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 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    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <netdb.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include <gai_misc.h>
26
27
28 /* We need this special structure to handle asynchronous I/O.  */
29 struct async_waitlist
30   {
31     int counter;
32     struct sigevent sigev;
33     struct waitlist list[0];
34   };
35
36
37 int
38 getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
39 {
40   struct sigevent defsigev;
41   struct requestlist *requests[ent];
42   int cnt;
43   volatile int total = 0;
44   int result = 0;
45
46   /* Check arguments.  */
47   if (mode != GAI_WAIT && mode != GAI_NOWAIT)
48     {
49       __set_errno (EINVAL);
50       return EAI_SYSTEM;
51     }
52
53   if (sig == NULL)
54     {
55       defsigev.sigev_notify = SIGEV_NONE;
56       sig = &defsigev;
57     }
58
59   /* Request the mutex.  */
60   pthread_mutex_lock (&__gai_requests_mutex);
61
62   /* Now we can enqueue all requests.  Since we already acquired the
63      mutex the enqueue function need not do this.  */
64   for (cnt = 0; cnt < ent; ++cnt)
65     if (list[cnt] != NULL)
66       {
67         requests[cnt] = __gai_enqueue_request (list[cnt]);
68
69         if (requests[cnt] != NULL)
70           /* Successfully enqueued.  */
71           ++total;
72         else
73           /* Signal that we've seen an error.  `errno' and the error code
74              of the gaicb will tell more.  */
75           result = EAI_SYSTEM;
76       }
77     else
78       requests[cnt] = NULL;
79
80   if (total == 0)
81     {
82       /* We don't have anything to do except signalling if we work
83          asynchronously.  */
84
85       /* Release the mutex.  We do this before raising a signal since the
86          signal handler might do a `siglongjmp' and then the mutex is
87          locked forever.  */
88       pthread_mutex_unlock (&__gai_requests_mutex);
89
90       if (mode == GAI_NOWAIT)
91         __gai_notify_only (sig,
92                            sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
93
94       return result;
95     }
96   else if (mode == GAI_WAIT)
97     {
98 #ifndef DONT_NEED_GAI_MISC_COND
99       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
100 #endif
101       struct waitlist waitlist[ent];
102       int oldstate;
103
104       total = 0;
105       for (cnt = 0; cnt < ent; ++cnt)
106         if (requests[cnt] != NULL)
107           {
108 #ifndef DONT_NEED_GAI_MISC_COND
109             waitlist[cnt].cond = &cond;
110 #endif
111             waitlist[cnt].next = requests[cnt]->waiting;
112             waitlist[cnt].counterp = &total;
113             waitlist[cnt].sigevp = NULL;
114             waitlist[cnt].caller_pid = 0;       /* Not needed.  */
115             requests[cnt]->waiting = &waitlist[cnt];
116             ++total;
117           }
118
119       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
120          points we must be careful.  We added entries to the waiting lists
121          which we must remove.  So defer cancelation for now.  */
122       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
123
124       while (total > 0)
125         {
126 #ifdef DONT_NEED_GAI_MISC_COND
127           int not_used __attribute__ ((unused));
128           GAI_MISC_WAIT (not_used, total, NULL, 1);
129 #else
130           pthread_cond_wait (&cond, &__gai_requests_mutex);
131 #endif
132         }
133
134       /* Now it's time to restore the cancelation state.  */
135       pthread_setcancelstate (oldstate, NULL);
136
137 #ifndef DONT_NEED_GAI_MISC_COND
138       /* Release the conditional variable.  */
139       if (pthread_cond_destroy (&cond) != 0)
140         /* This must never happen.  */
141         abort ();
142 #endif
143     }
144   else
145     {
146       struct async_waitlist *waitlist;
147
148       waitlist = (struct async_waitlist *)
149         malloc (sizeof (struct async_waitlist)
150                 + (ent * sizeof (struct waitlist)));
151
152       if (waitlist == NULL)
153         result = EAI_AGAIN;
154       else
155         {
156           pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
157           total = 0;
158
159           for (cnt = 0; cnt < ent; ++cnt)
160             if (requests[cnt] != NULL)
161               {
162 #ifndef DONT_NEED_GAI_MISC_COND
163                 waitlist->list[cnt].cond = NULL;
164 #endif
165                 waitlist->list[cnt].next = requests[cnt]->waiting;
166                 waitlist->list[cnt].counterp = &waitlist->counter;
167                 waitlist->list[cnt].sigevp = &waitlist->sigev;
168                 waitlist->list[cnt].caller_pid = caller_pid;
169                 requests[cnt]->waiting = &waitlist->list[cnt];
170                 ++total;
171               }
172
173           waitlist->counter = total;
174           waitlist->sigev = *sig;
175         }
176     }
177
178   /* Release the mutex.  */
179   pthread_mutex_unlock (&__gai_requests_mutex);
180
181   return result;
182 }