LCOV - code coverage report
Current view: top level - lib - thread.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 307 525 58.5 %
Date: 2015-11-19 Functions: 40 55 72.7 %

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

Generated by: LCOV version 1.10