Diff for /embedaddon/quagga/lib/thread.c between versions 1.1 and 1.1.1.4

version 1.1, 2012/02/21 17:26:12 version 1.1.1.4, 2016/11/02 10:09:11
Line 27 Line 27
 #include "memory.h"  #include "memory.h"
 #include "log.h"  #include "log.h"
 #include "hash.h"  #include "hash.h"
   #include "pqueue.h"
 #include "command.h"  #include "command.h"
 #include "sigevent.h"  #include "sigevent.h"
 #if defined HAVE_SNMP && defined SNMP_AGENTX
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 #include <net-snmp/agent/net-snmp-agent-includes.h>
 #include <net-snmp/agent/snmp_vars.h>
 
 extern int agentx_enabled;
 #endif
 
 #if defined(__APPLE__)
 #include <mach/mach.h>
 #include <mach/mach_time.h>
 #endif
 
 
 /* Recent absolute time of day */  /* Recent absolute time of day */
 struct timeval recent_time;  struct timeval recent_time;
 static struct timeval last_recent_time;  static struct timeval last_recent_time;
Line 38  static struct timeval relative_time; Line 54  static struct timeval relative_time;
 static struct timeval relative_time_base;  static struct timeval relative_time_base;
 /* init flag */  /* init flag */
 static unsigned short timers_inited;  static unsigned short timers_inited;
 static struct hash *cpu_record = NULL;  static struct hash *cpu_record = NULL;
 /* Struct timeval's tv_usec one second value.  */  /* Struct timeval's tv_usec one second value.  */
 #define TIMER_SECOND_MICRO 1000000L  #define TIMER_SECOND_MICRO 1000000L
   
Line 86  timeval_cmp (struct timeval a, struct timeval b) Line 102  timeval_cmp (struct timeval a, struct timeval b)
           ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);            ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
 }  }
   
static unsigned longunsigned long
 timeval_elapsed (struct timeval a, struct timeval b)  timeval_elapsed (struct timeval a, struct timeval b)
 {  {
   return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)    return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
           + (a.tv_usec - b.tv_usec));            + (a.tv_usec - b.tv_usec));
 }  }
#ifndef HAVE_CLOCK_MONOTONIC#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
 static void  static void
 quagga_gettimeofday_relative_adjust (void)  quagga_gettimeofday_relative_adjust (void)
 {  {
Line 112  quagga_gettimeofday_relative_adjust (void) Line 128  quagga_gettimeofday_relative_adjust (void)
     }      }
   last_recent_time = recent_time;    last_recent_time = recent_time;
 }  }
#endif /* !HAVE_CLOCK_MONOTONIC */#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
   
 /* gettimeofday wrapper, to keep recent_time updated */  /* gettimeofday wrapper, to keep recent_time updated */
 static int  static int
Line 152  quagga_get_relative (struct timeval *tv) Line 168  quagga_get_relative (struct timeval *tv)
         relative_time.tv_usec = tp.tv_nsec / 1000;          relative_time.tv_usec = tp.tv_nsec / 1000;
       }        }
   }    }
#else /* !HAVE_CLOCK_MONOTONIC */#elif defined(__APPLE__)
   {
     uint64_t ticks;
     uint64_t useconds;
     static mach_timebase_info_data_t timebase_info;
 
     ticks = mach_absolute_time();
     if (timebase_info.denom == 0)
       mach_timebase_info(&timebase_info);
 
     useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
     relative_time.tv_sec = useconds / 1000000;
     relative_time.tv_usec = useconds % 1000000;
 
     return 0;
   }
 #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
   if (!(ret = quagga_gettimeofday (&recent_time)))    if (!(ret = quagga_gettimeofday (&recent_time)))
     quagga_gettimeofday_relative_adjust();      quagga_gettimeofday_relative_adjust();
 #endif /* HAVE_CLOCK_MONOTONIC */  #endif /* HAVE_CLOCK_MONOTONIC */
