Annotation of embedaddon/quagga/lib/thread.c, revision 1.1.1.3

1.1       misho       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"
1.1.1.3 ! misho      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: 
1.1       misho      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: 
1.1.1.3 ! misho     111: #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
1.1       misho     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: }
1.1.1.3 ! misho     130: #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
1.1       misho     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:   }
1.1.1.3 ! misho     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__ */
1.1       misho     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;
1.1.1.3 ! misho     269:   strcpy(new->funcname, a->funcname);
1.1       misho     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: 
1.1.1.2   misho     281: static void 
1.1       misho     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);
1.1.1.3 ! misho     336:   strcpy(tmp.funcname, "TOTAL");
1.1       misho     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.  */
1.1.1.2   misho     639: static int
1.1       misho     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 */
1.1.1.3 ! misho     667: void
        !           668: strip_funcname (char *dest, const char *funcname)
1.1       misho     669: {
1.1.1.3 ! misho     670:   char buff[FUNCNAME_LEN];
        !           671:   char tmp, *e, *b = buff;
1.1       misho     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';
1.1.1.3 ! misho     687:   strcpy (dest, b);
1.1       misho     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: {
1.1.1.3 ! misho     696:   struct thread *thread = thread_trim_head (&m->unuse);
1.1       misho     697: 
1.1.1.3 ! misho     698:   if (! thread)
1.1       misho     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:   
1.1.1.3 ! misho     709:   strip_funcname (thread->funcname, funcname);
1.1       misho     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:     }
1.1.1.3 ! misho     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:     }
1.1       misho     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;
1.1.1.2   misho    1012:   struct thread *next;
1.1       misho    1013:   unsigned int ready = 0;
                   1014:   
1.1.1.2   misho    1015:   for (thread = list->head; thread; thread = next)
1.1       misho    1016:     {
1.1.1.2   misho    1017:       next = thread->next;
1.1       misho    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;
1.1.1.2   misho    1033:   struct thread *next;
1.1       misho    1034:   unsigned int ready = 0;
                   1035:   
1.1.1.2   misho    1036:   for (thread = list->head; thread; thread = next)
1.1       misho    1037:     {
1.1.1.2   misho    1038:       next = thread->next;
1.1       misho    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;
1.1.1.3 ! misho    1064: #if defined HAVE_SNMP && defined SNMP_AGENTX
        !          1065:       struct timeval snmp_timer_wait;
        !          1066:       int snmpblock = 0;
        !          1067:       int fdsetsize;
        !          1068: #endif
1.1       misho    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:       
1.1.1.3 ! misho    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
1.1       misho    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: 
1.1.1.3 ! misho    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: 
1.1       misho    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);
1.1.1.3 ! misho    1207:   return (timeval_elapsed(relative_time, thread->real) >
1.1       misho    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;
1.1.1.3 ! misho    1236:   RUSAGE_T before, after;
1.1       misho    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;
1.1.1.3 ! misho    1249:       strcpy(tmp.funcname, thread->funcname);
1.1       misho    1250:       
                   1251:       thread->hist = hash_get (cpu_record, &tmp, 
                   1252:                     (void * (*) (void *))cpu_record_hash_alloc);
                   1253:     }
                   1254: 
1.1.1.3 ! misho    1255:   GETRUSAGE (&before);
        !          1256:   thread->real = before.real;
1.1       misho    1257: 
                   1258:   (*thread->func) (thread);
                   1259: 
1.1.1.3 ! misho    1260:   GETRUSAGE (&after);
1.1       misho    1261: 
1.1.1.3 ! misho    1262:   realtime = thread_consumed_time (&after, &before, &cputime);
1.1       misho    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;
1.1.1.3 ! misho    1309:   strip_funcname (dummy.funcname, funcname);
1.1       misho    1310:   thread_call (&dummy);
                   1311: 
                   1312:   return NULL;
                   1313: }

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