Let tst-swscanf find its locale
[platform/upstream/glibc.git] / resolv / gai_misc.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 <assert.h>
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24
25 #include <gai_misc.h>
26
27
28
29 #ifndef gai_create_helper_thread
30 # define gai_create_helper_thread __gai_create_helper_thread
31
32 extern inline int
33 __gai_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
34                             void *arg)
35 {
36   pthread_attr_t attr;
37
38   /* Make sure the thread is created detached.  */
39   pthread_attr_init (&attr);
40   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
41
42   int ret = pthread_create (threadp, &attr, tf, arg);
43
44   (void) pthread_attr_destroy (&attr);
45   return ret;
46 }
47 #endif
48
49
50 /* Pool of request list entries.  */
51 static struct requestlist **pool;
52
53 /* Number of total and allocated pool entries.  */
54 static size_t pool_max_size;
55 static size_t pool_size;
56
57 /* We implement a two dimensional array but allocate each row separately.
58    The macro below determines how many entries should be used per row.
59    It should better be a power of two.  */
60 #define ENTRIES_PER_ROW 32
61
62 /* How many rows we allocate at once.  */
63 #define ROWS_STEP       8
64
65 /* List of available entries.  */
66 static struct requestlist *freelist;
67
68 /* Structure list of all currently processed requests.  */
69 static struct requestlist *requests;
70 static struct requestlist *requests_tail;
71
72 /* Number of threads currently running.  */
73 static int nthreads;
74
75 /* Number of threads waiting for work to arrive. */
76 static int idle_thread_count;
77
78
79 /* These are the values used for optimization.  We will probably
80    create a funcion to set these values.  */
81 static struct gaiinit optim =
82 {
83   20,   /* int gai_threads;     Maximal number of threads.  */
84   64,   /* int gai_num;         Number of expected simultanious requests. */
85   0,
86   0,
87   0,
88   0,
89   1,
90   0
91 };
92
93
94 /* Since the list is global we need a mutex protecting it.  */
95 pthread_mutex_t __gai_requests_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
96
97 /* When you add a request to the list and there are idle threads present,
98    you signal this condition variable. When a thread finishes work, it waits
99    on this condition variable for a time before it actually exits. */
100 pthread_cond_t __gai_new_request_notification = PTHREAD_COND_INITIALIZER;
101
102
103 /* Functions to handle request list pool.  */
104 static struct requestlist *
105 get_elem (void)
106 {
107   struct requestlist *result;
108
109   if (freelist == NULL)
110     {
111       struct requestlist *new_row;
112       int cnt;
113
114       if (pool_size + 1 >= pool_max_size)
115         {
116           size_t new_max_size = pool_max_size + ROWS_STEP;
117           struct requestlist **new_tab;
118
119           new_tab = (struct requestlist **)
120             realloc (pool, new_max_size * sizeof (struct requestlist *));
121
122           if (new_tab == NULL)
123             return NULL;
124
125           pool_max_size = new_max_size;
126           pool = new_tab;
127         }
128
129       /* Allocate the new row.  */
130       cnt = pool_size == 0 ? optim.gai_num : ENTRIES_PER_ROW;
131       new_row = (struct requestlist *) calloc (cnt,
132                                                sizeof (struct requestlist));
133       if (new_row == NULL)
134         return NULL;
135
136       pool[pool_size++] = new_row;
137
138       /* Put all the new entries in the freelist.  */
139       do
140         {
141           new_row->next = freelist;
142           freelist = new_row++;
143         }
144       while (--cnt > 0);
145     }
146
147   result = freelist;
148   freelist = freelist->next;
149
150   return result;
151 }
152
153
154 struct requestlist *
155 internal_function
156 __gai_find_request (const struct gaicb *gaicbp)
157 {
158   struct requestlist *runp;
159
160   runp = requests;
161   while (runp != NULL)
162     if (runp->gaicbp == gaicbp)
163       return runp;
164     else
165       runp = runp->next;
166
167   return NULL;
168 }
169
170
171 int
172 internal_function
173 __gai_remove_request (struct gaicb *gaicbp)
174 {
175   struct requestlist *runp;
176   struct requestlist *lastp;
177
178   runp = requests;
179   lastp = NULL;
180   while (runp != NULL)
181     if (runp->gaicbp == gaicbp)
182       break;
183     else
184       {
185         lastp = runp;
186         runp = runp->next;
187       }
188
189   if (runp == NULL)
190     /* Not known.  */
191     return -1;
192   if (runp->running != 0)
193     /* Currently handled.  */
194     return 1;
195
196   /* Dequeue the request.  */
197   if (lastp == NULL)
198     requests = runp->next;
199   else
200     lastp->next = runp->next;
201   if (runp == requests_tail)
202     requests_tail = lastp;
203
204   return 0;
205 }
206
207
208 /* The thread handler.  */
209 static void *handle_requests (void *arg);
210
211
212 /* The main function of the async I/O handling.  It enqueues requests
213    and if necessary starts and handles threads.  */
214 struct requestlist *
215 internal_function
216 __gai_enqueue_request (struct gaicb *gaicbp)
217 {
218   struct requestlist *newp;
219   struct requestlist *lastp;
220
221   /* Get the mutex.  */
222   pthread_mutex_lock (&__gai_requests_mutex);
223
224   /* Get a new element for the waiting list.  */
225   newp = get_elem ();
226   if (newp == NULL)
227     {
228       pthread_mutex_unlock (&__gai_requests_mutex);
229       __set_errno (EAGAIN);
230       return NULL;
231     }
232   newp->running = 0;
233   newp->gaicbp = gaicbp;
234   newp->waiting = NULL;
235   newp->next = NULL;
236
237   lastp = requests_tail;
238   if (requests_tail == NULL)
239     requests = requests_tail = newp;
240   else
241     {
242       requests_tail->next = newp;
243       requests_tail = newp;
244     }
245
246   gaicbp->__return = EAI_INPROGRESS;
247
248   /* See if we need to and are able to create a thread.  */
249   if (nthreads < optim.gai_threads && idle_thread_count == 0)
250     {
251       pthread_t thid;
252
253       newp->running = 1;
254
255       /* Now try to start a thread.  */
256       if (gai_create_helper_thread (&thid, handle_requests, newp) == 0)
257         /* We managed to enqueue the request.  All errors which can
258            happen now can be recognized by calls to `gai_error'.  */
259         ++nthreads;
260       else
261         {
262           if (nthreads == 0)
263             {
264               /* We cannot create a thread in the moment and there is
265                  also no thread running.  This is a problem.  `errno' is
266                  set to EAGAIN if this is only a temporary problem.  */
267               assert (lastp->next == newp);
268               lastp->next = NULL;
269               requests_tail = lastp;
270
271               newp->next = freelist;
272               freelist = newp;
273
274               newp = NULL;
275             }
276           else
277             /* We are not handling the request after all.  */
278             newp->running = 0;
279         }
280     }
281
282   /* Enqueue the request in the request queue.  */
283   if (newp != NULL)
284     {
285       /* If there is a thread waiting for work, then let it know that we
286          have just given it something to do. */
287       if (idle_thread_count > 0)
288         pthread_cond_signal (&__gai_new_request_notification);
289     }
290
291   /* Release the mutex.  */
292   pthread_mutex_unlock (&__gai_requests_mutex);
293
294   return newp;
295 }
296
297
298 static void *
299 __attribute__ ((noreturn))
300 handle_requests (void *arg)
301 {
302   struct requestlist *runp = (struct requestlist *) arg;
303
304   do
305     {
306       /* If runp is NULL, then we were created to service the work queue
307          in general, not to handle any particular request. In that case we
308          skip the "do work" stuff on the first pass, and go directly to the
309          "get work off the work queue" part of this loop, which is near the
310          end. */
311       if (runp == NULL)
312         pthread_mutex_lock (&__gai_requests_mutex);
313       else
314         {
315           /* Make the request.  */
316           struct gaicb *req = runp->gaicbp;
317           struct requestlist *srchp;
318           struct requestlist *lastp;
319
320           req->__return = getaddrinfo (req->ar_name, req->ar_service,
321                                        req->ar_request, &req->ar_result);
322
323           /* Get the mutex.  */
324           pthread_mutex_lock (&__gai_requests_mutex);
325
326           /* Send the signal to notify about finished processing of the
327              request.  */
328           __gai_notify (runp);
329
330           /* Now dequeue the current request.  */
331           lastp = NULL;
332           srchp = requests;
333           while (srchp != runp)
334             {
335               lastp = srchp;
336               srchp = srchp->next;
337             }
338           assert (runp->running == 1);
339
340           if (requests_tail == runp)
341             requests_tail = lastp;
342           if (lastp == NULL)
343             requests = requests->next;
344           else
345             lastp->next = runp->next;
346
347           /* Free the old element.  */
348           runp->next = freelist;
349           freelist = runp;
350         }
351
352       runp = requests;
353       while (runp != NULL && runp->running != 0)
354         runp = runp->next;
355
356       /* If the runlist is empty, then we sleep for a while, waiting for
357          something to arrive in it. */
358       if (runp == NULL && optim.gai_idle_time >= 0)
359         {
360           struct timeval now;
361           struct timespec wakeup_time;
362
363           ++idle_thread_count;
364           gettimeofday (&now, NULL);
365           wakeup_time.tv_sec = now.tv_sec + optim.gai_idle_time;
366           wakeup_time.tv_nsec = now.tv_usec * 1000;
367           if (wakeup_time.tv_nsec >= 1000000000)
368             {
369               wakeup_time.tv_nsec -= 1000000000;
370               ++wakeup_time.tv_sec;
371             }
372           pthread_cond_timedwait (&__gai_new_request_notification,
373                                   &__gai_requests_mutex, &wakeup_time);
374           --idle_thread_count;
375           runp = requests;
376           while (runp != NULL && runp->running != 0)
377             runp = runp->next;
378         }
379
380       if (runp == NULL)
381         --nthreads;
382       else
383         {
384           /* Mark the request as being worked on.  */
385           assert (runp->running == 0);
386           runp->running = 1;
387
388           /* If we have a request to process, and there's still another in
389              the run list, then we need to either wake up or create a new
390              thread to service the request that is still in the run list. */
391           if (requests != NULL)
392             {
393               /* There are at least two items in the work queue to work on.
394                  If there are other idle threads, then we should wake them
395                  up for these other work elements; otherwise, we should try
396                  to create a new thread. */
397               if (idle_thread_count > 0)
398                 pthread_cond_signal (&__gai_new_request_notification);
399               else if (nthreads < optim.gai_threads)
400                 {
401                   pthread_t thid;
402                   pthread_attr_t attr;
403
404                   /* Make sure the thread is created detached.  */
405                   pthread_attr_init (&attr);
406                   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
407
408                   /* Now try to start a thread. If we fail, no big deal,
409                      because we know that there is at least one thread (us)
410                      that is working on lookup operations. */
411                   if (pthread_create (&thid, &attr, handle_requests, NULL)
412                       == 0)
413                     ++nthreads;
414                 }
415             }
416         }
417
418       /* Release the mutex.  */
419       pthread_mutex_unlock (&__gai_requests_mutex);
420     }
421   while (runp != NULL);
422
423   pthread_exit (NULL);
424 }
425
426
427 /* Free allocated resources.  */
428 libc_freeres_fn (free_res)
429 {
430   size_t row;
431
432   for (row = 0; row < pool_max_size; ++row)
433     free (pool[row]);
434
435   free (pool);
436 }