? build ? bgpd/DEADJOE ? tests/heavy-wq.c ? tests/heavy.c ? zebra/zebra_rib.c.wq Index: bgpd/bgp_main.c =================================================================== RCS file: /var/cvsroot/quagga/bgpd/bgp_main.c,v retrieving revision 1.16 diff -u -p -b -r1.16 bgp_main.c --- bgpd/bgp_main.c 7 Dec 2004 15:39:31 -0000 1.16 +++ bgpd/bgp_main.c 19 Apr 2005 17:31:24 -0000 @@ -164,7 +164,7 @@ sighup (void) vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, BGP_VTYSH_PATH); /* Try to return to normal operation. */ } @@ -282,7 +282,7 @@ main (int argc, char **argv) signal_init (master, Q_SIGC(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); - vty_init (master); + vty_init (); memory_init (); /* BGP related initialization. */ @@ -302,7 +302,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Make bgp vty socket. */ - vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, BGP_VTYSH_PATH); /* Print banner. */ zlog_notice ("BGPd %s starting: vty@%d, bgp@%d", QUAGGA_VERSION, Index: doc/quagga.info =================================================================== RCS file: /var/cvsroot/quagga/doc/quagga.info,v retrieving revision 1.10 diff -u -p -b -r1.10 quagga.info --- doc/quagga.info 10 Apr 2005 16:43:40 -0000 1.10 +++ doc/quagga.info 19 Apr 2005 17:31:30 -0000 @@ -1,4 +1,5 @@ -This is quagga.info, produced by makeinfo version 4.7 from quagga.texi. +This is ../../../doc/quagga.info, produced by makeinfo version 4.7 from +../../../doc/quagga.texi. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission @@ -22,7 +23,7 @@ END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. - This is Edition 0.99.0, last updated 15 December 2004 of `The Quagga + This is Edition 0.99.0, last updated 15 April 2005 of `The Quagga Manual', for Quagga Version 0.99.0. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. @@ -3825,17 +3826,11 @@ fig:normal-processing::, it consists of its attributes modified. Those routes which are accepted by the `Out' filters of a peer are announced to that peer. -[image src="fig-normal-processing.png" alt="Normal announcement processing"] + Figure 10.1: Announcement processing inside a "normal" BGP speaker -Figure 10.1: Announcement processing inside a "normal" BGP speaker + Figure 10.2: Full Mesh -[image src="fig_topologies_full.png" alt="Full Mesh BGP Topology"] - -Figure 10.2: Full Mesh - -[image src="fig_topologies_rs.png" alt="Route Server BGP Topology"] - -Figure 10.3: Route Server and clients + Figure 10.3: Route Server and clients Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as @@ -3920,9 +3915,8 @@ additional comments: not to remove them as they do not hurt anybody (they can always be left empty). -[image src="fig-rs-processing.png" alt="Route Server Processing Model"] - -Figure 10.4: Announcement processing model implemented by the Route Server + Figure 10.4: Announcement processing model implemented by the Route +Server  File: quagga.info, Node: Commands for configuring a Route Server, Next: Example of Route Server Configuration, Prev: Description of the Route Server model, Up: Configuring Quagga as a Route Server @@ -6080,157 +6074,157 @@ VTY Key Index  Tag Table: -Node: Top1890 -Node: Overview2485 -Node: About Quagga3886 -Node: System Architecture6139 -Node: Supported Platforms8829 -Node: Supported RFC9970 -Node: How to get Quagga11934 -Node: Mailing List12688 -Node: Bug Reports13135 -Node: Installation14013 -Node: Configure the Software14447 -Node: The Configure script and its options14695 -Node: Least-Privilege support17883 -Node: Linux notes19619 -Ref: Linux notes-Footnote-121477 -Node: Build the Software21543 -Node: Install the Software22091 -Node: Basic commands23551 -Node: Config Commands24326 -Node: Basic Config Commands25219 -Node: Sample Config File30709 -Node: Terminal Mode Commands31479 -Node: Common Invocation Options32576 -Node: Virtual Terminal Interfaces33983 -Node: VTY Overview34494 -Node: VTY Modes35745 -Node: VTY View Mode36195 -Node: VTY Enable Mode36445 -Node: VTY Other Modes36723 -Node: VTY CLI Commands36899 -Node: CLI Movement Commands37359 -Node: CLI Editing Commands37882 -Node: CLI Advanced Commands38470 -Node: Zebra39236 -Node: Invoking zebra39745 -Node: Interface Commands40324 -Node: Static Route Commands41856 -Node: zebra Terminal Mode Commands45129 -Node: RIP46094 -Node: Starting and Stopping ripd47031 -Node: RIP netmask48444 -Node: RIP Configuration49543 -Node: How to Announce RIP route53808 -Node: Filtering RIP Routes56371 -Node: RIP Metric Manipulation57838 -Node: RIP distance58751 -Node: RIP route-map59566 -Node: RIP Authentication62082 -Node: RIP Timers63189 -Node: Show RIP Information64475 -Node: RIP Debug Commands65848 -Node: RIPng66844 -Node: Invoking ripngd67164 -Node: ripngd Configuration67413 -Node: ripngd Terminal Mode Commands68164 -Node: ripngd Filtering Commands68528 -Node: OSPFv269037 -Node: Configuring ospfd69596 -Node: OSPF router70064 -Node: OSPF area73220 -Node: OSPF interface78402 -Node: Redistribute routes to OSPF81785 -Node: Showing OSPF information83948 -Node: Debugging OSPF85194 -Node: OSPFv386233 -Node: OSPF6 router86553 -Node: OSPF6 area86907 -Node: OSPF6 interface87085 -Node: Redistribute routes to OSPF687962 -Node: Showing OSPF6 information88278 -Node: BGP89098 -Node: Starting BGP89988 -Node: BGP router90565 -Node: BGP distance91809 -Node: BGP decision process92247 -Node: BGP network92729 -Node: BGP route92919 -Node: Route Aggregation93475 -Node: Redistribute to BGP94044 -Node: BGP Peer94571 -Node: Defining Peer94758 -Node: BGP Peer commands95371 -Node: Peer filtering97775 -Node: BGP Peer Group98283 -Node: BGP Address Family98596 -Node: Autonomous System98750 -Node: AS Path Regular Expression99587 -Node: Display BGP Routes by AS Path100834 -Node: AS Path Access List101274 -Node: Using AS Path in Route Map101741 -Node: Private AS Numbers102022 -Node: BGP Communities Attribute102180 -Node: BGP Community Lists104647 -Node: Numbered BGP Community Lists107301 -Node: BGP Community in Route Map108888 -Node: Display BGP Routes by Community110831 -Node: Using BGP Communities Attribute112000 -Node: BGP Extended Communities Attribute115568 -Node: BGP Extended Community Lists117340 -Node: BGP Extended Communities in Route Map119215 -Node: Displaying BGP routes119674 -Node: Show IP BGP119911 -Node: More Show IP BGP120611 -Node: Capability Negotiation121762 -Node: Route Reflector125066 -Node: Route Server125345 -Node: Multiple instance126411 -Node: BGP instance and view128222 -Node: Routing policy129602 -Node: Viewing the view130370 -Node: How to set up a 6-Bone connection130655 -Node: Dump BGP packets and table132027 -Node: Configuring Quagga as a Route Server132574 -Node: Description of the Route Server model133535 -Ref: fig:normal-processing135112 -Ref: fig:full-mesh135262 -Ref: fig:route-server135358 -Ref: filter-delegation135772 -Ref: Route Server tasks136956 -Ref: Route-server path filter process137327 -Ref: fig:rs-processing139641 -Node: Commands for configuring a Route Server139794 -Node: Example of Route Server Configuration142821 -Node: Configuration of the BGP routers without Route Server143742 -Node: Configuration of the BGP routers with Route Server146625 -Node: Configuration of the Route Server itself147926 -Node: Further considerations about Import and Export route-maps152925 -Node: VTY shell155969 -Node: VTY shell username156638 -Node: VTY shell integrated configuration157270 -Node: Filtering158718 -Node: IP Access List159071 -Node: IP Prefix List159457 -Node: ip prefix-list description162476 -Node: ip prefix-list sequential number control163003 -Node: Showing ip prefix-list163545 -Node: Clear counter of ip prefix-list164653 -Node: Route Map165092 -Node: Route Map Command165597 -Node: Route Map Match Command165794 -Node: Route Map Set Command166418 -Node: IPv6 Support167295 -Node: Router Advertisement167867 -Node: Kernel Interface173483 -Node: SNMP Support175440 -Node: Getting and installing an SNMP agent176012 -Node: SMUX configuration176585 -Node: MIB and command reference178721 -Node: Zebra Protocol180108 -Node: Packet Binary Dump Format182022 -Node: Command Index193632 -Node: VTY Key Index251339 +Node: Top1913 +Node: Overview2508 +Node: About Quagga3909 +Node: System Architecture6162 +Node: Supported Platforms8852 +Node: Supported RFC9993 +Node: How to get Quagga11957 +Node: Mailing List12711 +Node: Bug Reports13158 +Node: Installation14036 +Node: Configure the Software14470 +Node: The Configure script and its options14718 +Node: Least-Privilege support17906 +Node: Linux notes19642 +Ref: Linux notes-Footnote-121500 +Node: Build the Software21566 +Node: Install the Software22114 +Node: Basic commands23574 +Node: Config Commands24349 +Node: Basic Config Commands25242 +Node: Sample Config File30732 +Node: Terminal Mode Commands31502 +Node: Common Invocation Options32599 +Node: Virtual Terminal Interfaces34006 +Node: VTY Overview34517 +Node: VTY Modes35768 +Node: VTY View Mode36218 +Node: VTY Enable Mode36468 +Node: VTY Other Modes36746 +Node: VTY CLI Commands36922 +Node: CLI Movement Commands37382 +Node: CLI Editing Commands37905 +Node: CLI Advanced Commands38493 +Node: Zebra39259 +Node: Invoking zebra39768 +Node: Interface Commands40347 +Node: Static Route Commands41879 +Node: zebra Terminal Mode Commands45152 +Node: RIP46117 +Node: Starting and Stopping ripd47054 +Node: RIP netmask48467 +Node: RIP Configuration49566 +Node: How to Announce RIP route53831 +Node: Filtering RIP Routes56394 +Node: RIP Metric Manipulation57861 +Node: RIP distance58774 +Node: RIP route-map59589 +Node: RIP Authentication62105 +Node: RIP Timers63212 +Node: Show RIP Information64498 +Node: RIP Debug Commands65871 +Node: RIPng66867 +Node: Invoking ripngd67187 +Node: ripngd Configuration67436 +Node: ripngd Terminal Mode Commands68187 +Node: ripngd Filtering Commands68551 +Node: OSPFv269060 +Node: Configuring ospfd69619 +Node: OSPF router70087 +Node: OSPF area73243 +Node: OSPF interface78425 +Node: Redistribute routes to OSPF81808 +Node: Showing OSPF information83971 +Node: Debugging OSPF85217 +Node: OSPFv386256 +Node: OSPF6 router86576 +Node: OSPF6 area86930 +Node: OSPF6 interface87108 +Node: Redistribute routes to OSPF687985 +Node: Showing OSPF6 information88301 +Node: BGP89121 +Node: Starting BGP90011 +Node: BGP router90588 +Node: BGP distance91832 +Node: BGP decision process92270 +Node: BGP network92752 +Node: BGP route92942 +Node: Route Aggregation93498 +Node: Redistribute to BGP94067 +Node: BGP Peer94594 +Node: Defining Peer94781 +Node: BGP Peer commands95394 +Node: Peer filtering97798 +Node: BGP Peer Group98306 +Node: BGP Address Family98619 +Node: Autonomous System98773 +Node: AS Path Regular Expression99610 +Node: Display BGP Routes by AS Path100857 +Node: AS Path Access List101297 +Node: Using AS Path in Route Map101764 +Node: Private AS Numbers102045 +Node: BGP Communities Attribute102203 +Node: BGP Community Lists104670 +Node: Numbered BGP Community Lists107324 +Node: BGP Community in Route Map108911 +Node: Display BGP Routes by Community110854 +Node: Using BGP Communities Attribute112023 +Node: BGP Extended Communities Attribute115591 +Node: BGP Extended Community Lists117363 +Node: BGP Extended Communities in Route Map119238 +Node: Displaying BGP routes119697 +Node: Show IP BGP119934 +Node: More Show IP BGP120634 +Node: Capability Negotiation121785 +Node: Route Reflector125089 +Node: Route Server125368 +Node: Multiple instance126434 +Node: BGP instance and view128245 +Node: Routing policy129625 +Node: Viewing the view130393 +Node: How to set up a 6-Bone connection130678 +Node: Dump BGP packets and table132050 +Node: Configuring Quagga as a Route Server132597 +Node: Description of the Route Server model133558 +Ref: fig:normal-processing135135 +Ref: fig:full-mesh135204 +Ref: fig:route-server135229 +Ref: filter-delegation135571 +Ref: Route Server tasks136755 +Ref: Route-server path filter process137126 +Ref: fig:rs-processing139440 +Node: Commands for configuring a Route Server139517 +Node: Example of Route Server Configuration142544 +Node: Configuration of the BGP routers without Route Server143465 +Node: Configuration of the BGP routers with Route Server146348 +Node: Configuration of the Route Server itself147649 +Node: Further considerations about Import and Export route-maps152648 +Node: VTY shell155692 +Node: VTY shell username156361 +Node: VTY shell integrated configuration156993 +Node: Filtering158441 +Node: IP Access List158794 +Node: IP Prefix List159180 +Node: ip prefix-list description162199 +Node: ip prefix-list sequential number control162726 +Node: Showing ip prefix-list163268 +Node: Clear counter of ip prefix-list164376 +Node: Route Map164815 +Node: Route Map Command165320 +Node: Route Map Match Command165517 +Node: Route Map Set Command166141 +Node: IPv6 Support167018 +Node: Router Advertisement167590 +Node: Kernel Interface173206 +Node: SNMP Support175163 +Node: Getting and installing an SNMP agent175735 +Node: SMUX configuration176308 +Node: MIB and command reference178444 +Node: Zebra Protocol179831 +Node: Packet Binary Dump Format181745 +Node: Command Index193355 +Node: VTY Key Index251062  End Tag Table Index: isisd/isis_main.c =================================================================== RCS file: /var/cvsroot/quagga/isisd/isis_main.c,v retrieving revision 1.18 diff -u -p -b -r1.18 isis_main.c --- isisd/isis_main.c 23 Feb 2005 15:48:32 -0000 1.18 +++ isisd/isis_main.c 19 Apr 2005 17:31:31 -0000 @@ -300,7 +300,7 @@ main (int argc, char **argv, char **envp zprivs_init (&isisd_privs); signal_init (master, Q_SIGC (isisd_signals), isisd_signals); cmd_init (1); - vty_init (master); + vty_init (); memory_init (); access_list_init(); isis_init (); @@ -321,7 +321,7 @@ main (int argc, char **argv, char **envp pid_output (pid_file); /* Make isis vty socket. */ - vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, ISIS_VTYSH_PATH); /* Print banner. */ zlog_notice ("Quagga-ISISd %s starting: vty@%d", QUAGGA_VERSION, vty_port); Index: lib/Makefile.am =================================================================== RCS file: /var/cvsroot/quagga/lib/Makefile.am,v retrieving revision 1.20 diff -u -p -b -r1.20 Makefile.am --- lib/Makefile.am 15 Apr 2005 22:18:37 -0000 1.20 +++ lib/Makefile.am 19 Apr 2005 17:31:31 -0000 @@ -12,7 +12,7 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c qtime.c BUILT_SOURCES = memtypes.h @@ -25,9 +25,11 @@ pkginclude_HEADERS = \ memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h \ + privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ + workqueue.h qtime.h privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h EXTRA_DIST = regex.c regex-gnu.h memtypes.awk -memtypes.h: memtypes.c memtypes.awk - ($(GAWK) -f memtypes.awk memtypes.c > memtypes.h) +memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk + ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > memtypes.h) Index: lib/command.c =================================================================== RCS file: /var/cvsroot/quagga/lib/command.c,v retrieving revision 1.46 diff -u -p -b -r1.46 command.c --- lib/command.c 14 Mar 2005 20:19:01 -0000 1.46 +++ lib/command.c 19 Apr 2005 17:31:33 -0000 @@ -3578,8 +3578,10 @@ cmd_init (int terminal) install_element (CONFIG_NODE, &service_terminal_length_cmd); install_element (CONFIG_NODE, &no_service_terminal_length_cmd); - install_element(VIEW_NODE, &show_thread_cpu_cmd); - install_element(ENABLE_NODE, &show_thread_cpu_cmd); + install_element (VIEW_NODE, &show_thread_cpu_cmd); + install_element (ENABLE_NODE, &show_thread_cpu_cmd); + install_element (VIEW_NODE, &show_thread_work_queues_cmd); + install_element (ENABLE_NODE, &show_thread_work_queues_cmd); } srand(time(NULL)); } Index: lib/memtypes.c =================================================================== RCS file: /var/cvsroot/quagga/lib/memtypes.c,v retrieving revision 1.2 diff -u -p -b -r1.2 memtypes.c --- lib/memtypes.c 16 Apr 2005 15:51:05 -0000 1.2 +++ lib/memtypes.c 19 Apr 2005 17:31:34 -0000 @@ -64,6 +64,10 @@ struct memory_list memory_list_lib[] = { MTYPE_PRIVS, "Privilege information" }, { MTYPE_ZLOG, "Logging" }, { MTYPE_ZCLIENT, "Zclient" }, + { MTYPE_WORK_QUEUE, "Work queue" }, + { MTYPE_WORK_QUEUE_ITEM, "Work queue" }, + { MTYPE_WORK_QUEUE_NAME, "Work queue name string" }, + { MTYPE_WORK_QUEUE_SPEC, "Work queue specification" }, { -1, NULL }, }; @@ -74,6 +78,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_VRF_NAME, "VRF name" }, { MTYPE_NEXTHOP, "Nexthop" }, { MTYPE_RIB, "RIB" }, + { MTYPE_RIB_QUEUE, "RIB process work queue" }, { MTYPE_STATIC_IPV4, "Static IPv4 route" }, { MTYPE_STATIC_IPV6, "Static IPv6 route" }, { -1, NULL }, Index: lib/memtypes.h =================================================================== RCS file: /var/cvsroot/quagga/lib/memtypes.h,v retrieving revision 1.1 diff -u -p -b -r1.1 memtypes.h --- lib/memtypes.h 15 Apr 2005 22:18:37 -0000 1.1 +++ lib/memtypes.h 19 Apr 2005 17:31:34 -0000 @@ -56,11 +56,16 @@ enum MTYPE_PRIVS, MTYPE_ZLOG, MTYPE_ZCLIENT, + MTYPE_WORK_QUEUE, + MTYPE_WORK_QUEUE_ITEM, + MTYPE_WORK_QUEUE_NAME, + MTYPE_WORK_QUEUE_SPEC, MTYPE_RTADV_PREFIX, MTYPE_VRF, MTYPE_VRF_NAME, MTYPE_NEXTHOP, MTYPE_RIB, + MTYPE_RIB_QUEUE, MTYPE_STATIC_IPV4, MTYPE_STATIC_IPV6, MTYPE_BGP, Index: lib/qtime.c =================================================================== RCS file: lib/qtime.c diff -N lib/qtime.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/qtime.c 19 Apr 2005 17:31:34 -0000 @@ -0,0 +1,79 @@ +/* Time functions + * Copyright (C) 1998, 2000 Kunihiro Ishiguro + * + * This file is part of Quagga. + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +struct timeval +timeval_adjust (struct timeval a) +{ + while (a.tv_usec >= TIMER_SECOND_MICRO) + { + a.tv_usec -= TIMER_SECOND_MICRO; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += TIMER_SECOND_MICRO; + a.tv_sec--; + } + + if (a.tv_sec < 0) + { + a.tv_sec = 0; + a.tv_usec = 10; + } + + if (a.tv_sec > TIMER_SECOND_MICRO) + a.tv_sec = TIMER_SECOND_MICRO; + + return a; +} + +struct timeval +timeval_subtract (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_usec = a.tv_usec - b.tv_usec; + ret.tv_sec = a.tv_sec - b.tv_sec; + + return timeval_adjust (ret); +} + +int +timeval_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec + ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +unsigned long +timeval_elapsed (struct timeval a, struct timeval b) +{ + return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + + (a.tv_usec - b.tv_usec)); +} + Index: lib/qtime.h =================================================================== RCS file: lib/qtime.h diff -N lib/qtime.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/qtime.h 19 Apr 2005 17:31:34 -0000 @@ -0,0 +1,24 @@ +/* + * $Id:$ + */ + +#ifndef _QUAGGA_TIME_H +#define _QUAGGA_TIME_H +#include + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +/* adjust tv_usec portion of timeval */ +struct timeval timeval_adjust (struct timeval); + +/* subtract b from a */ +struct timeval timeval_subtract (struct timeval a, struct timeval b); + +/* cmp a and b, positive if a is later. */ +int timeval_cmp (struct timeval a, struct timeval b); + +/* return difference, in micro seconds, of a from b */ +unsigned long timeval_elapsed (struct timeval a, struct timeval b); + +#endif /* _QUAGGA_TIME_H */ Index: lib/thread.c =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.c,v retrieving revision 1.14 diff -u -p -b -r1.14 thread.c --- lib/thread.c 16 Apr 2005 17:11:24 -0000 1.14 +++ lib/thread.c 19 Apr 2005 17:31:34 -0000 @@ -28,69 +28,16 @@ #include "log.h" #include "hash.h" #include "command.h" +#include "workqueue.h" #include "sigevent.h" +#include "qtime.h" static struct hash *cpu_record = NULL; -/* Struct timeval's tv_usec one second value. */ -#define TIMER_SECOND_MICRO 1000000L - -struct timeval -timeval_adjust (struct timeval a) -{ - while (a.tv_usec >= TIMER_SECOND_MICRO) - { - a.tv_usec -= TIMER_SECOND_MICRO; - a.tv_sec++; - } - - while (a.tv_usec < 0) - { - a.tv_usec += TIMER_SECOND_MICRO; - a.tv_sec--; - } - - if (a.tv_sec < 0) - { - a.tv_sec = 0; - a.tv_usec = 10; - } - - if (a.tv_sec > TIMER_SECOND_MICRO) - a.tv_sec = TIMER_SECOND_MICRO; - - return a; -} - -static struct timeval -timeval_subtract (struct timeval a, struct timeval b) -{ - struct timeval ret; - - ret.tv_usec = a.tv_usec - b.tv_usec; - ret.tv_sec = a.tv_sec - b.tv_sec; - - return timeval_adjust (ret); -} - -static int -timeval_cmp (struct timeval a, struct timeval b) -{ - return (a.tv_sec == b.tv_sec - ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); -} - -static unsigned long -timeval_elapsed (struct timeval a, struct timeval b) -{ - return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) - + (a.tv_usec - b.tv_usec)); -} - static unsigned int cpu_record_hash_key (struct cpu_thread_history *a) { - return (unsigned int) a->func; + return ((unsigned long) a->func) & -1U; } static int @@ -114,7 +61,7 @@ static inline void vty_out_cpu_thread_history(struct vty* vty, struct cpu_thread_history *a) { - vty_out(vty, " %7ld.%03ld %9d %8ld %10ld %c%c%c%c%c %s%s", + vty_out(vty, " %7ld.%03ld %9d %8ld %10ld %c%c%c%c%c%c %s%s", a->total/1000, a->total%1000, a->total_calls, a->total/a->total_calls, a->max, a->types & (1 << THREAD_READ) ? 'R':' ', @@ -122,6 +69,7 @@ vty_out_cpu_thread_history(struct vty* v a->types & (1 << THREAD_TIMER) ? 'T':' ', a->types & (1 << THREAD_EVENT) ? 'E':' ', a->types & (1 << THREAD_EXECUTE) ? 'X':' ', + a->types & (1 << THREAD_QUEUE) ? 'Q' : ' ', a->funcname, VTY_NEWLINE); } @@ -172,7 +120,7 @@ DEFUN(show_thread_cpu, SHOW_STR "Thread information\n" "Thread CPU usage\n" - "Display filter (rwtex)\n") + "Display filter (rwtexq)\n") { int i = 0; unsigned char filter = 0xff; @@ -204,6 +152,10 @@ DEFUN(show_thread_cpu, case 'X': filter |= (1 << THREAD_EXECUTE); break; + case 'q': + case 'Q': + filter |= (1 << THREAD_QUEUE); + break; default: break; } @@ -211,7 +163,7 @@ DEFUN(show_thread_cpu, } if (filter == 0) { - vty_out(vty, "Invalid filter \"%s\" specified, must contain at least one of 'RWTEX'%s", + vty_out(vty, "Invalid filter \"%s\" specified, must contain at least one of 'RWTEXQ'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } @@ -252,12 +204,19 @@ thread_master_debug (struct thread_maste struct thread_master * thread_master_create () { + struct thread_master *m; + if (cpu_record == NULL) - { - cpu_record = hash_create_size( 1011, cpu_record_hash_key, cpu_record_hash_cmp); - } - return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, + cpu_record = hash_create_size (1011, cpu_record_hash_key, + cpu_record_hash_cmp); + + m = (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); + + m->queues = list_new(); + + return m; + } /* Add a new thread to the list. */ @@ -346,7 +305,7 @@ thread_master_free (struct thread_master thread_list_free (m, &m->event); thread_list_free (m, &m->ready); thread_list_free (m, &m->unuse); - + list_delete (m->queues); XFREE (MTYPE_THREAD_MASTER, m); } @@ -726,6 +685,51 @@ thread_process_fd (struct thread_master return ready; } +/* Find first suitable work queue ready for processing, create a thread + * to do so and add this thread to the ready list. + */ +void +thread_process_work_queues (struct thread_master *m, struct list *list) +{ + struct listnode *node, *nnode; + struct work_queue *wq; + struct timeval tvnow; + struct thread *new; + + if ( !listcount (list) ) + return; + + gettimeofday(&tvnow, NULL); + + for (ALL_LIST_ELEMENTS (list, node, nnode, wq)) + { + /* ignore empty work queue */ + if ( !listcount (wq->items) ) + continue; + + /* run new work queues (nextrun not yet set) + * and eligible existing queues */ + if ((!timerisset (&wq->nextrun)) + || timercmp (&tvnow, &wq->nextrun, >)) + { + char *str = XSTRDUP (MTYPE_THREAD_FUNCNAME, wq->name); + + /* create new thread and add it to ready list */ + new = thread_get (wq->master, THREAD_QUEUE, + &work_queue_run, + wq, str); + + thread_list_add (&m->ready, new); + + /* move the work_queue object to the back of the queue */ + LISTNODE_DETACH (list, node); + LISTNODE_ATTACH (list, node); + + return; + } + } +} + /* Fetch next ready thread. */ struct thread * thread_fetch (struct thread_master *m, struct thread *fetch) @@ -799,6 +803,9 @@ thread_fetch (struct thread_master *m, s /* Write thead. */ ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); + /* Work queues, lowest priority */ + thread_process_work_queues (m, m->queues); + if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); } @@ -821,10 +828,6 @@ thread_consumed_time (RUSAGE_T *now, RUS return thread_time; } -#if 0 - -/* This function is not currently used: threads never yield! */ - /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds. */ int @@ -839,8 +842,6 @@ thread_should_yield (struct thread *thre else return 0; } - -#endif /* We check thread consumed time. If the system has getrusage, we'll use that to get indepth stats on the performance of the thread. If Index: lib/thread.h =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.h,v retrieving revision 1.5 diff -u -p -b -r1.5 thread.h --- lib/thread.h 16 Apr 2005 17:11:24 -0000 1.5 +++ lib/thread.h 19 Apr 2005 17:31:34 -0000 @@ -22,6 +22,8 @@ #ifndef _ZEBRA_THREAD_H #define _ZEBRA_THREAD_H +#include + #ifdef HAVE_RUSAGE #define RUSAGE_T struct rusage #define GETRUSAGE(X) getrusage (RUSAGE_SELF, X); @@ -47,6 +49,7 @@ struct thread_master struct thread_list event; struct thread_list ready; struct thread_list unuse; + struct list *queues; fd_set readfd; fd_set writefd; fd_set exceptfd; @@ -72,7 +75,8 @@ struct thread char* funcname; }; -struct cpu_thread_history { +struct cpu_thread_history +{ int (*func)(struct thread *); const char *funcname; unsigned int total_calls; @@ -86,11 +90,12 @@ struct cpu_thread_history { #define THREAD_TIMER 2 #define THREAD_EVENT 3 #define THREAD_READY 4 -#define THREAD_UNUSED 5 -#define THREAD_EXECUTE 6 +#define THREAD_QUEUE 5 +#define THREAD_UNUSED 6 +#define THREAD_EXECUTE 7 /* Thread yield time. */ -#define THREAD_YIELD_TIME_SLOT 100 * 1000L /* 100ms */ +#define THREAD_YIELD_TIME_SLOT 20 * 1000L /* 20ms */ /* Macros. */ #define THREAD_ARG(X) ((X)->arg) @@ -155,8 +160,10 @@ struct thread *funcname_thread_execute ( int (*)(struct thread *), void *, int, const char *); void thread_call (struct thread *); unsigned long thread_timer_remain_second (struct thread *); +int thread_should_yield (struct thread *); extern struct cmd_element show_thread_cpu_cmd; +extern struct cmd_element show_thread_work_queues_cmd; extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before); Index: lib/vty.c =================================================================== RCS file: /var/cvsroot/quagga/lib/vty.c,v retrieving revision 1.43 diff -u -p -b -r1.43 vty.c --- lib/vty.c 16 Apr 2005 17:11:24 -0000 1.43 +++ lib/vty.c 19 Apr 2005 17:31:36 -0000 @@ -53,7 +53,7 @@ enum event #endif /* VTYSH */ }; -static void vty_event (enum event, int, struct vty *); +static void vty_event (struct thread_master *, enum event, int, struct vty *); /* Extern host structure from command.c */ extern struct host host; @@ -312,7 +312,6 @@ vty_new () new->obuf = buffer_new(0); /* Use default buffer size. */ new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); new->max = VTY_BUFSIZ; - return new; } @@ -1334,7 +1333,7 @@ vty_read (struct thread *thread) { if (ERRNO_IO_RETRY(errno)) { - vty_event (VTY_READ, vty_sock, vty); + vty_event (thread->master, VTY_READ, vty_sock, vty); return 0; } zlog_warn("%s: read error on vty client fd %d, closing: %s", @@ -1518,8 +1517,8 @@ vty_read (struct thread *thread) vty_close (vty); else { - vty_event (VTY_WRITE, vty_sock, vty); - vty_event (VTY_READ, vty_sock, vty); + vty_event (thread->master, VTY_WRITE, vty_sock, vty); + vty_event (thread->master, VTY_READ, vty_sock, vty); } return 0; } @@ -1571,14 +1570,14 @@ vty_flush (struct thread *thread) { vty->status = VTY_NORMAL; if (vty->lines == 0) - vty_event (VTY_READ, vty_sock, vty); + vty_event (thread->master, VTY_READ, vty_sock, vty); } break; case BUFFER_PENDING: /* There is more data waiting to be written. */ vty->status = VTY_MORE; if (vty->lines == 0) - vty_event (VTY_WRITE, vty_sock, vty); + vty_event (thread->master, VTY_WRITE, vty_sock, vty); break; } @@ -1587,12 +1586,13 @@ vty_flush (struct thread *thread) /* Create new vty structure. */ static struct vty * -vty_create (int vty_sock, union sockunion *su) +vty_create (int vty_sock, union sockunion *su, struct thread_master *master) { struct vty *vty; /* Allocate new vty structure and set up default values. */ vty = vty_new (); + vty->master = master; vty->fd = vty_sock; vty->type = VTY_TERM; vty->address = sockunion_su2str (su); @@ -1651,8 +1651,8 @@ vty_create (int vty_sock, union sockunio vty_prompt (vty); /* Add read/write thread. */ - vty_event (VTY_WRITE, vty_sock, vty); - vty_event (VTY_READ, vty_sock, vty); + vty_event (vty->master, VTY_WRITE, vty_sock, vty); + vty_event (vty->master, VTY_READ, vty_sock, vty); return vty; } @@ -1673,7 +1673,7 @@ vty_accept (struct thread *thread) accept_sock = THREAD_FD (thread); /* We continue hearing vty socket. */ - vty_event (VTY_SERV, accept_sock, NULL); + vty_event (thread->master, VTY_SERV, accept_sock, NULL); memset (&su, 0, sizeof (union sockunion)); @@ -1701,7 +1701,7 @@ vty_accept (struct thread *thread) close (vty_sock); /* continue accepting connections */ - vty_event (VTY_SERV, accept_sock, NULL); + vty_event (thread->master, VTY_SERV, accept_sock, NULL); prefix_free (p); @@ -1723,7 +1723,7 @@ vty_accept (struct thread *thread) close (vty_sock); /* continue accepting connections */ - vty_event (VTY_SERV, accept_sock, NULL); + vty_event (thread->master, VTY_SERV, accept_sock, NULL); prefix_free (p); @@ -1741,14 +1741,15 @@ vty_accept (struct thread *thread) zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", safe_strerror (errno)); - vty = vty_create (vty_sock, &su); + vty = vty_create (vty_sock, &su, thread->master); return 0; } #if defined(HAVE_IPV6) && !defined(NRL) static void -vty_serv_sock_addrinfo (const char *hostname, unsigned short port) +vty_serv_sock_addrinfo (struct thread_master *master, const char *hostname, + unsigned short port) { int ret; struct addrinfo req; @@ -1804,7 +1805,7 @@ vty_serv_sock_addrinfo (const char *host continue; } - vty_event (VTY_SERV, sock, NULL); + vty_event (master, VTY_SERV, sock, NULL); } while ((ainfo = ainfo->ai_next) != NULL); @@ -1814,7 +1815,8 @@ vty_serv_sock_addrinfo (const char *host /* Make vty server socket. */ static void -vty_serv_sock_family (const char* addr, unsigned short port, int family) +vty_serv_sock_family (struct thread_master *master, const char* addr, + unsigned short port, int family) { int ret; union sockunion su; @@ -1874,7 +1876,7 @@ vty_serv_sock_family (const char* addr, } /* Add vty server event. */ - vty_event (VTY_SERV, accept_sock, NULL); + vty_event (master, VTY_SERV, accept_sock, NULL); } #ifdef VTYSH @@ -1883,7 +1885,7 @@ vty_serv_sock_family (const char* addr, /* VTY shell UNIX domain socket. */ static void -vty_serv_un (const char *path) +vty_serv_un (struct thread_master *master, const char *path) { int ret; int sock, len; @@ -1945,7 +1947,7 @@ vty_serv_un (const char *path) } } - vty_event (VTYSH_SERV, sock, NULL); + vty_event (master, VTYSH_SERV, sock, NULL); } /* #define VTYSH_DEBUG 1 */ @@ -1961,7 +1963,7 @@ vtysh_accept (struct thread *thread) accept_sock = THREAD_FD (thread); - vty_event (VTYSH_SERV, accept_sock, NULL); + vty_event (thread->master, VTYSH_SERV, accept_sock, NULL); memset (&client, 0, sizeof (struct sockaddr_un)); client_len = sizeof (struct sockaddr_un); @@ -1989,10 +1991,11 @@ vtysh_accept (struct thread *thread) vty = vty_new (); vty->fd = sock; + vty->master = thread->master; vty->type = VTY_SHELL_SERV; vty->node = VIEW_NODE; - vty_event (VTYSH_READ, sock, vty); + vty_event (thread->master, VTYSH_READ, sock, vty); return 0; } @@ -2003,7 +2006,7 @@ vtysh_flush(struct vty *vty) switch (buffer_flush_available(vty->obuf, vty->fd)) { case BUFFER_PENDING: - vty_event(VTYSH_WRITE, vty->fd, vty); + vty_event(vty->master, VTYSH_WRITE, vty->fd, vty); break; case BUFFER_ERROR: zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd); @@ -2038,7 +2041,7 @@ vtysh_read (struct thread *thread) { if (ERRNO_IO_RETRY(errno)) { - vty_event (VTYSH_READ, sock, vty); + vty_event (vty->master, VTYSH_READ, sock, vty); return 0; } zlog_warn("%s: read failed on vtysh client fd %d, closing: %s", @@ -2082,7 +2085,7 @@ vtysh_read (struct thread *thread) } } - vty_event (VTYSH_READ, sock, vty); + vty_event (thread->master, VTYSH_READ, sock, vty); return 0; } @@ -2101,7 +2104,8 @@ vtysh_write (struct thread *thread) /* Determine address family to bind. */ void -vty_serv_sock (const char *addr, unsigned short port, const char *path) +vty_serv_sock (struct thread_master *master, const char *addr, + unsigned short port, const char *path) { /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) @@ -2109,18 +2113,18 @@ vty_serv_sock (const char *addr, unsigne #ifdef HAVE_IPV6 #ifdef NRL - vty_serv_sock_family (addr, port, AF_INET); - vty_serv_sock_family (addr, port, AF_INET6); + vty_serv_sock_family (master, addr, port, AF_INET); + vty_serv_sock_family (master, addr, port, AF_INET6); #else /* ! NRL */ - vty_serv_sock_addrinfo (addr, port); + vty_serv_sock_addrinfo (master, addr, port); #endif /* NRL*/ #else /* ! HAVE_IPV6 */ - vty_serv_sock_family (addr,port, AF_INET); + vty_serv_sock_family (master, addr,port, AF_INET); #endif /* HAVE_IPV6 */ } #ifdef VTYSH - vty_serv_un (path); + vty_serv_un (master, path); #endif /* VTYSH */ } @@ -2197,6 +2201,7 @@ vty_read_file (FILE *confp) struct vty *vty; vty = vty_new (); + vty->master = NULL; vty->fd = 0; /* stdout */ vty->type = VTY_TERM; vty->node = CONFIG_NODE; @@ -2449,11 +2454,10 @@ vty_config_unlock (struct vty *vty) return vty->config; } -/* Master of the threads. */ -static struct thread_master *master; static void -vty_event (enum event event, int sock, struct vty *vty) +vty_event (struct thread_master *master, enum event event, + int sock, struct vty *vty) { struct thread *vty_serv_thread; @@ -2550,7 +2554,7 @@ exec_timeout (struct vty *vty, const cha vty_timeout_val = timeout; vty->v_timeout = timeout; - vty_event (VTY_TIMEOUT_RESET, 0, vty); + vty_event (vty->master, VTY_TIMEOUT_RESET, 0, vty); return CMD_SUCCESS; @@ -2869,14 +2873,12 @@ vty_init_vtysh () /* Install vty's own commands like `who' command. */ void -vty_init (struct thread_master *master_thread) +vty_init () { /* For further configuration read, preserve current directory. */ vty_save_cwd (); vtyvec = vector_init (VECTOR_MIN_SIZE); - - master = master_thread; /* Initilize server thread vector. */ Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); Index: lib/vty.h =================================================================== RCS file: /var/cvsroot/quagga/lib/vty.h,v retrieving revision 1.10 diff -u -p -b -r1.10 vty.h --- lib/vty.h 23 Feb 2005 15:48:32 -0000 1.10 +++ lib/vty.h 19 Apr 2005 17:31:36 -0000 @@ -29,6 +29,9 @@ Software Foundation, Inc., 59 Temple Pla /* VTY struct. */ struct vty { + /* Thread master, if any applicable, to this vty */ + struct thread_master *master; + /* File descripter of this vty. */ int fd; @@ -178,14 +181,15 @@ struct vty extern char integrate_default[]; /* Prototypes. */ -void vty_init (struct thread_master *); +void vty_init (void); void vty_init_vtysh (void); void vty_reset (void); struct vty *vty_new (void); int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); void vty_read_config (char *, char *); void vty_time_print (struct vty *, int); -void vty_serv_sock (const char *, unsigned short, const char *); +void vty_serv_sock (struct thread_master *, const char *, + unsigned short, const char *); void vty_close (struct vty *); char *vty_get_cwd (void); void vty_log (const char *level, const char *proto, const char *fmt, va_list); Index: lib/workqueue.c =================================================================== RCS file: lib/workqueue.c diff -N lib/workqueue.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/workqueue.c 19 Apr 2005 17:31:36 -0000 @@ -0,0 +1,374 @@ +/* + * Quagga Work Queue Support. + * + * Copyright (C) 2005 Sun Microsystems, Inc. + * + * This file is part of GNU Zebra. + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* master list of work_queues */ +//static struct list *work_queues = NULL; + +/* create new work queue */ +struct work_queue * +work_queue_new (struct thread_master *m, const char *queue_name) +{ + struct work_queue *new; + + new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct work_queue)); + + if (new == NULL) + return new; + + new->name = XSTRDUP (MTYPE_WORK_QUEUE_NAME, queue_name); + new->master = m; + + new->items = list_new (); + new->unused = list_new (); + + if (! (new->items && new->unused) ) + { + if (new->items) + list_free (new->items); + if (new->unused) + list_free (new->unused); + + XFREE (MTYPE_WORK_QUEUE_NAME, new->name); + XFREE (MTYPE_WORK_QUEUE, new); + + return NULL; + } + + new->items->del = (void (*)(void *)) work_queue_item_free; + new->unused->del = (void (*)(void *)) work_queue_item_free; + + listnode_add (m->queues, new); + + /* largest possible figure for the initial compare */ + new->cycles.worst = 0; + + return new; +} + +void +work_queue_free (struct work_queue *wq) +{ + /* list_delete frees items via callback */ + list_delete (wq->items); + list_delete (wq->unused); + XFREE (MTYPE_WORK_QUEUE_NAME, wq->name); + XFREE (MTYPE_WORK_QUEUE, wq); + return; +} + +struct work_queue_item * +work_queue_item_new (struct work_queue *wq) +{ + struct work_queue_item *item; + struct listnode *ln; + assert (wq); + + if (wq->unused->count > 0) + { + ln = listhead (wq->unused); + item = (struct work_queue_item *)ln->data; + list_delete_node (wq->unused, ln); /* delete only the node.. */ + } + else + { + item = XCALLOC (MTYPE_WORK_QUEUE_ITEM, + sizeof (struct work_queue_item)); + } + + return item; +} + +void +work_queue_item_free (struct work_queue_item *item) +{ + printf ("%s: free %p\n", __func__, item); + XFREE (MTYPE_WORK_QUEUE_ITEM, item); + return; +} + +void +work_queue_item_add (struct work_queue *wq, struct work_queue_item *item) +{ + /* TODO: check the work queue's delay value and factor in if this + * item is being added to an empty queue + */ + listnode_add (wq->items, item); + return; +} + +void +work_queue_item_remove (struct work_queue *wq, struct listnode *ln) +{ + struct work_queue_item *item = listgetdata (ln); + + /* call private data deletion callback if needed */ + if (wq->spec->del_item_data) + wq->spec->del_item_data (item->data); + + if (listcount (wq->unused) < 10) + { + /* attach listnode, with pointer to item in data and all, + * to the unused list + */ + LISTNODE_DETACH (wq->items, ln); + LISTNODE_ATTACH (wq->unused, ln); + memset (ln->data, 0, sizeof (struct work_queue_item)); + } + else + listnode_delete (wq->items, ln); + + return; +} + +void +work_queue_item_requeue (struct work_queue *wq, struct listnode *ln) +{ + LISTNODE_DETACH (wq->items, ln); + LISTNODE_ATTACH (wq->items, ln); /* attach to end of list */ +} + +struct work_queue_spec * +work_queue_spec_new (int npostfuncs) +{ + struct work_queue_spec *new; + + new = XCALLOC (MTYPE_WORK_QUEUE_SPEC, sizeof (struct work_queue_spec)); + if (new) + { + new->hold = WORK_QUEUE_DEFAULT_HOLD; + new->delay = WORK_QUEUE_DEFAULT_DELAY; + } + return new; +} + +void +work_queue_spec_free (struct work_queue_spec *spec) +{ + printf ("%s: free %p\n",__func__, spec); + XFREE (MTYPE_WORK_QUEUE_SPEC, spec); + return; +} + +DEFUN(show_thread_work_queues, + show_thread_work_queues_cmd, + "show work-queues", + SHOW_STR + "Work Queue information\n") +{ + struct listnode *node; + struct work_queue *wq; + struct timeval tvnow; + + gettimeofday (&tvnow, NULL); + + if (vty->master == NULL) + { + vty_out (vty, + "%% No thread-master context, cant retrieve work queue info!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + vty_out (vty, + "%13s %6s %-23s%s", + "List Counts","(ms)", "Cycle Counts ", + VTY_NEWLINE); + vty_out (vty, + "%6s %6s %6s %7s %7s %7s %s%s", + "Items","Unused", + "Delay","Best","Worst","Avg.", + "Name", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (vty->master->queues, node, wq)) + { + unsigned long ms; + struct timeval tv; +#if 0 + zlog_info ("show: now %lds %ldsu, next: %lds %ldsu", + tvnow.tv_sec, tvnow.tv_usec, + wq->timers.nextrun.tv_sec, wq->timers.nextrun.tv_usec); +#endif + tv = timeval_subtract (wq->nextrun, tvnow); +#if 0 + zlog_info ("show: tv: %lds %ldsu", tv.tv_sec, tv.tv_usec); +#endif + ms = (tv.tv_sec*1000L) + (tv.tv_usec/1000L); + vty_out (vty,"%6d %6d %6ld %7d %7d %7d %s%s", + listcount (wq->items), + listcount (wq->unused), + ms, + wq->cycles.best, + wq->cycles.worst, + wq->cycles.avg, + wq->name, + VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* timer thread to process a work queue + * will reschedule itself if required, + * otherwise work_queue_item_add + */ +int +work_queue_run (struct thread *thread) +{ + struct work_queue *wq; + struct work_queue_item *item; + wq_item_status ret; + unsigned int granularity, cycles = 0; + struct listnode *node, *nnode; + char yielded = 0; + + wq = THREAD_ARG (thread); + + assert (wq && wq->items); + + /* calculate cycle granularity: + * list iteration == 1 cycle + * granularity == # cycles between checks whether we should yield. + * worst == likely worst case cycle/time-slot count, as determined + * by recent history. + * + * granularity should be << than cycles.worst (eg 1/4th of) or else + * WORK_QUEUE_GRANULARITY_MIN, and no greater than THREAD_YIELD_TIME_SLOT. + * + * cycles.worst can increase slowly after each run to provide some + * hysteris, but not past cycles.best. + * + * Best: starts low, can only increase + * Worst: starts high, can be decreased if we run to end of time slot + * can increase otherwise. + * + * We could use just the average and save some work, however we want to be + * able to adjust quickly to CPU pressure. Average wont shift much if + * daemon has been running a long time. + */ + if ( (granularity = (wq->cycles.worst >> 2)) + < WORK_QUEUE_GRANULARITY_MIN) + granularity = WORK_QUEUE_GRANULARITY_MIN; + + for (ALL_LIST_ELEMENTS (wq->items, node, nnode, item)) + { + /* dont run items which are past their allowed retries */ + if (item->retry_count >= wq->spec->max_retries) + { + /* run error handler, if any */ + if (wq->spec->errorfunc) + wq->spec->errorfunc (wq, item); + work_queue_item_remove (wq, node); + continue; + } + + /* run and take care of items that want to be retried immediately */ + do + { + ret = wq->spec->workfunc (item->data); + item->retry_count++; + } + while ((ret == WQ_RETRY_NOW) + && (item->retry_count < wq->spec->max_retries)); + + switch (ret) + { + case WQ_RETRY_LATER: + { + item->retry_count++; + goto stats; + } + case WQ_REQUEUE: + { + item->retry_count++; + work_queue_item_requeue (wq, node); + break; + } + case WQ_RETRY_NOW: + case WQ_ERROR: + { + if (wq->spec->errorfunc) + wq->spec->errorfunc (wq, item); + } + /* fall through here is deliberate */ + case WQ_SUCCESS: + default: + { + work_queue_item_remove (wq, node); + break; + } + } + + /* completed cycle */ + cycles++; + + /* test if we should yield */ + if (!(cycles % granularity) && thread_should_yield (thread)) + { + yielded = 1; + goto stats; + } + } + +stats: + + /* We didn't do our worst, check for best, and potentially + * bump worst up a bit + */ + if (cycles > wq->cycles.worst) + { + if (cycles > wq->cycles.best) + wq->cycles.best = cycles; + + /* hysteris for worst */ + if ( (wq->cycles.best / 2) > wq->cycles.worst) + wq->cycles.worst = wq->cycles.worst * 2; + } + + /* Rolling average: + * avg(n,x,y) = ((n-1)x+y)/n, + * x = previous average, y = new value, n = total # of values + * + * It's an interesting statistic, but not of functional use. + * could be removed to save runtime. + */ + wq->cycles.avg = ((wq->runs * wq->cycles.avg) + cycles) / (++(wq->runs)); + + gettimeofday (&wq->nextrun, NULL); + + if (wq->spec->delay) + { + wq->nextrun.tv_usec += (wq->spec->delay * 1000L); + timeval_adjust (wq->nextrun); + } + + return 0; +} Index: lib/workqueue.h =================================================================== RCS file: lib/workqueue.h diff -N lib/workqueue.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/workqueue.h 19 Apr 2005 17:31:36 -0000 @@ -0,0 +1,104 @@ +/* + * Quagga Work Queues. + * + * Copyright (C) 2005 Sun Microsystems, Inc. + * + * This file is part of Quagga. + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _QUAGGA_WORK_QUEUE_H +#define _QUAGGA_WORK_QUEUE_H + +/* Work queue default cycle granularities */ +#define WORK_QUEUE_GRANULARITY_MIN 5 /* minimum items to process */ +#define WORK_QUEUE_GRANULARITY_DEFAULT 100 + +/* Work queue default hold and cycle times - millisec */ +#define WORK_QUEUE_DEFAULT_HOLD 100 /* hold time for initial run of a queue */ +#define WORK_QUEUE_DEFAULT_DELAY 10 /* minimum delay between queue runs */ + +/* action value, for use by item processor and item error handlers */ +typedef enum +{ + WQ_SUCCESS = 0, + WQ_ERROR, /* Error, run error handler if provided */ + WQ_RETRY_NOW, /* retry immediately */ + WQ_RETRY_LATER, /* retry later, cease processing work queue */ + WQ_REQUEUE /* requeue item, continue processing work queue */ +} wq_item_status; + +/* A single work queue item, unsurprisingly */ +struct work_queue_item +{ + void *data; /* opaque data */ + unsigned short retry_count; /* number of times retried */ +}; + +struct work_queue +{ + struct thread_master *master; /* thread master */ + char *name; /* work queue name */ + struct work_queue_spec *spec; /* specification for this work queue */ + + /* remaining fields should be opaque to users */ + struct list *items; /* queue item list */ + struct list *unused; /* reuseable q item list */ + + unsigned int runs; /* runs count */ + struct timeval nextrun; /* next run time */ + + struct { + unsigned int best; + unsigned int worst; + unsigned int avg; + } cycles; /* cycle counts */ +}; + +struct work_queue_spec +{ + /* work function to process items with */ + wq_item_status (*workfunc) (void *); + + /* error handling function, optional */ + void (*errorfunc) (struct work_queue *, struct work_queue_item *); + + /* callback to delete user specific item data */ + void (*del_item_data) (void *); + + /* max number of retries to make for item that errors */ + unsigned int max_retries; + + unsigned int hold; /* hold time for first run */ + unsigned int delay; /* min ms delay between queue runs*/ +}; + +/* User API */ +struct work_queue *work_queue_new (struct thread_master *, const char *); +void work_queue_free (struct work_queue *); +struct work_queue_item *work_queue_item_new (struct work_queue *); +void work_queue_item_free (struct work_queue_item *); +void work_queue_item_add (struct work_queue *, struct work_queue_item *); +void work_queue_item_requeue (struct work_queue *, struct listnode *); +void work_queue_item_remove (struct work_queue *, struct listnode *); +struct work_queue_spec *work_queue_spec_new (); +void work_queue_spec_free (struct work_queue_spec *); + +/* Helpers, exported for thread.c and command.c */ +int work_queue_run (struct thread *); +extern struct cmd_element show_work_queues_cmd; +#endif /* _QUAGGA_WORK_QUEUE_H */ Index: lib/zebra.h =================================================================== RCS file: /var/cvsroot/quagga/lib/zebra.h,v retrieving revision 1.33 diff -u -p -b -r1.33 zebra.h --- lib/zebra.h 8 Apr 2005 16:42:03 -0000 1.33 +++ lib/zebra.h 19 Apr 2005 17:31:37 -0000 @@ -29,6 +29,10 @@ Software Foundation, Inc., 59 Temple Pla #define _GNU_SOURCE #endif /* GNU_LINUX */ +#ifdef DMALLOC +#include +#endif /* DMALLOC */ + #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ @@ -46,6 +50,7 @@ typedef int socklen_t; #include #include #include +#include #include #include #include @@ -58,8 +63,8 @@ typedef int socklen_t; #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ -#include #include +#include #include #include #ifdef HAVE_SYS_SYSCTL_H Index: ospf6d/ospf6_main.c =================================================================== RCS file: /var/cvsroot/quagga/ospf6d/ospf6_main.c,v retrieving revision 1.19 diff -u -p -b -r1.19 ospf6_main.c --- ospf6d/ospf6_main.c 7 Dec 2004 15:39:32 -0000 1.19 +++ ospf6d/ospf6_main.c 19 Apr 2005 17:31:37 -0000 @@ -256,7 +256,7 @@ main (int argc, char *argv[], char *envp /* initialize zebra libraries */ signal_init (master, Q_SIGC(ospf6_signals), ospf6_signals); cmd_init (1); - vty_init (master); + vty_init (); memory_init (); if_init (); access_list_init (); @@ -280,7 +280,7 @@ main (int argc, char *argv[], char *envp /* Make ospf6 vty socket. */ if (!vty_port) vty_port = OSPF6_VTY_PORT; - vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, OSPF6_VTYSH_PATH); /* Print start message */ zlog_notice ("OSPF6d (Quagga-%s ospf6d-%s) starts: vty@%d", Index: ospfclient/Makefile.am =================================================================== RCS file: /var/cvsroot/quagga/ospfclient/Makefile.am,v retrieving revision 1.6 diff -u -p -b -r1.6 Makefile.am --- ospfclient/Makefile.am 23 Jul 2004 16:23:56 -0000 1.6 +++ ospfclient/Makefile.am 19 Apr 2005 17:31:37 -0000 @@ -1,6 +1,6 @@ ## Automake.am for OSPF API client -INCLUDES = -I../lib -I../ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version 0:0:0 Index: ospfd/ospf_main.c =================================================================== RCS file: /var/cvsroot/quagga/ospfd/ospf_main.c,v retrieving revision 1.22 diff -u -p -b -r1.22 ospf_main.c --- ospfd/ospf_main.c 7 Dec 2004 15:39:32 -0000 1.22 +++ ospfd/ospf_main.c 19 Apr 2005 17:31:37 -0000 @@ -280,7 +280,7 @@ main (int argc, char **argv) signal_init (master, Q_SIGC(ospf_signals), ospf_signals); cmd_init (1); debug_init (); - vty_init (master); + vty_init (); memory_init (); access_list_init (); @@ -315,7 +315,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Create VTY socket */ - vty_serv_sock (vty_addr, vty_port, OSPF_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, OSPF_VTYSH_PATH); /* Print banner. */ zlog_notice ("OSPFd %s starting: vty@%d", QUAGGA_VERSION, vty_port); Index: ripd/rip_main.c =================================================================== RCS file: /var/cvsroot/quagga/ripd/rip_main.c,v retrieving revision 1.15 diff -u -p -b -r1.15 rip_main.c --- ripd/rip_main.c 7 Dec 2004 15:39:33 -0000 1.15 +++ ripd/rip_main.c 19 Apr 2005 17:31:37 -0000 @@ -135,7 +135,7 @@ sighup (void) vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, RIP_VTYSH_PATH); /* Try to return to normal operation. */ } @@ -264,7 +264,7 @@ main (int argc, char **argv) zprivs_init (&ripd_privs); signal_init (master, Q_SIGC(ripd_signals), ripd_signals); cmd_init (1); - vty_init (master); + vty_init (); memory_init (); keychain_init (); @@ -288,7 +288,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, RIP_VTYSH_PATH); /* Print banner. */ zlog_notice ("RIPd %s starting: vty@%d", QUAGGA_VERSION, vty_port); Index: ripngd/ripng_main.c =================================================================== RCS file: /var/cvsroot/quagga/ripngd/ripng_main.c,v retrieving revision 1.15 diff -u -p -b -r1.15 ripng_main.c --- ripngd/ripng_main.c 7 Dec 2004 15:39:33 -0000 1.15 +++ ripngd/ripng_main.c 19 Apr 2005 17:31:37 -0000 @@ -137,7 +137,7 @@ sighup (void) /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Try to return to normal operation. */ } @@ -267,7 +267,7 @@ main (int argc, char **argv) zprivs_init (&ripngd_privs); signal_init (master, Q_SIGC(ripng_signals), ripng_signals); cmd_init (1); - vty_init (master); + vty_init (); memory_init (); /* RIPngd inits. */ @@ -286,7 +286,7 @@ main (int argc, char **argv) daemon (0, 0); /* Create VTY socket */ - vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); + vty_serv_sock (master, vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Process id file create. */ pid_output (pid_file); Index: solaris/Makefile.am =================================================================== RCS file: /var/cvsroot/quagga/solaris/Makefile.am,v retrieving revision 1.3 diff -u -p -b -r1.3 Makefile.am --- solaris/Makefile.am 13 Apr 2005 03:37:23 -0000 1.3 +++ solaris/Makefile.am 19 Apr 2005 17:31:37 -0000 @@ -71,7 +71,7 @@ pkginfo.%.tmpl: $(srcdir)/pkginfo.%.tmpl rm -f $@ $(edit) $< > $@ -pkginfo.%.full: $(srcdir)/pkginfo.%.tmpl pkginfo.tmpl Makefile +pkginfo.%.full: pkginfo.%.tmpl pkginfo.tmpl Makefile cat pkginfo.tmpl pkginfo.$*.tmpl > $@ # use 'edit' above to transform prototype.in to pkgmk acceptable prototype Index: tests/Makefile.am =================================================================== RCS file: /var/cvsroot/quagga/tests/Makefile.am,v retrieving revision 1.2 diff -u -p -b -r1.2 Makefile.am --- tests/Makefile.am 13 Apr 2005 03:31:35 -0000 1.2 +++ tests/Makefile.am 19 Apr 2005 17:31:37 -0000 @@ -1,12 +1,15 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" -noinst_PROGRAMS = testsig testbuffer testmemory +noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c +heavy_SOURCES = heavy.c +heavywq_SOURCES = heavy-wq.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ - +heavy_LDADD = ../lib/libzebra.la @LIBCAP@ +heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ Index: zebra/main.c =================================================================== RCS file: /var/cvsroot/quagga/zebra/main.c,v retrieving revision 1.21 diff -u -p -b -r1.21 main.c --- zebra/main.c 16 Jan 2005 23:34:02 -0000 1.21 +++ zebra/main.c 19 Apr 2005 17:31:37 -0000 @@ -311,7 +311,7 @@ main (int argc, char **argv) /* Vty related initialize. */ signal_init (zebrad.master, Q_SIGC(zebra_signals), zebra_signals); cmd_init (1); - vty_init (zebrad.master); + vty_init (); memory_init (); /* Zebra related initialize. */ @@ -370,7 +370,7 @@ main (int argc, char **argv) pid = getpid (); /* Make vty server socket. */ - vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); + vty_serv_sock (zebrad.master, vty_addr, vty_port, ZEBRA_VTYSH_PATH); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); Index: zebra/rib.h =================================================================== RCS file: /var/cvsroot/quagga/zebra/rib.h,v retrieving revision 1.5 diff -u -p -b -r1.5 rib.h --- zebra/rib.h 12 Oct 2004 20:50:58 -0000 1.5 +++ zebra/rib.h 19 Apr 2005 17:31:38 -0000 @@ -32,6 +32,9 @@ struct rib struct rib *next; struct rib *prev; + /* ref count */ + unsigned int lock; + /* Type fo this route. */ int type; @@ -232,6 +235,8 @@ void rib_update (); void rib_sweep_route (); void rib_close (); void rib_init (); +extern void rib_lock (struct rib *); +extern void rib_unlock (struct rib *); int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, Index: zebra/zserv.c =================================================================== RCS file: /var/cvsroot/quagga/zebra/zserv.c,v retrieving revision 1.29 diff -u -p -b -r1.29 zserv.c --- zebra/zserv.c 10 Apr 2005 15:01:56 -0000 1.29 +++ zebra/zserv.c 19 Apr 2005 17:31:38 -0000 @@ -780,10 +780,11 @@ zread_ipv4_add (struct zserv *client, u_ s = client->ibuf; /* Allocate new rib. */ - rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); memset (rib, 0, sizeof (struct rib)); /* Type, flags, message. */ + rib->lock++; rib->type = stream_getc (s); rib->flags = stream_getc (s); message = stream_getc (s); Index: zebra/zserv.h =================================================================== RCS file: /var/cvsroot/quagga/zebra/zserv.h,v retrieving revision 1.9 diff -u -p -b -r1.9 zserv.h --- zebra/zserv.h 28 Feb 2005 20:52:15 -0000 1.9 +++ zebra/zserv.h 19 Apr 2005 17:31:38 -0000 @@ -31,6 +31,12 @@ /* Default configuration filename. */ #define DEFAULT_CONFIG_FILE "zebra.conf" +struct zebra_queue_node_t +{ + struct route_node *node; + struct rib *del; +}; + /* Client structure. */ struct zserv { @@ -77,6 +83,8 @@ struct zebra_t /* default table */ int rtm_table_default; + /* rib work queue */ + struct work_queue *ribq; }; /* Count prefix size from mask length */