Line 215  recent_relative_time (void) Line 247  recent_relative_time (void)
 {  {
   return relative_time;    return relative_time;
 }  }
 static unsigned int  static unsigned int
 cpu_record_hash_key (struct cpu_thread_history *a)  cpu_record_hash_key (struct cpu_thread_history *a)
 {  {
Line 235  cpu_record_hash_alloc (struct cpu_thread_history *a) Line 267  cpu_record_hash_alloc (struct cpu_thread_history *a)
   struct cpu_thread_history *new;    struct cpu_thread_history *new;
   new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));    new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
   new->func = a->func;    new->func = a->func;
  new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);  new->funcname = a->funcname;
   return new;    return new;
 }  }
   
Line 244  cpu_record_hash_free (void *a) Line 276  cpu_record_hash_free (void *a)
 {  {
   struct cpu_thread_history *hist = a;    struct cpu_thread_history *hist = a;
     
   XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname);  
   XFREE (MTYPE_THREAD_STATS, hist);    XFREE (MTYPE_THREAD_STATS, hist);
 }  }
   
static inline void static void 
 vty_out_cpu_thread_history(struct vty* vty,  vty_out_cpu_thread_history(struct vty* vty,
                            struct cpu_thread_history *a)                             struct cpu_thread_history *a)
 {  {
Line 303  cpu_record_print(struct vty *vty, thread_type filter) Line 334  cpu_record_print(struct vty *vty, thread_type filter)
   void *args[3] = {&tmp, vty, &filter};    void *args[3] = {&tmp, vty, &filter};
   
   memset(&tmp, 0, sizeof tmp);    memset(&tmp, 0, sizeof tmp);
  tmp.funcname = (char *)"TOTAL";  tmp.funcname = "TOTAL";
   tmp.types = filter;    tmp.types = filter;
   
 #ifdef HAVE_RUSAGE  #ifdef HAVE_RUSAGE
Line 465  DEFUN(clear_thread_cpu, Line 496  DEFUN(clear_thread_cpu,
   cpu_record_clear (filter);    cpu_record_clear (filter);
   return CMD_SUCCESS;    return CMD_SUCCESS;
 }  }
/* List allocation and head/tail print out. */static int
static voidthread_timer_cmp(void *a, void *b)
thread_list_debug (struct thread_list *list) 
 {  {
  printf ("count [%d] head [%p] tail [%p]\n",  struct thread *thread_a = a;
          list->count, list->head, list->tail);  struct thread *thread_b = b;
 
   long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
 
   if (cmp < 0)
     return -1;
   if (cmp > 0)
     return 1;
   return 0;
 }  }
   
/* Debug print for thread_master. */static void
static void  __attribute__ ((unused))thread_timer_update(void *node, int actual_position)
thread_master_debug (struct thread_master *m) 
 {  {
  printf ("-----------\n");  struct thread *thread = node;
  printf ("readlist  : ");
  thread_list_debug (&m->read);  thread->index = actual_position;
  printf ("writelist : "); 
  thread_list_debug (&m->write); 
  printf ("timerlist : "); 
  thread_list_debug (&m->timer); 
  printf ("eventlist : "); 
  thread_list_debug (&m->event); 
  printf ("unuselist : "); 
  thread_list_debug (&m->unuse); 
  printf ("bgndlist : "); 
  thread_list_debug (&m->background); 
  printf ("total alloc: [%ld]\n", m->alloc); 
  printf ("-----------\n"); 
 }  }
 /* Allocate new thread master.  */  /* Allocate new thread master.  */
 struct thread_master *  struct thread_master *
 thread_master_create ()  thread_master_create ()
 {  {
     struct thread_master *rv;
   
   if (cpu_record == NULL)     if (cpu_record == NULL) 
     cpu_record       cpu_record 
      = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,       = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
                          (int (*) (const void *, const void *))cpu_record_hash_cmp);                     (int (*) (const void *, const void *))cpu_record_hash_cmp);
    
  return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,  rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
                                           sizeof (struct thread_master));
   /* Initialize the timer queues */
   rv->timer = pqueue_create();
   rv->background = pqueue_create();
   rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
   rv->timer->update = rv->background->update = thread_timer_update;
 
   return rv;
 }  }
   
 /* Add a new thread to the list.  */  /* Add a new thread to the list.  */
