Back to index

glibc  2.9
Defines | Functions | Variables
gai_misc.c File Reference
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
#include <gai_misc.h>

Go to the source code of this file.

Defines

#define gai_create_helper_thread   __gai_create_helper_thread
#define ENTRIES_PER_ROW   32
#define ROWS_STEP   8

Functions

int __gai_create_helper_thread (pthread_t *threadp, void *(*tf)(void *), void *arg)
static struct requestlistget_elem (void)
struct requestlist
*internal_function 
__gai_find_request (const struct gaicb *gaicbp)
int internal_function __gai_remove_request (struct gaicb *gaicbp)
static void * handle_requests (void *arg)
struct requestlist
*internal_function 
__gai_enqueue_request (struct gaicb *gaicbp)
static void * __attribute__ ((noreturn))
 libc_freeres_fn (free_res)

Variables

static struct requestlist ** pool
static size_t pool_max_size
static size_t pool_size
static struct requestlistfreelist
static struct requestlistrequests
static struct requestlistrequests_tail
static int nthreads
static int idle_thread_count
static struct gaiinit
pthread_mutex_t __gai_requests_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
pthread_cond_t __gai_new_request_notification = PTHREAD_COND_INITIALIZER

Define Documentation

#define ENTRIES_PER_ROW   32

Definition at line 61 of file gai_misc.c.

Definition at line 31 of file gai_misc.c.

#define ROWS_STEP   8

Definition at line 64 of file gai_misc.c.


Function Documentation

static void* __attribute__ ( (noreturn)  ) [static]

Definition at line 300 of file gai_misc.c.

{
  struct requestlist *runp = (struct requestlist *) arg;

  do
    {
      /* If runp is NULL, then we were created to service the work queue
        in general, not to handle any particular request. In that case we
        skip the "do work" stuff on the first pass, and go directly to the
        "get work off the work queue" part of this loop, which is near the
        end. */
      if (runp == NULL)
       pthread_mutex_lock (&__gai_requests_mutex);
      else
       {
         /* Make the request.  */
         struct gaicb *req = runp->gaicbp;
         struct requestlist *srchp;
         struct requestlist *lastp;

         req->__return = getaddrinfo (req->ar_name, req->ar_service,
                                   req->ar_request, &req->ar_result);

         /* Get the mutex.  */
         pthread_mutex_lock (&__gai_requests_mutex);

         /* Send the signal to notify about finished processing of the
            request.  */
         __gai_notify (runp);

         /* Now dequeue the current request.  */
         lastp = NULL;
         srchp = requests;
         while (srchp != runp)
           {
             lastp = srchp;
             srchp = srchp->next;
           }
         assert (runp->running == 1);

         if (requests_tail == runp)
           requests_tail = lastp;
         if (lastp == NULL)
           requests = requests->next;
         else
           lastp->next = runp->next;

         /* Free the old element.  */
         runp->next = freelist;
         freelist = runp;
       }

      runp = requests;
      while (runp != NULL && runp->running != 0)
       runp = runp->next;

      /* If the runlist is empty, then we sleep for a while, waiting for
        something to arrive in it. */
      if (runp == NULL && optim.gai_idle_time >= 0)
       {
         struct timeval now;
         struct timespec wakeup_time;

         ++idle_thread_count;
         gettimeofday (&now, NULL);
         wakeup_time.tv_sec = now.tv_sec + optim.gai_idle_time;
         wakeup_time.tv_nsec = now.tv_usec * 1000;
         if (wakeup_time.tv_nsec > 1000000000)
           {
             wakeup_time.tv_nsec -= 1000000000;
             ++wakeup_time.tv_sec;
           }
         pthread_cond_timedwait (&__gai_new_request_notification,
                              &__gai_requests_mutex, &wakeup_time);
         --idle_thread_count;
         runp = requests;
         while (runp != NULL && runp->running != 0)
           runp = runp->next;
       }

      if (runp == NULL)
       --nthreads;
      else
       {
         /* Mark the request as being worked on.  */
         assert (runp->running == 0);
         runp->running = 1;

         /* If we have a request to process, and there's still another in
            the run list, then we need to either wake up or create a new
            thread to service the request that is still in the run list. */
         if (requests != NULL)
           {
             /* There are at least two items in the work queue to work on.
               If there are other idle threads, then we should wake them
               up for these other work elements; otherwise, we should try
               to create a new thread. */
             if (idle_thread_count > 0)
              pthread_cond_signal (&__gai_new_request_notification);
             else if (nthreads < optim.gai_threads)
              {
                pthread_t thid;
                pthread_attr_t attr;

                /* Make sure the thread is created detached.  */
                pthread_attr_init (&attr);
                pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

                /* Now try to start a thread. If we fail, no big deal,
                   because we know that there is at least one thread (us)
                   that is working on lookup operations. */
                if (pthread_create (&thid, &attr, handle_requests, NULL)
                    == 0)
                  ++nthreads;
              }
           }
       }

      /* Release the mutex.  */
      pthread_mutex_unlock (&__gai_requests_mutex);
    }
  while (runp != NULL);

  pthread_exit (NULL);
}

Here is the call graph for this function:

int __gai_create_helper_thread ( pthread_t threadp,
void *(*)(void *)  tf,
void *  arg 
) [inline]

Definition at line 34 of file gai_misc.c.

{
  pthread_attr_t attr;

  /* Make sure the thread is created detached.  */
  pthread_attr_init (&attr);
  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

  int ret = pthread_create (threadp, &attr, tf, arg);

  (void) pthread_attr_destroy (&attr);
  return ret;
}

Here is the call graph for this function:

struct requestlist* internal_function __gai_enqueue_request ( struct gaicb *  gaicbp) [read]

