(linenum→info "unix/slp.c:2238")

glibc/2.7/resolv/gai_misc.c

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