Line 522  thread_list_add (struct thread_list *list, struct thre Line 556  thread_list_add (struct thread_list *list, struct thre
   list->count++;    list->count++;
 }  }
   
 /* Add a new thread just before the point.  */  
 static void  
 thread_list_add_before (struct thread_list *list,   
                         struct thread *point,   
                         struct thread *thread)  
 {  
   thread->next = point;  
   thread->prev = point->prev;  
   if (point->prev)  
     point->prev->next = thread;  
   else  
     list->head = thread;  
   point->prev = thread;  
   list->count++;  
 }  
   
 /* Delete a thread from the list. */  /* Delete a thread from the list. */
 static struct thread *  static struct thread *
 thread_list_delete (struct thread_list *list, struct thread *thread)  thread_list_delete (struct thread_list *list, struct thread *thread)
Line 564  thread_add_unuse (struct thread_master *m, struct thre Line 582  thread_add_unuse (struct thread_master *m, struct thre
   assert (thread->prev == NULL);    assert (thread->prev == NULL);
   assert (thread->type == THREAD_UNUSED);    assert (thread->type == THREAD_UNUSED);
   thread_list_add (&m->unuse, thread);    thread_list_add (&m->unuse, thread);
   /* XXX: Should we deallocate funcname here? */  
 }  }
   
 /* Free all unused thread. */  /* Free all unused thread. */
Line 577  thread_list_free (struct thread_master *m, struct thre Line 594  thread_list_free (struct thread_master *m, struct thre
   for (t = list->head; t; t = next)    for (t = list->head; t; t = next)
     {      {
       next = t->next;        next = t->next;
       if (t->funcname)  
         XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);  
       XFREE (MTYPE_THREAD, t);        XFREE (MTYPE_THREAD, t);
       list->count--;        list->count--;
       m->alloc--;        m->alloc--;
     }      }
 }  }
   
   static void
   thread_queue_free (struct thread_master *m, struct pqueue *queue)
   {
     int i;
   
     for (i = 0; i < queue->size; i++)
       XFREE(MTYPE_THREAD, queue->array[i]);
   
     m->alloc -= queue->size;
     pqueue_delete(queue);
   }
   
 /* Stop thread scheduler. */  /* Stop thread scheduler. */
 void  void
 thread_master_free (struct thread_master *m)  thread_master_free (struct thread_master *m)
 {  {
   thread_list_free (m, &m->read);    thread_list_free (m, &m->read);
   thread_list_free (m, &m->write);    thread_list_free (m, &m->write);
  thread_list_free (m, &m->timer);  thread_queue_free (m, m->timer);
   thread_list_free (m, &m->event);    thread_list_free (m, &m->event);
   thread_list_free (m, &m->ready);    thread_list_free (m, &m->ready);
   thread_list_free (m, &m->unuse);    thread_list_free (m, &m->unuse);
  thread_list_free (m, &m->background);  thread_queue_free (m, m->background);
       
   XFREE (MTYPE_THREAD_MASTER, m);    XFREE (MTYPE_THREAD_MASTER, m);
   
Line 608  thread_master_free (struct thread_master *m) Line 635  thread_master_free (struct thread_master *m)
 }  }
   
 /* Thread list is empty or not.  */  /* Thread list is empty or not.  */
static inline intstatic int
 thread_empty (struct thread_list *list)  thread_empty (struct thread_list *list)
 {  {
   return  list->head ? 0 : 1;    return  list->head ? 0 : 1;
Line 635  thread_timer_remain_second (struct thread *thread) Line 662  thread_timer_remain_second (struct thread *thread)
     return 0;      return 0;
 }  }
   
