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

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

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