Index: lib/command.c =================================================================== RCS file: /var/cvsroot/quagga/lib/command.c,v retrieving revision 1.24 diff -u -r1.24 command.c --- lib/command.c 19 Oct 2004 20:40:08 -0000 1.24 +++ lib/command.c 22 Oct 2004 13:09:10 -0000 @@ -520,6 +520,33 @@ return ""; } +static void +thread_config_timer_jitter_write (struct vty *vty, const char *timerstr, + struct thread_timer_precision_vars *vars) +{ + vty_out (vty, "thread timer %s jitter %d", timerstr, vars->precision); + + if (vars->scale > 0) + vty_out (vty, " %d", vars->scale); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +/* Write out thread configuration */ +static void +thread_config_write (struct vty *vty) +{ + if (memcmp (&thread_timer_sec_precision, &thread_timer_sec_precision_def, + sizeof (struct thread_timer_precision_vars)) != 0) + thread_config_timer_jitter_write (vty, "sec", + &thread_timer_sec_precision); + + if (memcmp (&thread_timer_msec_precision, &thread_timer_msec_precision_def, + sizeof (struct thread_timer_precision_vars)) != 0) + thread_config_timer_jitter_write (vty, "msec", + &thread_timer_msec_precision); +} + /* This function write configuration of this host. */ int config_write_host (struct vty *vty) @@ -573,6 +600,8 @@ if (! host.motd) vty_out (vty, "no banner motd%s", VTY_NEWLINE); + + thread_config_write (vty); return 1; } @@ -3358,6 +3387,10 @@ install_element (CONFIG_NODE, &no_banner_motd_cmd); install_element (CONFIG_NODE, &service_terminal_length_cmd); install_element (CONFIG_NODE, &no_service_terminal_length_cmd); + install_element (CONFIG_NODE, &thread_timer_jitter_cmd); + install_element (CONFIG_NODE, &no_thread_timer_jitter_cmd); + install_element (CONFIG_NODE, &thread_timer_jitter_factor_cmd); + install_element(VIEW_NODE, &show_thread_cpu_cmd); install_element(ENABLE_NODE, &show_thread_cpu_cmd); Index: lib/thread.c =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.c,v retrieving revision 1.9 diff -u -r1.9 thread.c --- lib/thread.c 11 Oct 2004 09:40:58 -0000 1.9 +++ lib/thread.c 22 Oct 2004 13:09:10 -0000 @@ -1,4 +1,4 @@ -/* Thread management routine +#/* Thread management routine * Copyright (C) 1998, 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. @@ -23,18 +23,60 @@ #include -#include "thread.h" #include "memory.h" #include "log.h" #include "hash.h" #include "command.h" #include "sigevent.h" - -static struct hash *cpu_record = NULL; +#include "vty.h" +#include "thread.h" /* Struct timeval's tv_usec one second value. */ #define TIMER_SECOND_MICRO 1000000L +static struct hash *cpu_record = NULL; + +/* default sec timer precision = ± ~0.05s */ +#define THREAD_DEFAULT_SEC_PRECISION 200U +#define THREAD_DEFAULT_SEC_SCALE 8U + +/* default msec timer precision = ± ~0.05ms */ +#define THREAD_DEFAULT_MSEC_PRECISION 6U +#define THREAD_DEFAULT_MSEC_SCALE 3U + +#define JITTER_VALUE(F,S) \ + ((S) << (S)) +#define JITTER_RANGE(factor,scale) \ + JITTER_VALUE((factor),(scale)) << 1 +#define JITTER_MAX (TIMER_SECOND_MICRO << 1) + +/* default timer precision/jitter*/ +struct thread_timer_precision_vars thread_timer_sec_precision_def = +{ + .precision = THREAD_DEFAULT_SEC_PRECISION, + .scale = THREAD_DEFAULT_SEC_SCALE, +}; + +struct thread_timer_precision_vars thread_timer_msec_precision_def = +{ + .precision = THREAD_DEFAULT_MSEC_PRECISION, + .scale = THREAD_DEFAULT_MSEC_SCALE, +}; + +/* current */ +struct thread_timer_precision_vars thread_timer_sec_precision = +{ + .precision = THREAD_DEFAULT_SEC_PRECISION, + .scale = THREAD_DEFAULT_SEC_SCALE, +}; + +struct thread_timer_precision_vars thread_timer_msec_precision = +{ + .precision = THREAD_DEFAULT_MSEC_PRECISION, + .scale = THREAD_DEFAULT_MSEC_SCALE, +}; + + struct timeval timeval_adjust (struct timeval a) { @@ -253,6 +295,12 @@ struct thread_master * thread_master_create () { + /* Not quite the best place for it, but a new file for + * quagga_random_init would be silly + */ + srand (time(NULL)); + srandom (time(NULL)); + if (cpu_record == NULL) { cpu_record = hash_create_size( 1011, cpu_record_hash_key, cpu_record_hash_cmp); @@ -482,15 +530,111 @@ return thread; } +#define THREAD_STR "Thread information/settings\n" +#define TIMER_STR "Timer information/settings\n" + +DEFUN_HIDDEN (thread_timer_jitter, + thread_timer_jitter_cmd, + "thread timer (sec|msec) jitter <0-1000000> <0-128>", + THREAD_STR + TIMER_STR + "thread_add_timer precision/jitter\n" + "thread_add_msec_timer precision/jitter\n" + "Timer jitter settings\n" + "Jitter factor in microseconds to apply to timer\n" + "Jitter scale (jitter factor will be multiplied by 2^scale)\n") +{ + struct thread_timer_precision_vars *varscur, *varsdef; + unsigned int factor; + u_char scale = 0; + + if (argc < 2) + { + vty_out (vty, "%% Insufficient number of arguments%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp (argv[0], "sec")) + { + varscur = &thread_timer_sec_precision; + varsdef = &thread_timer_msec_precision_def; + } + else if (!strcmp (argv[0], "msec")) + { + varscur = &thread_timer_msec_precision; + varsdef = &thread_timer_msec_precision_def; + } + else + { + vty_out (vty, "%% Specified timer, %s, unknown%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + /* "no thread timer (sec|msec) jitter" */ + if (argc == 1) + { + memcpy (varscur, varsdef, sizeof (struct thread_timer_precision_vars)); + return CMD_SUCCESS; + } + + VTY_GET_INTEGER_RANGE ("jitter factor", factor, argv[1], + 0U, TIMER_SECOND_MICRO); + + if (argc > 2) + VTY_GET_INTEGER_RANGE ("jitter scale", scale, argv[2], 0, 128); + + if ( JITTER_RANGE(factor, scale) > JITTER_MAX ) + { + vty_out (vty, "%% Resulting jitter value, %ld, is too high%s", + JITTER_MAX, VTY_NEWLINE); + return CMD_WARNING; + } + + varscur->precision = factor; + varscur->scale = scale; + + return CMD_SUCCESS; +} + +ALIAS_HIDDEN (thread_timer_jitter, + no_thread_timer_jitter_cmd, + "no thread timer (sec|msec) jitter", + NO_STR + THREAD_STR + TIMER_STR + "thread_add_timer precision/jitter\n" + "thread_add_msec_timer precision/jitter\n") + +ALIAS_HIDDEN (thread_timer_jitter, + thread_timer_jitter_factor_cmd, + "no thread timer (sec|msec) jitter <0-TIMER_MICRO_SECOND>", + NO_STR + THREAD_STR + TIMER_STR + "thread_add_timer precision/jitter\n" + "thread_add_msec_timer precision/jitter\n" + "Timer jitter settings\n" + "Jitter factor in microseconds to apply to timer\n") + +/* NB: see command.c::thread_config_write for thread config write-out */ + +/* Add timer, specified in relative time from now. + * Non-0 precision results in timer having jitter applied, bounded + * by +/- (precision<tv_sec; timer_now.tv_usec += time_relative->tv_usec; timeval_adjust (timer_now); + + if (precision > 0) + { + timer_jitter.tv_sec = 0; + timer_jitter.tv_usec = JITTER_VALUE(precision,scale); + + if (timeval_cmp (*time_relative, timer_jitter)) + { + timer_jitter.tv_usec = (random() % JITTER_RANGE(precision,scale)); + timer_jitter.tv_usec -= JITTER_VALUE(precision,scale); + timeval_adjust (timer_jitter); + + timer_now.tv_sec += timer_jitter.tv_sec; + timer_now.tv_usec += timer_jitter.tv_usec; + timeval_adjust (timer_now); + } + } + thread->u.sands = timer_now; /* Sort by timeval. */ @@ -537,7 +698,12 @@ trel.tv_sec = timer; trel.tv_usec = 0; - return funcname_thread_add_timer_timeval (m, func, arg, &trel, funcname); + /* 200*2^8us = precision of +/- ~0.05s */ + return + funcname_thread_add_timer_timeval (m, func, arg, &trel, + thread_timer_sec_precision.precision, + thread_timer_msec_precision.scale, + funcname); } /* Add timer event thread with "millisecond" resolution */ @@ -555,7 +721,12 @@ trel.tv_sec = timer / TIMER_SECOND_MICRO; trel.tv_usec = (timer % TIMER_SECOND_MICRO); - return funcname_thread_add_timer_timeval (m, func, arg, &trel, funcname); + /* 6*2^3us = +/- ~0.05 msec */ + return + funcname_thread_add_timer_timeval (m, func, arg, &trel, + thread_timer_msec_precision.precision, + thread_timer_msec_precision.scale, + funcname); } /* Add simple event thread. */ @@ -800,7 +971,7 @@ /* Write thead. */ ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); - + if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); } Index: lib/thread.h =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.h,v retrieving revision 1.4 diff -u -r1.4 thread.h --- lib/thread.h 5 Oct 2004 21:01:24 -0000 1.4 +++ lib/thread.h 22 Oct 2004 13:09:11 -0000 @@ -80,6 +80,12 @@ unsigned char types; }; +struct thread_timer_precision_vars +{ + unsigned int precision; + u_char scale; +}; + /* Thread types. */ #define THREAD_READ 0 #define THREAD_WRITE 1 @@ -156,6 +162,15 @@ void thread_call (struct thread *); unsigned long thread_timer_remain_second (struct thread *); +/* statically defined and exported variables/functions, + * typically for commands + */ extern struct cmd_element show_thread_cpu_cmd; - +extern struct cmd_element thread_timer_jitter_cmd; +extern struct cmd_element thread_timer_jitter_factor_cmd; +extern struct cmd_element no_thread_timer_jitter_cmd; +extern struct thread_timer_precision_vars thread_timer_sec_precision; +extern struct thread_timer_precision_vars thread_timer_sec_precision_def; +extern struct thread_timer_precision_vars thread_timer_msec_precision; +extern struct thread_timer_precision_vars thread_timer_msec_precision_def; #endif /* _ZEBRA_THREAD_H */