/* Trim blankspace and "()"s */struct timeval
static char *thread_timer_remain(struct thread *thread)
strip_funcname (const char *funcname)  
 {  {
  char buff[100];  quagga_get_relative(NULL);
  char tmp, *ret, *e, *b = buff; 
   
  strncpy(buff, funcname, sizeof(buff));  return timeval_subtract(thread->u.sands, relative_time);
  buff[ sizeof(buff) -1] = '\0'; 
  e = buff +strlen(buff) -1; 
 
  /* Wont work for funcname ==  "Word (explanation)"  */ 
 
  while (*b == ' ' || *b == '(') 
    ++b; 
  while (*e == ' ' || *e == ')') 
    --e; 
  e++; 
 
  tmp = *e; 
  *e = '\0'; 
  ret  = XSTRDUP (MTYPE_THREAD_FUNCNAME, b); 
  *e = tmp; 
 
  return ret; 
 }  }
   
   #define debugargdef  const char *funcname, const char *schedfrom, int fromln
   #define debugargpass funcname, schedfrom, fromln
   
 /* Get new thread.  */  /* Get new thread.  */
 static struct thread *  static struct thread *
 thread_get (struct thread_master *m, u_char type,  thread_get (struct thread_master *m, u_char type,
            int (*func) (struct thread *), void *arg, const char* funcname)            int (*func) (struct thread *), void *arg, debugargdef)
 {  {
  struct thread *thread;  struct thread *thread = thread_trim_head (&m->unuse);
   
  if (!thread_empty (&m->unuse))  if (! thread)
     {      {
       thread = thread_trim_head (&m->unuse);  
       if (thread->funcname)  
         XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);  
     }  
   else  
     {  
       thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));        thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
       m->alloc++;        m->alloc++;
     }      }
