File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / thread.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:39 2013 UTC (11 years, 1 month ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

    1: /* Thread management routine
    2:  * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
    3:  *
    4:  * This file is part of GNU Zebra.
    5:  *
    6:  * GNU Zebra is free software; you can redistribute it and/or modify it
    7:  * under the terms of the GNU General Public License as published by the
    8:  * Free Software Foundation; either version 2, or (at your option) any
    9:  * later version.
   10:  *
   11:  * GNU Zebra is distributed in the hope that it will be useful, but
   12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:  * General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU General Public License
   17:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
   18:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   19:  * 02111-1307, USA.  
   20:  */
   21: 
   22: /* #define DEBUG */
   23: 
   24: #include <zebra.h>
   25: 
   26: #include "thread.h"
   27: #include "memory.h"
   28: #include "log.h"
   29: #include "hash.h"
   30: #include "command.h"
   31: #include "sigevent.h"
   32: 
   33: #if defined HAVE_SNMP && defined SNMP_AGENTX
   34: #include <net-snmp/net-snmp-config.h>
   35: #include <net-snmp/net-snmp-includes.h>
   36: #include <net-snmp/agent/net-snmp-agent-includes.h>
   37: #include <net-snmp/agent/snmp_vars.h>
   38: 
   39: extern int agentx_enabled;
   40: #endif
   41: 
   42: #if defined(__APPLE__)
   43: #include <mach/mach.h>
   44: #include <mach/mach_time.h>
   45: #endif
   46: 
   47: 
   48: /* Recent absolute time of day */
   49: struct timeval recent_time;
   50: static struct timeval last_recent_time;
   51: /* Relative time, since startup */
   52: static struct timeval relative_time;
   53: static struct timeval relative_time_base;
   54: /* init flag */
   55: static unsigned short timers_inited;
   56: 
   57: static struct hash *cpu_record = NULL;
   58: 
   59: /* Struct timeval's tv_usec one second value.  */
   60: #define TIMER_SECOND_MICRO 1000000L
   61: 
   62: /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
   63:    And change negative values to 0. */
   64: static struct timeval
   65: timeval_adjust (struct timeval a)
   66: {
   67:   while (a.tv_usec >= TIMER_SECOND_MICRO)
   68:     {
   69:       a.tv_usec -= TIMER_SECOND_MICRO;
   70:       a.tv_sec++;
   71:     }
   72: 
   73:   while (a.tv_usec < 0)
   74:     {
   75:       a.tv_usec += TIMER_SECOND_MICRO;
   76:       a.tv_sec--;
   77:     }
   78: 
   79:   if (a.tv_sec < 0)
   80:       /* Change negative timeouts to 0. */
   81:       a.tv_sec = a.tv_usec = 0;
   82: 
   83:   return a;
   84: }
   85: 
   86: static struct timeval
   87: timeval_subtract (struct timeval a, struct timeval b)
   88: {
   89:   struct timeval ret;
   90: 
   91:   ret.tv_usec = a.tv_usec - b.tv_usec;
   92:   ret.tv_sec = a.tv_sec - b.tv_sec;
   93: 
   94:   return timeval_adjust (ret);
   95: }
   96: 
   97: static long
   98: timeval_cmp (struct timeval a, struct timeval b)
   99: {
  100:   return (a.tv_sec == b.tv_sec
  101: 	  ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
  102: }
  103: 
  104: static unsigned long
  105: timeval_elapsed (struct timeval a, struct timeval b)
  106: {
  107:   return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
  108: 	  + (a.tv_usec - b.tv_usec));
  109: }
  110: 
  111: #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
  112: static void
  113: quagga_gettimeofday_relative_adjust (void)
  114: {
  115:   struct timeval diff;
  116:   if (timeval_cmp (recent_time, last_recent_time) < 0)
  117:     {
  118:       relative_time.tv_sec++;
  119:       relative_time.tv_usec = 0;
  120:     }
  121:   else
  122:     {
  123:       diff = timeval_subtract (recent_time, last_recent_time);
  124:       relative_time.tv_sec += diff.tv_sec;
  125:       relative_time.tv_usec += diff.tv_usec;
  126:       relative_time = timeval_adjust (relative_time);
  127:     }
  128:   last_recent_time = recent_time;
  129: }
  130: #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
  131: 
  132: /* gettimeofday wrapper, to keep recent_time updated */
  133: static int
  134: quagga_gettimeofday (struct timeval *tv)
  135: {
  136:   int ret;
  137:   
  138:   assert (tv);
  139:   
  140:   if (!(ret = gettimeofday (&recent_time, NULL)))
  141:     {
  142:       /* init... */
  143:       if (!timers_inited)
  144:         {
  145:           relative_time_base = last_recent_time = recent_time;
  146:           timers_inited = 1;
  147:         }
  148:       /* avoid copy if user passed recent_time pointer.. */
  149:       if (tv != &recent_time)
  150:         *tv = recent_time;
  151:       return 0;
  152:     }
  153:   return ret;
  154: }
  155: 
  156: static int
  157: quagga_get_relative (struct timeval *tv)
  158: {
  159:   int ret;
  160: 
  161: #ifdef HAVE_CLOCK_MONOTONIC
  162:   {
  163:     struct timespec tp;
  164:     if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
  165:       {
  166:         relative_time.tv_sec = tp.tv_sec;
  167:         relative_time.tv_usec = tp.tv_nsec / 1000;
  168:       }
  169:   }
  170: #elif defined(__APPLE__)
  171:   {
  172:     uint64_t ticks;
  173:     uint64_t useconds;
  174:     static mach_timebase_info_data_t timebase_info;
  175: 
  176:     ticks = mach_absolute_time();
  177:     if (timebase_info.denom == 0)
  178:       mach_timebase_info(&timebase_info);
  179: 
  180:     useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
  181:     relative_time.tv_sec = useconds / 1000000;
  182:     relative_time.tv_usec = useconds % 1000000;
  183: 
  184:     return 0;
  185:   }
  186: #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
  187:   if (!(ret = quagga_gettimeofday (&recent_time)))
  188:     quagga_gettimeofday_relative_adjust();
  189: #endif /* HAVE_CLOCK_MONOTONIC */
  190: 
  191:   if (tv)
  192:     *tv = relative_time;
  193: 
  194:   return ret;
  195: }
  196: 
  197: /* Get absolute time stamp, but in terms of the internal timer
  198:  * Could be wrong, but at least won't go back.
  199:  */
  200: static void
  201: quagga_real_stabilised (struct timeval *tv)
  202: {
  203:   *tv = relative_time_base;
  204:   tv->tv_sec += relative_time.tv_sec;
  205:   tv->tv_usec += relative_time.tv_usec;
  206:   *tv = timeval_adjust (*tv);
  207: }
  208: 
  209: /* Exported Quagga timestamp function.
  210:  * Modelled on POSIX clock_gettime.
  211:  */
  212: int
  213: quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
  214: {
  215:   switch (clkid)
  216:     {
  217:       case QUAGGA_CLK_REALTIME:
  218:         return quagga_gettimeofday (tv);
  219:       case QUAGGA_CLK_MONOTONIC:
  220:         return quagga_get_relative (tv);
  221:       case QUAGGA_CLK_REALTIME_STABILISED:
  222:         quagga_real_stabilised (tv);
  223:         return 0;
  224:       default:
  225:         errno = EINVAL;
  226:         return -1;
  227:     }
  228: }
  229: 
  230: /* time_t value in terms of stabilised absolute time. 
  231:  * replacement for POSIX time()
  232:  */
  233: time_t
  234: quagga_time (time_t *t)
  235: {
  236:   struct timeval tv;
  237:   quagga_real_stabilised (&tv);
  238:   if (t)
  239:     *t = tv.tv_sec;
  240:   return tv.tv_sec;
  241: }
  242: 
  243: /* Public export of recent_relative_time by value */
  244: struct timeval
  245: recent_relative_time (void)
  246: {
  247:   return relative_time;
  248: }
  249: 
  250: static unsigned int
  251: cpu_record_hash_key (struct cpu_thread_history *a)
  252: {
  253:   return (uintptr_t) a->func;
  254: }
  255: 
  256: static int 
  257: cpu_record_hash_cmp (const struct cpu_thread_history *a,
  258: 		     const struct cpu_thread_history *b)
  259: {
  260:   return a->func == b->func;
  261: }
  262: 
  263: static void *
  264: cpu_record_hash_alloc (struct cpu_thread_history *a)
  265: {
  266:   struct cpu_thread_history *new;
  267:   new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
  268:   new->func = a->func;
  269:   strcpy(new->funcname, a->funcname);
  270:   return new;
  271: }
  272: 
  273: static void
  274: cpu_record_hash_free (void *a)
  275: {
  276:   struct cpu_thread_history *hist = a;
  277:  
  278:   XFREE (MTYPE_THREAD_STATS, hist);
  279: }
  280: 
  281: static void 
  282: vty_out_cpu_thread_history(struct vty* vty,
  283: 			   struct cpu_thread_history *a)
  284: {
  285: #ifdef HAVE_RUSAGE
  286:   vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
  287: 	  a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
  288: 	  a->cpu.total/a->total_calls, a->cpu.max,
  289: 	  a->real.total/a->total_calls, a->real.max);
  290: #else
  291:   vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
  292: 	  a->real.total/1000, a->real.total%1000, a->total_calls,
  293: 	  a->real.total/a->total_calls, a->real.max);
  294: #endif
  295:   vty_out(vty, " %c%c%c%c%c%c %s%s",
  296: 	  a->types & (1 << THREAD_READ) ? 'R':' ',
  297: 	  a->types & (1 << THREAD_WRITE) ? 'W':' ',
  298: 	  a->types & (1 << THREAD_TIMER) ? 'T':' ',
  299: 	  a->types & (1 << THREAD_EVENT) ? 'E':' ',
  300: 	  a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
  301: 	  a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
  302: 	  a->funcname, VTY_NEWLINE);
  303: }
  304: 
  305: static void
  306: cpu_record_hash_print(struct hash_backet *bucket, 
  307: 		      void *args[])
  308: {
  309:   struct cpu_thread_history *totals = args[0];
  310:   struct vty *vty = args[1];
  311:   thread_type *filter = args[2];
  312:   struct cpu_thread_history *a = bucket->data;
  313:   
  314:   a = bucket->data;
  315:   if ( !(a->types & *filter) )
  316:        return;
  317:   vty_out_cpu_thread_history(vty,a);
  318:   totals->total_calls += a->total_calls;
  319:   totals->real.total += a->real.total;
  320:   if (totals->real.max < a->real.max)
  321:     totals->real.max = a->real.max;
  322: #ifdef HAVE_RUSAGE
  323:   totals->cpu.total += a->cpu.total;
  324:   if (totals->cpu.max < a->cpu.max)
  325:     totals->cpu.max = a->cpu.max;
  326: #endif
  327: }
  328: 
  329: static void
  330: cpu_record_print(struct vty *vty, thread_type filter)
  331: {
  332:   struct cpu_thread_history tmp;
  333:   void *args[3] = {&tmp, vty, &filter};
  334: 
  335:   memset(&tmp, 0, sizeof tmp);
  336:   strcpy(tmp.funcname, "TOTAL");
  337:   tmp.types = filter;
  338: 
  339: #ifdef HAVE_RUSAGE
  340:   vty_out(vty, "%21s %18s %18s%s",
  341:   	  "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
  342: #endif
  343:   vty_out(vty, "Runtime(ms)   Invoked Avg uSec Max uSecs");
  344: #ifdef HAVE_RUSAGE
  345:   vty_out(vty, " Avg uSec Max uSecs");
  346: #endif
  347:   vty_out(vty, "  Type  Thread%s", VTY_NEWLINE);
  348:   hash_iterate(cpu_record,
  349: 	       (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
  350: 	       args);
  351: 
  352:   if (tmp.total_calls > 0)
  353:     vty_out_cpu_thread_history(vty, &tmp);
  354: }
  355: 
  356: DEFUN(show_thread_cpu,
  357:       show_thread_cpu_cmd,
  358:       "show thread cpu [FILTER]",
  359:       SHOW_STR
  360:       "Thread information\n"
  361:       "Thread CPU usage\n"
  362:       "Display filter (rwtexb)\n")
  363: {
  364:   int i = 0;
  365:   thread_type filter = (thread_type) -1U;
  366: 
  367:   if (argc > 0)
  368:     {
  369:       filter = 0;
  370:       while (argv[0][i] != '\0')
  371: 	{
  372: 	  switch ( argv[0][i] )
  373: 	    {
  374: 	    case 'r':
  375: 	    case 'R':
  376: 	      filter |= (1 << THREAD_READ);
  377: 	      break;
  378: 	    case 'w':
  379: 	    case 'W':
  380: 	      filter |= (1 << THREAD_WRITE);
  381: 	      break;
  382: 	    case 't':
  383: 	    case 'T':
  384: 	      filter |= (1 << THREAD_TIMER);
  385: 	      break;
  386: 	    case 'e':
  387: 	    case 'E':
  388: 	      filter |= (1 << THREAD_EVENT);
  389: 	      break;
  390: 	    case 'x':
  391: 	    case 'X':
  392: 	      filter |= (1 << THREAD_EXECUTE);
  393: 	      break;
  394: 	    case 'b':
  395: 	    case 'B':
  396: 	      filter |= (1 << THREAD_BACKGROUND);
  397: 	      break;
  398: 	    default:
  399: 	      break;
  400: 	    }
  401: 	  ++i;
  402: 	}
  403:       if (filter == 0)
  404: 	{
  405: 	  vty_out(vty, "Invalid filter \"%s\" specified,"
  406:                   " must contain at least one of 'RWTEXB'%s",
  407: 		  argv[0], VTY_NEWLINE);
  408: 	  return CMD_WARNING;
  409: 	}
  410:     }
  411: 
  412:   cpu_record_print(vty, filter);
  413:   return CMD_SUCCESS;
  414: }
  415: 
  416: static void
  417: cpu_record_hash_clear (struct hash_backet *bucket, 
  418: 		      void *args)
  419: {
  420:   thread_type *filter = args;
  421:   struct cpu_thread_history *a = bucket->data;
  422:   
  423:   a = bucket->data;
  424:   if ( !(a->types & *filter) )
  425:        return;
  426:   
  427:   hash_release (cpu_record, bucket->data);
  428: }
  429: 
  430: static void
  431: cpu_record_clear (thread_type filter)
  432: {
  433:   thread_type *tmp = &filter;
  434:   hash_iterate (cpu_record,
  435: 	        (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
  436: 	        tmp);
  437: }
  438: 
  439: DEFUN(clear_thread_cpu,
  440:       clear_thread_cpu_cmd,
  441:       "clear thread cpu [FILTER]",
  442:       "Clear stored data\n"
  443:       "Thread information\n"
  444:       "Thread CPU usage\n"
  445:       "Display filter (rwtexb)\n")
  446: {
  447:   int i = 0;
  448:   thread_type filter = (thread_type) -1U;
  449: 
  450:   if (argc > 0)
  451:     {
  452:       filter = 0;
  453:       while (argv[0][i] != '\0')
  454: 	{
  455: 	  switch ( argv[0][i] )
  456: 	    {
  457: 	    case 'r':
  458: 	    case 'R':
  459: 	      filter |= (1 << THREAD_READ);
  460: 	      break;
  461: 	    case 'w':
  462: 	    case 'W':
  463: 	      filter |= (1 << THREAD_WRITE);
  464: 	      break;
  465: 	    case 't':
  466: 	    case 'T':
  467: 	      filter |= (1 << THREAD_TIMER);
  468: 	      break;
  469: 	    case 'e':
  470: 	    case 'E':
  471: 	      filter |= (1 << THREAD_EVENT);
  472: 	      break;
  473: 	    case 'x':
  474: 	    case 'X':
  475: 	      filter |= (1 << THREAD_EXECUTE);
  476: 	      break;
  477: 	    case 'b':
  478: 	    case 'B':
  479: 	      filter |= (1 << THREAD_BACKGROUND);
  480: 	      break;
  481: 	    default:
  482: 	      break;
  483: 	    }
  484: 	  ++i;
  485: 	}
  486:       if (filter == 0)
  487: 	{
  488: 	  vty_out(vty, "Invalid filter \"%s\" specified,"
  489:                   " must contain at least one of 'RWTEXB'%s",
  490: 		  argv[0], VTY_NEWLINE);
  491: 	  return CMD_WARNING;
  492: 	}
  493:     }
  494: 
  495:   cpu_record_clear (filter);
  496:   return CMD_SUCCESS;
  497: }
  498: 
  499: /* List allocation and head/tail print out. */
  500: static void
  501: thread_list_debug (struct thread_list *list)
  502: {
  503:   printf ("count [%d] head [%p] tail [%p]\n",
  504: 	  list->count, list->head, list->tail);
  505: }
  506: 
  507: /* Debug print for thread_master. */
  508: static void  __attribute__ ((unused))
  509: thread_master_debug (struct thread_master *m)
  510: {
  511:   printf ("-----------\n");
  512:   printf ("readlist  : ");
  513:   thread_list_debug (&m->read);
  514:   printf ("writelist : ");
  515:   thread_list_debug (&m->write);
  516:   printf ("timerlist : ");
  517:   thread_list_debug (&m->timer);
  518:   printf ("eventlist : ");
  519:   thread_list_debug (&m->event);
  520:   printf ("unuselist : ");
  521:   thread_list_debug (&m->unuse);
  522:   printf ("bgndlist : ");
  523:   thread_list_debug (&m->background);
  524:   printf ("total alloc: [%ld]\n", m->alloc);
  525:   printf ("-----------\n");
  526: }
  527: 
  528: /* Allocate new thread master.  */
  529: struct thread_master *
  530: thread_master_create ()
  531: {
  532:   if (cpu_record == NULL) 
  533:     cpu_record 
  534:       = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key, 
  535:                           (int (*) (const void *, const void *))cpu_record_hash_cmp);
  536:     
  537:   return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
  538: 					   sizeof (struct thread_master));
  539: }
  540: 
  541: /* Add a new thread to the list.  */
  542: static void
  543: thread_list_add (struct thread_list *list, struct thread *thread)
  544: {
  545:   thread->next = NULL;
  546:   thread->prev = list->tail;
  547:   if (list->tail)
  548:     list->tail->next = thread;
  549:   else
  550:     list->head = thread;
  551:   list->tail = thread;
  552:   list->count++;
  553: }
  554: 
  555: /* Add a new thread just before the point.  */
  556: static void
  557: thread_list_add_before (struct thread_list *list, 
  558: 			struct thread *point, 
  559: 			struct thread *thread)
  560: {
  561:   thread->next = point;
  562:   thread->prev = point->prev;
  563:   if (point->prev)
  564:     point->prev->next = thread;
  565:   else
  566:     list->head = thread;
  567:   point->prev = thread;
  568:   list->count++;
  569: }
  570: 
  571: /* Delete a thread from the list. */
  572: static struct thread *
  573: thread_list_delete (struct thread_list *list, struct thread *thread)
  574: {
  575:   if (thread->next)
  576:     thread->next->prev = thread->prev;
  577:   else
  578:     list->tail = thread->prev;
  579:   if (thread->prev)
  580:     thread->prev->next = thread->next;
  581:   else
  582:     list->head = thread->next;
  583:   thread->next = thread->prev = NULL;
  584:   list->count--;
  585:   return thread;
  586: }
  587: 
  588: /* Move thread to unuse list. */
  589: static void
  590: thread_add_unuse (struct thread_master *m, struct thread *thread)
  591: {
  592:   assert (m != NULL && thread != NULL);
  593:   assert (thread->next == NULL);
  594:   assert (thread->prev == NULL);
  595:   assert (thread->type == THREAD_UNUSED);
  596:   thread_list_add (&m->unuse, thread);
  597:   /* XXX: Should we deallocate funcname here? */
  598: }
  599: 
  600: /* Free all unused thread. */
  601: static void
  602: thread_list_free (struct thread_master *m, struct thread_list *list)
  603: {
  604:   struct thread *t;
  605:   struct thread *next;
  606: 
  607:   for (t = list->head; t; t = next)
  608:     {
  609:       next = t->next;
  610:       XFREE (MTYPE_THREAD, t);
  611:       list->count--;
  612:       m->alloc--;
  613:     }
  614: }
  615: 
  616: /* Stop thread scheduler. */
  617: void
  618: thread_master_free (struct thread_master *m)
  619: {
  620:   thread_list_free (m, &m->read);
  621:   thread_list_free (m, &m->write);
  622:   thread_list_free (m, &m->timer);
  623:   thread_list_free (m, &m->event);
  624:   thread_list_free (m, &m->ready);
  625:   thread_list_free (m, &m->unuse);
  626:   thread_list_free (m, &m->background);
  627:   
  628:   XFREE (MTYPE_THREAD_MASTER, m);
  629: 
  630:   if (cpu_record)
  631:     {
  632:       hash_clean (cpu_record, cpu_record_hash_free);
  633:       hash_free (cpu_record);
  634:       cpu_record = NULL;
  635:     }
  636: }
  637: 
  638: /* Thread list is empty or not.  */
  639: static int
  640: thread_empty (struct thread_list *list)
  641: {
  642:   return  list->head ? 0 : 1;
  643: }
  644: 
  645: /* Delete top of the list and return it. */
  646: static struct thread *
  647: thread_trim_head (struct thread_list *list)
  648: {
  649:   if (!thread_empty (list))
  650:     return thread_list_delete (list, list->head);
  651:   return NULL;
  652: }
  653: 
  654: /* Return remain time in second. */
  655: unsigned long
  656: thread_timer_remain_second (struct thread *thread)
  657: {
  658:   quagga_get_relative (NULL);
  659:   
  660:   if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
  661:     return thread->u.sands.tv_sec - relative_time.tv_sec;
  662:   else
  663:     return 0;
  664: }
  665: 
  666: /* Trim blankspace and "()"s */
  667: void
  668: strip_funcname (char *dest, const char *funcname)
  669: {
  670:   char buff[FUNCNAME_LEN];
  671:   char tmp, *e, *b = buff;
  672: 
  673:   strncpy(buff, funcname, sizeof(buff));
  674:   buff[ sizeof(buff) -1] = '\0';
  675:   e = buff +strlen(buff) -1;
  676: 
  677:   /* Wont work for funcname ==  "Word (explanation)"  */
  678: 
  679:   while (*b == ' ' || *b == '(')
  680:     ++b;
  681:   while (*e == ' ' || *e == ')')
  682:     --e;
  683:   e++;
  684: 
  685:   tmp = *e;
  686:   *e = '\0';
  687:   strcpy (dest, b);
  688:   *e = tmp;
  689: }
  690: 
  691: /* Get new thread.  */
  692: static struct thread *
  693: thread_get (struct thread_master *m, u_char type,
  694: 	    int (*func) (struct thread *), void *arg, const char* funcname)
  695: {
  696:   struct thread *thread = thread_trim_head (&m->unuse);
  697: 
  698:   if (! thread)
  699:     {
  700:       thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
  701:       m->alloc++;
  702:     }
  703:   thread->type = type;
  704:   thread->add_type = type;
  705:   thread->master = m;
  706:   thread->func = func;
  707:   thread->arg = arg;
  708:   
  709:   strip_funcname (thread->funcname, funcname);
  710: 
  711:   return thread;
  712: }
  713: 
  714: /* Add new read thread. */
  715: struct thread *
  716: funcname_thread_add_read (struct thread_master *m, 
  717: 		 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
  718: {
  719:   struct thread *thread;
  720: 
  721:   assert (m != NULL);
  722: 
  723:   if (FD_ISSET (fd, &m->readfd))
  724:     {
  725:       zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
  726:       return NULL;
  727:     }
  728: 
  729:   thread = thread_get (m, THREAD_READ, func, arg, funcname);
  730:   FD_SET (fd, &m->readfd);
  731:   thread->u.fd = fd;
  732:   thread_list_add (&m->read, thread);
  733: 
  734:   return thread;
  735: }
  736: 
  737: /* Add new write thread. */
  738: struct thread *
  739: funcname_thread_add_write (struct thread_master *m,
  740: 		 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
  741: {
  742:   struct thread *thread;
  743: 
  744:   assert (m != NULL);
  745: 
  746:   if (FD_ISSET (fd, &m->writefd))
  747:     {
  748:       zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
  749:       return NULL;
  750:     }
  751: 
  752:   thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
  753:   FD_SET (fd, &m->writefd);
  754:   thread->u.fd = fd;
  755:   thread_list_add (&m->write, thread);
  756: 
  757:   return thread;
  758: }
  759: 
  760: static struct thread *
  761: funcname_thread_add_timer_timeval (struct thread_master *m,
  762:                                    int (*func) (struct thread *), 
  763:                                   int type,
  764:                                   void *arg, 
  765:                                   struct timeval *time_relative, 
  766:                                   const char* funcname)
  767: {
  768:   struct thread *thread;
  769:   struct thread_list *list;
  770:   struct timeval alarm_time;
  771:   struct thread *tt;
  772: 
  773:   assert (m != NULL);
  774: 
  775:   assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
  776:   assert (time_relative);
  777:   
  778:   list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
  779:   thread = thread_get (m, type, func, arg, funcname);
  780: 
  781:   /* Do we need jitter here? */
  782:   quagga_get_relative (NULL);
  783:   alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
  784:   alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
  785:   thread->u.sands = timeval_adjust(alarm_time);
  786: 
  787:   /* Sort by timeval. */
  788:   for (tt = list->head; tt; tt = tt->next)
  789:     if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
  790:       break;
  791: 
  792:   if (tt)
  793:     thread_list_add_before (list, tt, thread);
  794:   else
  795:     thread_list_add (list, thread);
  796: 
  797:   return thread;
  798: }
  799: 
  800: 
  801: /* Add timer event thread. */
  802: struct thread *
  803: funcname_thread_add_timer (struct thread_master *m,
  804: 		           int (*func) (struct thread *), 
  805: 		           void *arg, long timer, const char* funcname)
  806: {
  807:   struct timeval trel;
  808: 
  809:   assert (m != NULL);
  810: 
  811:   trel.tv_sec = timer;
  812:   trel.tv_usec = 0;
  813: 
  814:   return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, 
  815:                                             &trel, funcname);
  816: }
  817: 
  818: /* Add timer event thread with "millisecond" resolution */
  819: struct thread *
  820: funcname_thread_add_timer_msec (struct thread_master *m,
  821:                                 int (*func) (struct thread *), 
  822:                                 void *arg, long timer, const char* funcname)
  823: {
  824:   struct timeval trel;
  825: 
  826:   assert (m != NULL);
  827: 
  828:   trel.tv_sec = timer / 1000;
  829:   trel.tv_usec = 1000*(timer % 1000);
  830: 
  831:   return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, 
  832:                                             arg, &trel, funcname);
  833: }
  834: 
  835: /* Add a background thread, with an optional millisec delay */
  836: struct thread *
  837: funcname_thread_add_background (struct thread_master *m,
  838:                                 int (*func) (struct thread *),
  839:                                 void *arg, long delay, 
  840:                                 const char *funcname)
  841: {
  842:   struct timeval trel;
  843:   
  844:   assert (m != NULL);
  845:   
  846:   if (delay)
  847:     {
  848:       trel.tv_sec = delay / 1000;
  849:       trel.tv_usec = 1000*(delay % 1000);
  850:     }
  851:   else
  852:     {
  853:       trel.tv_sec = 0;
  854:       trel.tv_usec = 0;
  855:     }
  856: 
  857:   return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
  858:                                             arg, &trel, funcname);
  859: }
  860: 
  861: /* Add simple event thread. */
  862: struct thread *
  863: funcname_thread_add_event (struct thread_master *m,
  864: 		  int (*func) (struct thread *), void *arg, int val, const char* funcname)
  865: {
  866:   struct thread *thread;
  867: 
  868:   assert (m != NULL);
  869: 
  870:   thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
  871:   thread->u.val = val;
  872:   thread_list_add (&m->event, thread);
  873: 
  874:   return thread;
  875: }
  876: 
  877: /* Cancel thread from scheduler. */
  878: void
  879: thread_cancel (struct thread *thread)
  880: {
  881:   struct thread_list *list;
  882:   
  883:   switch (thread->type)
  884:     {
  885:     case THREAD_READ:
  886:       assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
  887:       FD_CLR (thread->u.fd, &thread->master->readfd);
  888:       list = &thread->master->read;
  889:       break;
  890:     case THREAD_WRITE:
  891:       assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
  892:       FD_CLR (thread->u.fd, &thread->master->writefd);
  893:       list = &thread->master->write;
  894:       break;
  895:     case THREAD_TIMER:
  896:       list = &thread->master->timer;
  897:       break;
  898:     case THREAD_EVENT:
  899:       list = &thread->master->event;
  900:       break;
  901:     case THREAD_READY:
  902:       list = &thread->master->ready;
  903:       break;
  904:     case THREAD_BACKGROUND:
  905:       list = &thread->master->background;
  906:       break;
  907:     default:
  908:       return;
  909:       break;
  910:     }
  911:   thread_list_delete (list, thread);
  912:   thread->type = THREAD_UNUSED;
  913:   thread_add_unuse (thread->master, thread);
  914: }
  915: 
  916: /* Delete all events which has argument value arg. */
  917: unsigned int
  918: thread_cancel_event (struct thread_master *m, void *arg)
  919: {
  920:   unsigned int ret = 0;
  921:   struct thread *thread;
  922: 
  923:   thread = m->event.head;
  924:   while (thread)
  925:     {
  926:       struct thread *t;
  927: 
  928:       t = thread;
  929:       thread = t->next;
  930: 
  931:       if (t->arg == arg)
  932:         {
  933:           ret++;
  934:           thread_list_delete (&m->event, t);
  935:           t->type = THREAD_UNUSED;
  936:           thread_add_unuse (m, t);
  937:         }
  938:     }
  939: 
  940:   /* thread can be on the ready list too */
  941:   thread = m->ready.head;
  942:   while (thread)
  943:     {
  944:       struct thread *t;
  945: 
  946:       t = thread;
  947:       thread = t->next;
  948: 
  949:       if (t->arg == arg)
  950:         {
  951:           ret++;
  952:           thread_list_delete (&m->ready, t);
  953:           t->type = THREAD_UNUSED;
  954:           thread_add_unuse (m, t);
  955:         }
  956:     }
  957:   return ret;
  958: }
  959: 
  960: static struct timeval *
  961: thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
  962: {
  963:   if (!thread_empty (tlist))
  964:     {
  965:       *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
  966:       return timer_val;
  967:     }
  968:   return NULL;
  969: }
  970: 
  971: static struct thread *
  972: thread_run (struct thread_master *m, struct thread *thread,
  973: 	    struct thread *fetch)
  974: {
  975:   *fetch = *thread;
  976:   thread->type = THREAD_UNUSED;
  977:   thread_add_unuse (m, thread);
  978:   return fetch;
  979: }
  980: 
  981: static int
  982: thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
  983: {
  984:   struct thread *thread;
  985:   struct thread *next;
  986:   int ready = 0;
  987:   
  988:   assert (list);
  989:   
  990:   for (thread = list->head; thread; thread = next)
  991:     {
  992:       next = thread->next;
  993: 
  994:       if (FD_ISSET (THREAD_FD (thread), fdset))
  995:         {
  996:           assert (FD_ISSET (THREAD_FD (thread), mfdset));
  997:           FD_CLR(THREAD_FD (thread), mfdset);
  998:           thread_list_delete (list, thread);
  999:           thread_list_add (&thread->master->ready, thread);
 1000:           thread->type = THREAD_READY;
 1001:           ready++;
 1002:         }
 1003:     }
 1004:   return ready;
 1005: }
 1006: 
 1007: /* Add all timers that have popped to the ready list. */
 1008: static unsigned int
 1009: thread_timer_process (struct thread_list *list, struct timeval *timenow)
 1010: {
 1011:   struct thread *thread;
 1012:   struct thread *next;
 1013:   unsigned int ready = 0;
 1014:   
 1015:   for (thread = list->head; thread; thread = next)
 1016:     {
 1017:       next = thread->next;
 1018:       if (timeval_cmp (*timenow, thread->u.sands) < 0)
 1019:         return ready;
 1020:       thread_list_delete (list, thread);
 1021:       thread->type = THREAD_READY;
 1022:       thread_list_add (&thread->master->ready, thread);
 1023:       ready++;
 1024:     }
 1025:   return ready;
 1026: }
 1027: 
 1028: /* process a list en masse, e.g. for event thread lists */
 1029: static unsigned int
 1030: thread_process (struct thread_list *list)
 1031: {
 1032:   struct thread *thread;
 1033:   struct thread *next;
 1034:   unsigned int ready = 0;
 1035:   
 1036:   for (thread = list->head; thread; thread = next)
 1037:     {
 1038:       next = thread->next;
 1039:       thread_list_delete (list, thread);
 1040:       thread->type = THREAD_READY;
 1041:       thread_list_add (&thread->master->ready, thread);
 1042:       ready++;
 1043:     }
 1044:   return ready;
 1045: }
 1046: 
 1047: 
 1048: /* Fetch next ready thread. */
 1049: struct thread *
 1050: thread_fetch (struct thread_master *m, struct thread *fetch)
 1051: {
 1052:   struct thread *thread;
 1053:   fd_set readfd;
 1054:   fd_set writefd;
 1055:   fd_set exceptfd;
 1056:   struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
 1057:   struct timeval timer_val_bg;
 1058:   struct timeval *timer_wait = &timer_val;
 1059:   struct timeval *timer_wait_bg;
 1060: 
 1061:   while (1)
 1062:     {
 1063:       int num = 0;
 1064: #if defined HAVE_SNMP && defined SNMP_AGENTX
 1065:       struct timeval snmp_timer_wait;
 1066:       int snmpblock = 0;
 1067:       int fdsetsize;
 1068: #endif
 1069:       
 1070:       /* Signals pre-empt everything */
 1071:       quagga_sigevent_process ();
 1072:        
 1073:       /* Drain the ready queue of already scheduled jobs, before scheduling
 1074:        * more.
 1075:        */
 1076:       if ((thread = thread_trim_head (&m->ready)) != NULL)
 1077:         return thread_run (m, thread, fetch);
 1078:       
 1079:       /* To be fair to all kinds of threads, and avoid starvation, we
 1080:        * need to be careful to consider all thread types for scheduling
 1081:        * in each quanta. I.e. we should not return early from here on.
 1082:        */
 1083:        
 1084:       /* Normal event are the next highest priority.  */
 1085:       thread_process (&m->event);
 1086:       
 1087:       /* Structure copy.  */
 1088:       readfd = m->readfd;
 1089:       writefd = m->writefd;
 1090:       exceptfd = m->exceptfd;
 1091:       
 1092:       /* Calculate select wait timer if nothing else to do */
 1093:       if (m->ready.count == 0)
 1094:         {
 1095:           quagga_get_relative (NULL);
 1096:           timer_wait = thread_timer_wait (&m->timer, &timer_val);
 1097:           timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
 1098:           
 1099:           if (timer_wait_bg &&
 1100:               (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
 1101:             timer_wait = timer_wait_bg;
 1102:         }
 1103:       
 1104: #if defined HAVE_SNMP && defined SNMP_AGENTX
 1105:       /* When SNMP is enabled, we may have to select() on additional
 1106: 	 FD. snmp_select_info() will add them to `readfd'. The trick
 1107: 	 with this function is its last argument. We need to set it to
 1108: 	 0 if timer_wait is not NULL and we need to use the provided
 1109: 	 new timer only if it is still set to 0. */
 1110:       if (agentx_enabled)
 1111:         {
 1112:           fdsetsize = FD_SETSIZE;
 1113:           snmpblock = 1;
 1114:           if (timer_wait)
 1115:             {
 1116:               snmpblock = 0;
 1117:               memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
 1118:             }
 1119:           snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
 1120:           if (snmpblock == 0)
 1121:             timer_wait = &snmp_timer_wait;
 1122:         }
 1123: #endif
 1124:       num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
 1125:       
 1126:       /* Signals should get quick treatment */
 1127:       if (num < 0)
 1128:         {
 1129:           if (errno == EINTR)
 1130:             continue; /* signal received - process it */
 1131:           zlog_warn ("select() error: %s", safe_strerror (errno));
 1132:             return NULL;
 1133:         }
 1134: 
 1135: #if defined HAVE_SNMP && defined SNMP_AGENTX
 1136:       if (agentx_enabled)
 1137:         {
 1138:           if (num > 0)
 1139:             snmp_read(&readfd);
 1140:           else if (num == 0)
 1141:             {
 1142:               snmp_timeout();
 1143:               run_alarms();
 1144:             }
 1145:           netsnmp_check_outstanding_agent_requests();
 1146:         }
 1147: #endif
 1148: 
 1149:       /* Check foreground timers.  Historically, they have had higher
 1150:          priority than I/O threads, so let's push them onto the ready
 1151: 	 list in front of the I/O threads. */
 1152:       quagga_get_relative (NULL);
 1153:       thread_timer_process (&m->timer, &relative_time);
 1154:       
 1155:       /* Got IO, process it */
 1156:       if (num > 0)
 1157:         {
 1158:           /* Normal priority read thead. */
 1159:           thread_process_fd (&m->read, &readfd, &m->readfd);
 1160:           /* Write thead. */
 1161:           thread_process_fd (&m->write, &writefd, &m->writefd);
 1162:         }
 1163: 
 1164: #if 0
 1165:       /* If any threads were made ready above (I/O or foreground timer),
 1166:          perhaps we should avoid adding background timers to the ready
 1167: 	 list at this time.  If this is code is uncommented, then background
 1168: 	 timer threads will not run unless there is nothing else to do. */
 1169:       if ((thread = thread_trim_head (&m->ready)) != NULL)
 1170:         return thread_run (m, thread, fetch);
 1171: #endif
 1172: 
 1173:       /* Background timer/events, lowest priority */
 1174:       thread_timer_process (&m->background, &relative_time);
 1175:       
 1176:       if ((thread = thread_trim_head (&m->ready)) != NULL)
 1177:         return thread_run (m, thread, fetch);
 1178:     }
 1179: }
 1180: 
 1181: unsigned long
 1182: thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
 1183: {
 1184: #ifdef HAVE_RUSAGE
 1185:   /* This is 'user + sys' time.  */
 1186:   *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
 1187: 	     timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
 1188: #else
 1189:   *cputime = 0;
 1190: #endif /* HAVE_RUSAGE */
 1191:   return timeval_elapsed (now->real, start->real);
 1192: }
 1193: 
 1194: /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds. 
 1195:    Note: we are using real (wall clock) time for this calculation.
 1196:    It could be argued that CPU time may make more sense in certain
 1197:    contexts.  The things to consider are whether the thread may have
 1198:    blocked (in which case wall time increases, but CPU time does not),
 1199:    or whether the system is heavily loaded with other processes competing
 1200:    for CPU time.  On balance, wall clock time seems to make sense. 
 1201:    Plus it has the added benefit that gettimeofday should be faster
 1202:    than calling getrusage. */
 1203: int
 1204: thread_should_yield (struct thread *thread)
 1205: {
 1206:   quagga_get_relative (NULL);
 1207:   return (timeval_elapsed(relative_time, thread->real) >
 1208:   	  THREAD_YIELD_TIME_SLOT);
 1209: }
 1210: 
 1211: void
 1212: thread_getrusage (RUSAGE_T *r)
 1213: {
 1214:   quagga_get_relative (NULL);
 1215: #ifdef HAVE_RUSAGE
 1216:   getrusage(RUSAGE_SELF, &(r->cpu));
 1217: #endif
 1218:   r->real = relative_time;
 1219: 
 1220: #ifdef HAVE_CLOCK_MONOTONIC
 1221:   /* quagga_get_relative() only updates recent_time if gettimeofday
 1222:    * based, not when using CLOCK_MONOTONIC. As we export recent_time
 1223:    * and guarantee to update it before threads are run...
 1224:    */
 1225:   quagga_gettimeofday(&recent_time);
 1226: #endif /* HAVE_CLOCK_MONOTONIC */
 1227: }
 1228: 
 1229: /* We check thread consumed time. If the system has getrusage, we'll
 1230:    use that to get in-depth stats on the performance of the thread in addition
 1231:    to wall clock time stats from gettimeofday. */
 1232: void
 1233: thread_call (struct thread *thread)
 1234: {
 1235:   unsigned long realtime, cputime;
 1236:   RUSAGE_T before, after;
 1237: 
 1238:  /* Cache a pointer to the relevant cpu history thread, if the thread
 1239:   * does not have it yet.
 1240:   *
 1241:   * Callers submitting 'dummy threads' hence must take care that
 1242:   * thread->cpu is NULL
 1243:   */
 1244:   if (!thread->hist)
 1245:     {
 1246:       struct cpu_thread_history tmp;
 1247:       
 1248:       tmp.func = thread->func;
 1249:       strcpy(tmp.funcname, thread->funcname);
 1250:       
 1251:       thread->hist = hash_get (cpu_record, &tmp, 
 1252:                     (void * (*) (void *))cpu_record_hash_alloc);
 1253:     }
 1254: 
 1255:   GETRUSAGE (&before);
 1256:   thread->real = before.real;
 1257: 
 1258:   (*thread->func) (thread);
 1259: 
 1260:   GETRUSAGE (&after);
 1261: 
 1262:   realtime = thread_consumed_time (&after, &before, &cputime);
 1263:   thread->hist->real.total += realtime;
 1264:   if (thread->hist->real.max < realtime)
 1265:     thread->hist->real.max = realtime;
 1266: #ifdef HAVE_RUSAGE
 1267:   thread->hist->cpu.total += cputime;
 1268:   if (thread->hist->cpu.max < cputime)
 1269:     thread->hist->cpu.max = cputime;
 1270: #endif
 1271: 
 1272:   ++(thread->hist->total_calls);
 1273:   thread->hist->types |= (1 << thread->add_type);
 1274: 
 1275: #ifdef CONSUMED_TIME_CHECK
 1276:   if (realtime > CONSUMED_TIME_CHECK)
 1277:     {
 1278:       /*
 1279:        * We have a CPU Hog on our hands.
 1280:        * Whinge about it now, so we're aware this is yet another task
 1281:        * to fix.
 1282:        */
 1283:       zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
 1284: 		 thread->funcname,
 1285: 		 (unsigned long) thread->func,
 1286: 		 realtime/1000, cputime/1000);
 1287:     }
 1288: #endif /* CONSUMED_TIME_CHECK */
 1289: }
 1290: 
 1291: /* Execute thread */
 1292: struct thread *
 1293: funcname_thread_execute (struct thread_master *m,
 1294:                 int (*func)(struct thread *), 
 1295:                 void *arg,
 1296:                 int val,
 1297: 		const char* funcname)
 1298: {
 1299:   struct thread dummy; 
 1300: 
 1301:   memset (&dummy, 0, sizeof (struct thread));
 1302: 
 1303:   dummy.type = THREAD_EVENT;
 1304:   dummy.add_type = THREAD_EXECUTE;
 1305:   dummy.master = NULL;
 1306:   dummy.func = func;
 1307:   dummy.arg = arg;
 1308:   dummy.u.val = val;
 1309:   strip_funcname (dummy.funcname, funcname);
 1310:   thread_call (&dummy);
 1311: 
 1312:   return NULL;
 1313: }

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