Definition at line 217 of file gai_misc.c.

{
  struct requestlist *newp;
  struct requestlist *lastp;

  /* Get the mutex.  */
  pthread_mutex_lock (&__gai_requests_mutex);

  /* Get a new element for the waiting list.  */
  newp = get_elem ();
  if (newp == NULL)
    {
      pthread_mutex_unlock (&__gai_requests_mutex);
      __set_errno (EAGAIN);
      return NULL;
    }
  newp->running = 0;
  newp->gaicbp = gaicbp;
  newp->waiting = NULL;
  newp->next = NULL;

  lastp = requests_tail;
  if (requests_tail == NULL)
    requests = requests_tail = newp;
  else
    {
      requests_tail->next = newp;
      requests_tail = newp;
    }

  gaicbp->__return = EAI_INPROGRESS;

  /* See if we need to and are able to create a thread.  */
  if (nthreads < optim.gai_threads && idle_thread_count == 0)
    {
      pthread_t thid;

      newp->running = 1;

      /* Now try to start a thread.  */
      if (gai_create_helper_thread (&thid, handle_requests, newp) == 0)
       /* We managed to enqueue the request.  All errors which can
          happen now can be recognized by calls to `gai_error'.  */
       ++nthreads;
      else
       {
         if (nthreads == 0)
           {
             /* We cannot create a thread in the moment and there is
               also no thread running.  This is a problem.  `errno' is
               set to EAGAIN if this is only a temporary problem.  */
             assert (lastp->next == newp);
             lastp->next = NULL;
             requests_tail = lastp;

             newp->next = freelist;
             freelist = newp;

             newp = NULL;
           }
         else
           /* We are not handling the request after all.  */
           newp->running = 0;
       }
    }

  /* Enqueue the request in the request queue.  */
  if (newp != NULL)
    {
      /* If there is a thread waiting for work, then let it know that we
        have just given it something to do. */
      if (idle_thread_count > 0)
       pthread_cond_signal (&__gai_new_request_notification);
    }

  /* Release the mutex.  */
  pthread_mutex_unlock (&__gai_requests_mutex);

  return newp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct requestlist* internal_function __gai_find_request ( const struct gaicb *  gaicbp) [read]

Definition at line 157 of file gai_misc.c.

{
  struct requestlist *runp;

  runp = requests;
  while (runp != NULL)
    if (runp->gaicbp == gaicbp)
      return runp;
    else
      runp = runp->next;

  return NULL;
}

Here is the caller graph for this function:

int internal_function __gai_remove_request ( struct gaicb *  gaicbp)

Definition at line 174 of file gai_misc.c.

{
  struct requestlist *runp;
  struct requestlist *lastp;

  runp = requests;
  lastp = NULL;
  while (runp != NULL)
    if (runp->gaicbp == gaicbp)
      break;
    else
      {
       lastp = runp;
       runp = runp->next;
      }

  if (runp == NULL)
    /* Not known.  */
    return -1;
  if (runp->running != 0)
    /* Currently handled.  */
    return 1;

  /* Dequeue the request.  */
  if (lastp == NULL)
    requests = runp->next;
  else
    lastp->next = runp->next;
  if (runp == requests_tail)
    requests_tail = lastp;

  return 0;
}

Here is the caller graph for this function:

static struct requestlist* get_elem ( void  ) [static, read]

Definition at line 106 of file gai_misc.c.

{
  struct requestlist *result;

  if (freelist == NULL)
    {
      struct requestlist *new_row;
      int cnt;

      if (pool_size + 1 >= pool_max_size)
       {
         size_t new_max_size = pool_max_size + ROWS_STEP;
         struct requestlist **new_tab;

         new_tab = (struct requestlist **)
           realloc (pool, new_max_size * sizeof (struct requestlist *));

         if (new_tab == NULL)
           return NULL;

         pool_max_size = new_max_size;
         pool = new_tab;
       }

      /* Allocate the new row.  */
      cnt = pool_size == 0 ? optim.gai_num : ENTRIES_PER_ROW;
      new_row = (struct requestlist *) calloc (cnt,
                                          sizeof (struct requestlist));
      if (new_row == NULL)
       return NULL;

      pool[pool_size++] = new_row;

      /* Put all the new entries in the freelist.  */
      do
       {
         new_row->next = freelist;
         freelist = new_row++;
       }
      while (--cnt > 0);
    }

  result = freelist;
  freelist = freelist->next;

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void* handle_requests ( void *  arg) [static]

Here is the caller graph for this function:

libc_freeres_fn ( free_res  )

Definition at line 429 of file gai_misc.c.

{
  size_t row;

  for (row = 0; row < pool_max_size; ++row)
    free (pool[row]);

  free (pool);
}

Variable Documentation

Definition at line 101 of file gai_misc.c.

pthread_mutex_t __gai_requests_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP

Definition at line 96 of file gai_misc.c.

struct requestlist* freelist [static]

Definition at line 67 of file gai_misc.c.

struct gaiinit [static]
Initial value:
{
  20,  
  64,  
  0,
  0,
  0,
  0,
  1,
  0
}

Definition at line 82 of file gai_misc.c.

Definition at line 77 of file gai_misc.c.

int nthreads [static]

Definition at line 74 of file gai_misc.c.

struct requestlist** pool [static]

Definition at line 52 of file gai_misc.c.

Definition at line 55 of file gai_misc.c.

size_t pool_size [static]

Definition at line 56 of file gai_misc.c.

struct requestlist* requests [static]

Definition at line 70 of file gai_misc.c.

struct requestlist* requests_tail [static]

Definition at line 71 of file gai_misc.c.