Line 685  thread_get (struct thread_master *m, u_char type, Line 690  thread_get (struct thread_master *m, u_char type,
   thread->master = m;    thread->master = m;
   thread->func = func;    thread->func = func;
   thread->arg = arg;    thread->arg = arg;
    thread->index = -1;
  thread->funcname = strip_funcname(funcname); 
   
     thread->funcname = funcname;
     thread->schedfrom = schedfrom;
     thread->schedfrom_line = fromln;
   
   return thread;    return thread;
 }  }
   
 /* Add new read thread. */  /* Add new read thread. */
 struct thread *  struct thread *
 funcname_thread_add_read (struct thread_master *m,   funcname_thread_add_read (struct thread_master *m, 
                 int (*func) (struct thread *), void *arg, int fd, const char* funcname)                 int (*func) (struct thread *), void *arg, int fd,
                  debugargdef)
 {  {
   struct thread *thread;    struct thread *thread;
   
Line 706  funcname_thread_add_read (struct thread_master *m,  Line 715  funcname_thread_add_read (struct thread_master *m, 
       return NULL;        return NULL;
     }      }
   
  thread = thread_get (m, THREAD_READ, func, arg, funcname);  thread = thread_get (m, THREAD_READ, func, arg, debugargpass);
   FD_SET (fd, &m->readfd);    FD_SET (fd, &m->readfd);
   thread->u.fd = fd;    thread->u.fd = fd;
   thread_list_add (&m->read, thread);    thread_list_add (&m->read, thread);
Line 717  funcname_thread_add_read (struct thread_master *m,  Line 726  funcname_thread_add_read (struct thread_master *m, 
 /* Add new write thread. */  /* Add new write thread. */
 struct thread *  struct thread *
 funcname_thread_add_write (struct thread_master *m,  funcname_thread_add_write (struct thread_master *m,
                 int (*func) (struct thread *), void *arg, int fd, const char* funcname)                 int (*func) (struct thread *), void *arg, int fd,
                  debugargdef)
 {  {
   struct thread *thread;    struct thread *thread;
   
Line 729  funcname_thread_add_write (struct thread_master *m, Line 739  funcname_thread_add_write (struct thread_master *m,
       return NULL;        return NULL;
     }      }
   
  thread = thread_get (m, THREAD_WRITE, func, arg, funcname);  thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass);
   FD_SET (fd, &m->writefd);    FD_SET (fd, &m->writefd);
   thread->u.fd = fd;    thread->u.fd = fd;
   thread_list_add (&m->write, thread);    thread_list_add (&m->write, thread);
Line 742  funcname_thread_add_timer_timeval (struct thread_maste Line 752  funcname_thread_add_timer_timeval (struct thread_maste
                                    int (*func) (struct thread *),                                      int (*func) (struct thread *), 
                                   int type,                                    int type,
                                   void *arg,                                     void *arg, 
                                  struct timeval *time_relative,                                   struct timeval *time_relative,
                                  const char* funcname)                                  debugargdef)
 {  {
   struct thread *thread;    struct thread *thread;
  struct thread_list *list;  struct pqueue *queue;
   struct timeval alarm_time;    struct timeval alarm_time;
   struct thread *tt;  
   
   assert (m != NULL);    assert (m != NULL);
   
   assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);    assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
   assert (time_relative);    assert (time_relative);
       
  list = ((type == THREAD_TIMER) ? &m->timer : &m->background);  queue = ((type == THREAD_TIMER) ? m->timer : m->background);
  thread = thread_get (m, type, func, arg, funcname);  thread = thread_get (m, type, func, arg, debugargpass);
   
   /* Do we need jitter here? */    /* Do we need jitter here? */
   quagga_get_relative (NULL);    quagga_get_relative (NULL);
Line 764  funcname_thread_add_timer_timeval (struct thread_maste Line 773  funcname_thread_add_timer_timeval (struct thread_maste
   alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;    alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
   thread->u.sands = timeval_adjust(alarm_time);    thread->u.sands = timeval_adjust(alarm_time);
   
  /* Sort by timeval. */  pqueue_enqueue(thread, queue);
  for (tt = list->head; tt; tt = tt->next) 
    if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) 
      break; 
 
  if (tt) 
    thread_list_add_before (list, tt, thread); 
  else 
    thread_list_add (list, thread); 
 
   return thread;    return thread;
 }  }
   
Line 782  funcname_thread_add_timer_timeval (struct thread_maste Line 782  funcname_thread_add_timer_timeval (struct thread_maste
 struct thread *  struct thread *
 funcname_thread_add_timer (struct thread_master *m,  funcname_thread_add_timer (struct thread_master *m,
                            int (*func) (struct thread *),                              int (*func) (struct thread *), 
                           void *arg, long timer, const char* funcname)                           void *arg, long timer,
                            debugargdef)
 {  {
   struct timeval trel;    struct timeval trel;
   
Line 792  funcname_thread_add_timer (struct thread_master *m, Line 793  funcname_thread_add_timer (struct thread_master *m,
   trel.tv_usec = 0;    trel.tv_usec = 0;
   
   return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,     return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, 
                                            &trel, funcname);                                            &trel, debugargpass);
 }  }
   
 /* Add timer event thread with "millisecond" resolution */  /* Add timer event thread with "millisecond" resolution */
 struct thread *  struct thread *
 funcname_thread_add_timer_msec (struct thread_master *m,  funcname_thread_add_timer_msec (struct thread_master *m,
                                 int (*func) (struct thread *),                                   int (*func) (struct thread *), 
                                void *arg, long timer, const char* funcname)                                void *arg, long timer,
                                 debugargdef)
 {  {
   struct timeval trel;    struct timeval trel;
   
Line 809  funcname_thread_add_timer_msec (struct thread_master * Line 811  funcname_thread_add_timer_msec (struct thread_master *
   trel.tv_usec = 1000*(timer % 1000);    trel.tv_usec = 1000*(timer % 1000);
   
   return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,     return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, 
                                            arg, &trel, funcname);                                            arg, &trel, debugargpass);
 }  }
   
 /* Add a background thread, with an optional millisec delay */  /* Add a background thread, with an optional millisec delay */
 struct thread *  struct thread *
 funcname_thread_add_background (struct thread_master *m,  funcname_thread_add_background (struct thread_master *m,
                                 int (*func) (struct thread *),                                  int (*func) (struct thread *),
                                void *arg, long delay,                                 void *arg, long delay,
                                const char *funcname)                                debugargdef)
 {  {
   struct timeval trel;    struct timeval trel;
       
Line 835  funcname_thread_add_background (struct thread_master * Line 837  funcname_thread_add_background (struct thread_master *
     }      }
   
   return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,    return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
                                            arg, &trel, funcname);                                            arg, &trel, debugargpass);
 }  }
   
 /* Add simple event thread. */  /* Add simple event thread. */
 struct thread *  struct thread *
 funcname_thread_add_event (struct thread_master *m,  funcname_thread_add_event (struct thread_master *m,
                  int (*func) (struct thread *), void *arg, int val, const char* funcname)                  int (*func) (struct thread *), void *arg, int val,
                   debugargdef)
 {  {
   struct thread *thread;    struct thread *thread;
   
   assert (m != NULL);    assert (m != NULL);
   
  thread = thread_get (m, THREAD_EVENT, func, arg, funcname);  thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
   thread->u.val = val;    thread->u.val = val;
   thread_list_add (&m->event, thread);    thread_list_add (&m->event, thread);
   
Line 858  funcname_thread_add_event (struct thread_master *m, Line 861  funcname_thread_add_event (struct thread_master *m,
 void  void
 thread_cancel (struct thread *thread)  thread_cancel (struct thread *thread)
 {  {
  struct thread_list *list;  struct thread_list *list = NULL;
   struct pqueue *queue = NULL;
       
   switch (thread->type)    switch (thread->type)
     {      {
Line 873  thread_cancel (struct thread *thread) Line 877  thread_cancel (struct thread *thread)
       list = &thread->master->write;        list = &thread->master->write;
       break;        break;
     case THREAD_TIMER:      case THREAD_TIMER:
      list = &thread->master->timer;      queue = thread->master->timer;
       break;        break;
     case THREAD_EVENT:      case THREAD_EVENT:
       list = &thread->master->event;        list = &thread->master->event;
Line 882  thread_cancel (struct thread *thread) Line 886  thread_cancel (struct thread *thread)
       list = &thread->master->ready;        list = &thread->master->ready;
       break;        break;
     case THREAD_BACKGROUND:      case THREAD_BACKGROUND:
      list = &thread->master->background;      queue = thread->master->background;
       break;        break;
     default:      default:
       return;        return;
       break;        break;
     }      }
  thread_list_delete (list, thread);
   if (queue)
     {
       assert(thread->index >= 0);
       assert(thread == queue->array[thread->index]);
       pqueue_remove_at(thread->index, queue);
     }
   else if (list)
     {
       thread_list_delete (list, thread);
     }
   else
     {
       assert(!"Thread should be either in queue or list!");
     }
 
   thread->type = THREAD_UNUSED;    thread->type = THREAD_UNUSED;
   thread_add_unuse (thread->master, thread);    thread_add_unuse (thread->master, thread);
 }  }
Line 916  thread_cancel_event (struct thread_master *m, void *ar Line 935  thread_cancel_event (struct thread_master *m, void *ar
           thread_add_unuse (m, t);            thread_add_unuse (m, t);
         }          }
     }      }
   
     /* thread can be on the ready list too */
     thread = m->ready.head;
     while (thread)
       {
         struct thread *t;
   
         t = thread;
         thread = t->next;
   
         if (t->arg == arg)
           {
             ret++;
             thread_list_delete (&m->ready, t);
             t->type = THREAD_UNUSED;
             thread_add_unuse (m, t);
           }
       }
   return ret;    return ret;
 }  }
   
 static struct timeval *  static struct timeval *
thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
 {  {
  if (!thread_empty (tlist))  if (queue->size)
     {      {
      *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);      struct thread *next_timer = queue->array[0];
       *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
       return timer_val;        return timer_val;
     }      }
   return NULL;    return NULL;
Line 936  thread_run (struct thread_master *m, struct thread *th Line 974  thread_run (struct thread_master *m, struct thread *th
 {  {
   *fetch = *thread;    *fetch = *thread;
   thread->type = THREAD_UNUSED;    thread->type = THREAD_UNUSED;
   thread->funcname = NULL;  /* thread_call will free fetch's copied pointer */  
   thread_add_unuse (m, thread);    thread_add_unuse (m, thread);
   return fetch;    return fetch;
 }  }
Line 969  thread_process_fd (struct thread_list *list, fd_set *f Line 1006  thread_process_fd (struct thread_list *list, fd_set *f
   
 /* Add all timers that have popped to the ready list. */  /* Add all timers that have popped to the ready list. */
 static unsigned int  static unsigned int
thread_timer_process (struct thread_list *list, struct timeval *timenow)thread_timer_process (struct pqueue *queue, struct timeval *timenow)
 {  {
   struct thread *thread;    struct thread *thread;
   unsigned int ready = 0;    unsigned int ready = 0;
       
  for (thread = list->head; thread; thread = thread->next)  while (queue->size)
     {      {
         thread = queue->array[0];
       if (timeval_cmp (*timenow, thread->u.sands) < 0)        if (timeval_cmp (*timenow, thread->u.sands) < 0)
         return ready;          return ready;
      thread_list_delete (list, thread);      pqueue_dequeue(queue);
       thread->type = THREAD_READY;        thread->type = THREAD_READY;
       thread_list_add (&thread->master->ready, thread);        thread_list_add (&thread->master->ready, thread);
       ready++;        ready++;
Line 991  static unsigned int Line 1029  static unsigned int
 thread_process (struct thread_list *list)  thread_process (struct thread_list *list)
 {  {
   struct thread *thread;    struct thread *thread;
     struct thread *next;
   unsigned int ready = 0;    unsigned int ready = 0;
       
  for (thread = list->head; thread; thread = thread->next)  for (thread = list->head; thread; thread = next)
     {      {
         next = thread->next;
       thread_list_delete (list, thread);        thread_list_delete (list, thread);
       thread->type = THREAD_READY;        thread->type = THREAD_READY;
       thread_list_add (&thread->master->ready, thread);        thread_list_add (&thread->master->ready, thread);
Line 1020  thread_fetch (struct thread_master *m, struct thread * Line 1060  thread_fetch (struct thread_master *m, struct thread *
   while (1)    while (1)
     {      {
       int num = 0;        int num = 0;
   #if defined HAVE_SNMP && defined SNMP_AGENTX
         struct timeval snmp_timer_wait;
         int snmpblock = 0;
         int fdsetsize;
   #endif
               
       /* Signals pre-empt everything */        /* Signals pre-empt everything */
       quagga_sigevent_process ();        quagga_sigevent_process ();
Line 1047  thread_fetch (struct thread_master *m, struct thread * Line 1092  thread_fetch (struct thread_master *m, struct thread *
       if (m->ready.count == 0)        if (m->ready.count == 0)
         {          {
           quagga_get_relative (NULL);            quagga_get_relative (NULL);
          timer_wait = thread_timer_wait (&m->timer, &timer_val);          timer_wait = thread_timer_wait (m->timer, &timer_val);
          timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);          timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
                       
           if (timer_wait_bg &&            if (timer_wait_bg &&
               (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))                (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
             timer_wait = timer_wait_bg;              timer_wait = timer_wait_bg;
         }          }
               
   #if defined HAVE_SNMP && defined SNMP_AGENTX
         /* When SNMP is enabled, we may have to select() on additional
            FD. snmp_select_info() will add them to `readfd'. The trick
            with this function is its last argument. We need to set it to
            0 if timer_wait is not NULL and we need to use the provided
            new timer only if it is still set to 0. */
         if (agentx_enabled)
           {
             fdsetsize = FD_SETSIZE;
             snmpblock = 1;
             if (timer_wait)
               {
                 snmpblock = 0;
                 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
               }
             snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
             if (snmpblock == 0)
               timer_wait = &snmp_timer_wait;
           }
   #endif
       num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);        num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
               
       /* Signals should get quick treatment */        /* Signals should get quick treatment */
Line 1066  thread_fetch (struct thread_master *m, struct thread * Line 1131  thread_fetch (struct thread_master *m, struct thread *
             return NULL;              return NULL;
         }          }
   
   #if defined HAVE_SNMP && defined SNMP_AGENTX
         if (agentx_enabled)
           {
             if (num > 0)
               snmp_read(&readfd);
             else if (num == 0)
               {
                 snmp_timeout();
                 run_alarms();
               }
             netsnmp_check_outstanding_agent_requests();
           }
   #endif
   
       /* Check foreground timers.  Historically, they have had higher        /* Check foreground timers.  Historically, they have had higher
          priority than I/O threads, so let's push them onto the ready           priority than I/O threads, so let's push them onto the ready
          list in front of the I/O threads. */           list in front of the I/O threads. */
       quagga_get_relative (NULL);        quagga_get_relative (NULL);
      thread_timer_process (&m->timer, &relative_time);      thread_timer_process (m->timer, &relative_time);
               
       /* Got IO, process it */        /* Got IO, process it */
       if (num > 0)        if (num > 0)
Line 1091  thread_fetch (struct thread_master *m, struct thread * Line 1170  thread_fetch (struct thread_master *m, struct thread *
 #endif  #endif
   
       /* Background timer/events, lowest priority */        /* Background timer/events, lowest priority */
      thread_timer_process (&m->background, &relative_time);      thread_timer_process (m->background, &relative_time);
               
       if ((thread = thread_trim_head (&m->ready)) != NULL)        if ((thread = thread_trim_head (&m->ready)) != NULL)
         return thread_run (m, thread, fetch);          return thread_run (m, thread, fetch);
Line 1124  int Line 1203  int
 thread_should_yield (struct thread *thread)  thread_should_yield (struct thread *thread)
 {  {
   quagga_get_relative (NULL);    quagga_get_relative (NULL);
  return (timeval_elapsed(relative_time, thread->ru.real) >  return (timeval_elapsed(relative_time, thread->real) >
           THREAD_YIELD_TIME_SLOT);            THREAD_YIELD_TIME_SLOT);
 }  }
   
Line 1146  thread_getrusage (RUSAGE_T *r) Line 1225  thread_getrusage (RUSAGE_T *r)
 #endif /* HAVE_CLOCK_MONOTONIC */  #endif /* HAVE_CLOCK_MONOTONIC */
 }  }
   
   struct thread *thread_current = NULL;
   
 /* We check thread consumed time. If the system has getrusage, we'll  /* We check thread consumed time. If the system has getrusage, we'll
    use that to get in-depth stats on the performance of the thread in addition     use that to get in-depth stats on the performance of the thread in addition
    to wall clock time stats from gettimeofday. */     to wall clock time stats from gettimeofday. */
Line 1153  void Line 1234  void
 thread_call (struct thread *thread)  thread_call (struct thread *thread)
 {  {
   unsigned long realtime, cputime;    unsigned long realtime, cputime;
  RUSAGE_T ru;  RUSAGE_T before, after;
   
  /* Cache a pointer to the relevant cpu history thread, if the thread   /* Cache a pointer to the relevant cpu history thread, if the thread
   * does not have it yet.    * does not have it yet.
Line 1172  thread_call (struct thread *thread) Line 1253  thread_call (struct thread *thread)
                     (void * (*) (void *))cpu_record_hash_alloc);                      (void * (*) (void *))cpu_record_hash_alloc);
     }      }
   
  GETRUSAGE (&thread->ru);  GETRUSAGE (&before);
   thread->real = before.real;
   
     thread_current = thread;
   (*thread->func) (thread);    (*thread->func) (thread);
     thread_current = NULL;
   
  GETRUSAGE (&ru);  GETRUSAGE (&after);
   
  realtime = thread_consumed_time (&ru, &thread->ru, &cputime);  realtime = thread_consumed_time (&after, &before, &cputime);
   thread->hist->real.total += realtime;    thread->hist->real.total += realtime;
   if (thread->hist->real.max < realtime)    if (thread->hist->real.max < realtime)
     thread->hist->real.max = realtime;      thread->hist->real.max = realtime;
Line 1205  thread_call (struct thread *thread) Line 1289  thread_call (struct thread *thread)
                  realtime/1000, cputime/1000);                   realtime/1000, cputime/1000);
     }      }
 #endif /* CONSUMED_TIME_CHECK */  #endif /* CONSUMED_TIME_CHECK */
   
   XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname);  
 }  }
   
 /* Execute thread */  /* Execute thread */
Line 1215  funcname_thread_execute (struct thread_master *m, Line 1297  funcname_thread_execute (struct thread_master *m,
                 int (*func)(struct thread *),                   int (*func)(struct thread *), 
                 void *arg,                  void *arg,
                 int val,                  int val,
                const char* funcname)                debugargdef)
 {  {
   struct thread dummy;     struct thread dummy; 
   
Line 1227  funcname_thread_execute (struct thread_master *m, Line 1309  funcname_thread_execute (struct thread_master *m,
   dummy.func = func;    dummy.func = func;
   dummy.arg = arg;    dummy.arg = arg;
   dummy.u.val = val;    dummy.u.val = val;
   dummy.funcname = strip_funcname (funcname);  
   thread_call (&dummy);  
   
  XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);  dummy.funcname = funcname;
   dummy.schedfrom = schedfrom;
   dummy.schedfrom_line = fromln;
 
   thread_call (&dummy);
   
   return NULL;    return NULL;
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>