mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 11:25:41 +00:00
2005-04-25 Paul Jakma <paul.jakma@sun.com>
* workqueue.{c,h}: Helper API for setting up and running queues via background threads. * command.c: install the 'show workqueues' command * memtypes.c: Add work queue mtypes, and a rib-queue type for a zebra rib work queue. * memtypes.h: Updated to match memtypes.c * Makefile.am: Add new workqueue files to build.
This commit is contained in:
parent
b64d92a8a8
commit
354d119a65
@ -12,7 +12,7 @@ libzebra_la_SOURCES = \
|
|||||||
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
|
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 \
|
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 \
|
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
|
||||||
|
|
||||||
BUILT_SOURCES = memtypes.h
|
BUILT_SOURCES = memtypes.h
|
||||||
|
|
||||||
@ -25,7 +25,8 @@ pkginclude_HEADERS = \
|
|||||||
memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
|
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 \
|
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 \
|
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
|
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
|
||||||
|
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h workqueue.h
|
||||||
|
|
||||||
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk
|
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
$Id: command.c,v 1.46 2005/03/14 20:19:01 paul Exp $
|
$Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $
|
||||||
|
|
||||||
Command interpreter routine for virtual terminal [aka TeletYpe]
|
Command interpreter routine for virtual terminal [aka TeletYpe]
|
||||||
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
|
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
|
||||||
@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "vty.h"
|
#include "vty.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "workqueue.h"
|
||||||
|
|
||||||
/* Command vector which includes some level of command lists. Normally
|
/* Command vector which includes some level of command lists. Normally
|
||||||
each daemon maintains each own cmdvec. */
|
each daemon maintains each own cmdvec. */
|
||||||
@ -3578,8 +3579,10 @@ cmd_init (int terminal)
|
|||||||
install_element (CONFIG_NODE, &service_terminal_length_cmd);
|
install_element (CONFIG_NODE, &service_terminal_length_cmd);
|
||||||
install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
|
install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
|
||||||
|
|
||||||
install_element(VIEW_NODE, &show_thread_cpu_cmd);
|
install_element (VIEW_NODE, &show_thread_cpu_cmd);
|
||||||
install_element(ENABLE_NODE, &show_thread_cpu_cmd);
|
install_element (ENABLE_NODE, &show_thread_cpu_cmd);
|
||||||
|
install_element (VIEW_NODE, &show_work_queues_cmd);
|
||||||
|
install_element (ENABLE_NODE, &show_work_queues_cmd);
|
||||||
}
|
}
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* The script is sensitive to the format (though not whitespace), see
|
* The script is sensitive to the format (though not whitespace), see
|
||||||
* the top of memtypes.awk for more details.
|
* the top of memtypes.awk for more details.
|
||||||
*
|
*
|
||||||
* $Id: memtypes.c,v 1.3 2005/04/25 14:02:44 paul Exp $
|
* $Id: memtypes.c,v 1.4 2005/04/25 16:26:43 paul Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zebra.h"
|
#include "zebra.h"
|
||||||
@ -64,6 +64,9 @@ struct memory_list memory_list_lib[] =
|
|||||||
{ MTYPE_PRIVS, "Privilege information" },
|
{ MTYPE_PRIVS, "Privilege information" },
|
||||||
{ MTYPE_ZLOG, "Logging" },
|
{ MTYPE_ZLOG, "Logging" },
|
||||||
{ MTYPE_ZCLIENT, "Zclient" },
|
{ MTYPE_ZCLIENT, "Zclient" },
|
||||||
|
{ MTYPE_WORK_QUEUE, "Work queue" },
|
||||||
|
{ MTYPE_WORK_QUEUE_ITEM, "Work queue item" },
|
||||||
|
{ MTYPE_WORK_QUEUE_NAME, "Work queue name string" },
|
||||||
{ -1, NULL },
|
{ -1, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ struct memory_list memory_list_zebra[] =
|
|||||||
{ MTYPE_VRF_NAME, "VRF name" },
|
{ MTYPE_VRF_NAME, "VRF name" },
|
||||||
{ MTYPE_NEXTHOP, "Nexthop" },
|
{ MTYPE_NEXTHOP, "Nexthop" },
|
||||||
{ MTYPE_RIB, "RIB" },
|
{ MTYPE_RIB, "RIB" },
|
||||||
|
{ MTYPE_RIB_QUEUE, "RIB process work queue" },
|
||||||
{ MTYPE_STATIC_IPV4, "Static IPv4 route" },
|
{ MTYPE_STATIC_IPV4, "Static IPv4 route" },
|
||||||
{ MTYPE_STATIC_IPV6, "Static IPv6 route" },
|
{ MTYPE_STATIC_IPV6, "Static IPv6 route" },
|
||||||
{ -1, NULL },
|
{ -1, NULL },
|
||||||
|
@ -56,11 +56,16 @@ enum
|
|||||||
MTYPE_PRIVS,
|
MTYPE_PRIVS,
|
||||||
MTYPE_ZLOG,
|
MTYPE_ZLOG,
|
||||||
MTYPE_ZCLIENT,
|
MTYPE_ZCLIENT,
|
||||||
|
MTYPE_WORK_QUEUE,
|
||||||
|
MTYPE_WORK_QUEUE_ITEM,
|
||||||
|
MTYPE_WORK_QUEUE_NAME,
|
||||||
|
MTYPE_WORK_QUEUE_SPEC,
|
||||||
MTYPE_RTADV_PREFIX,
|
MTYPE_RTADV_PREFIX,
|
||||||
MTYPE_VRF,
|
MTYPE_VRF,
|
||||||
MTYPE_VRF_NAME,
|
MTYPE_VRF_NAME,
|
||||||
MTYPE_NEXTHOP,
|
MTYPE_NEXTHOP,
|
||||||
MTYPE_RIB,
|
MTYPE_RIB,
|
||||||
|
MTYPE_RIB_QUEUE,
|
||||||
MTYPE_STATIC_IPV4,
|
MTYPE_STATIC_IPV4,
|
||||||
MTYPE_STATIC_IPV6,
|
MTYPE_STATIC_IPV6,
|
||||||
MTYPE_BGP,
|
MTYPE_BGP,
|
||||||
|
329
lib/workqueue.c
Normal file
329
lib/workqueue.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* 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 <lib/zebra.h>
|
||||||
|
#include "thread.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "workqueue.h"
|
||||||
|
#include "linklist.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/* master list of work_queues */
|
||||||
|
static struct list work_queues;
|
||||||
|
|
||||||
|
#define WORK_QUEUE_MIN_GRANULARITY 1
|
||||||
|
|
||||||
|
static struct work_queue_item *
|
||||||
|
work_queue_item_new (struct work_queue *wq)
|
||||||
|
{
|
||||||
|
struct work_queue_item *item;
|
||||||
|
assert (wq);
|
||||||
|
|
||||||
|
item = XCALLOC (MTYPE_WORK_QUEUE_ITEM,
|
||||||
|
sizeof (struct work_queue_item));
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
work_queue_item_free (struct work_queue_item *item)
|
||||||
|
{
|
||||||
|
XFREE (MTYPE_WORK_QUEUE_ITEM, item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
if ( (new->items = list_new ()) == NULL)
|
||||||
|
{
|
||||||
|
if (new->items)
|
||||||
|
list_free (new->items);
|
||||||
|
|
||||||
|
XFREE (MTYPE_WORK_QUEUE_NAME, new->name);
|
||||||
|
XFREE (MTYPE_WORK_QUEUE, new);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->items->del = (void (*)(void *)) work_queue_item_free;
|
||||||
|
|
||||||
|
listnode_add (&work_queues, new);
|
||||||
|
|
||||||
|
new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
work_queue_free (struct work_queue *wq)
|
||||||
|
{
|
||||||
|
/* list_delete frees items via callback */
|
||||||
|
list_delete (wq->items);
|
||||||
|
listnode_delete (&work_queues, wq);
|
||||||
|
|
||||||
|
XFREE (MTYPE_WORK_QUEUE_NAME, wq->name);
|
||||||
|
XFREE (MTYPE_WORK_QUEUE, wq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
work_queue_add (struct work_queue *wq, void *data)
|
||||||
|
{
|
||||||
|
struct work_queue_item *item;
|
||||||
|
|
||||||
|
assert (wq);
|
||||||
|
|
||||||
|
if (!(item = work_queue_item_new (wq)))
|
||||||
|
{
|
||||||
|
zlog_err ("%s: unable to get new queue item", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->data = data;
|
||||||
|
listnode_add (wq->items, item);
|
||||||
|
|
||||||
|
/* if thread isnt already waiting, add one */
|
||||||
|
if (wq->thread == NULL)
|
||||||
|
wq->thread = thread_add_background (wq->master, work_queue_run,
|
||||||
|
wq, wq->spec.hold);
|
||||||
|
|
||||||
|
/* XXX: what if we didnt get a thread? try again? */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
work_queue_item_remove (struct work_queue *wq, struct listnode *ln)
|
||||||
|
{
|
||||||
|
struct work_queue_item *item = listgetdata (ln);
|
||||||
|
|
||||||
|
assert (item && item->data);
|
||||||
|
|
||||||
|
/* call private data deletion callback if needed */
|
||||||
|
if (wq->spec.del_item_data)
|
||||||
|
wq->spec.del_item_data (item->data);
|
||||||
|
|
||||||
|
list_delete_node (wq->items, ln);
|
||||||
|
work_queue_item_free (item);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(show_work_queues,
|
||||||
|
show_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);
|
||||||
|
|
||||||
|
vty_out (vty,
|
||||||
|
"%8s %11s %8s %21s%s",
|
||||||
|
"List","(ms) ","Q. Runs","Cycle Counts ",
|
||||||
|
VTY_NEWLINE);
|
||||||
|
vty_out (vty,
|
||||||
|
"%8s %5s %5s %8s %7s %6s %6s %s%s",
|
||||||
|
"Items",
|
||||||
|
"Delay","Hold",
|
||||||
|
"Total",
|
||||||
|
"Best","Gran.","Avg.",
|
||||||
|
"Name",
|
||||||
|
VTY_NEWLINE);
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO ((&work_queues), node, wq))
|
||||||
|
{
|
||||||
|
vty_out (vty,"%8d %5d %5d %8ld %7d %6d %6u %s%s",
|
||||||
|
listcount (wq->items),
|
||||||
|
wq->spec.delay, wq->spec.hold,
|
||||||
|
wq->runs,
|
||||||
|
wq->cycles.best, wq->cycles.granularity,
|
||||||
|
(unsigned int)(wq->cycles.total / wq->runs),
|
||||||
|
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 cycles = 0;
|
||||||
|
struct listnode *node, *nnode;
|
||||||
|
char yielded = 0;
|
||||||
|
|
||||||
|
wq = THREAD_ARG (thread);
|
||||||
|
wq->thread = NULL;
|
||||||
|
|
||||||
|
assert (wq && wq->items);
|
||||||
|
|
||||||
|
/* calculate cycle granularity:
|
||||||
|
* list iteration == 1 cycle
|
||||||
|
* granularity == # cycles between checks whether we should yield.
|
||||||
|
*
|
||||||
|
* granularity should be > 0, and can increase slowly after each run to
|
||||||
|
* provide some hysteris, but not past cycles.best or 2*cycles.
|
||||||
|
*
|
||||||
|
* Best: starts low, can only increase
|
||||||
|
*
|
||||||
|
* Granularity: starts at WORK_QUEUE_MIN_GRANULARITY, can be decreased if we run to end of time
|
||||||
|
* slot, can increase otherwise by a small factor.
|
||||||
|
*
|
||||||
|
* 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 (wq->cycles.granularity == 0)
|
||||||
|
wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS (wq->items, node, nnode, item))
|
||||||
|
{
|
||||||
|
assert (item && item->data);
|
||||||
|
|
||||||
|
/* 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->data);
|
||||||
|
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 % wq->cycles.granularity)
|
||||||
|
&& thread_should_yield (thread))
|
||||||
|
{
|
||||||
|
yielded = 1;
|
||||||
|
goto stats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stats:
|
||||||
|
|
||||||
|
#define WQ_HYSTERIS_FACTOR 2
|
||||||
|
|
||||||
|
/* we yielded, check whether granularity should be reduced */
|
||||||
|
if (yielded && (cycles < wq->cycles.granularity))
|
||||||
|
{
|
||||||
|
wq->cycles.granularity = ((cycles > 0) ? cycles
|
||||||
|
: WORK_QUEUE_MIN_GRANULARITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cycles > (wq->cycles.granularity))
|
||||||
|
{
|
||||||
|
if (cycles > wq->cycles.best)
|
||||||
|
wq->cycles.best = cycles;
|
||||||
|
|
||||||
|
/* along with yielded check, provides hysteris for granularity */
|
||||||
|
if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR))
|
||||||
|
wq->cycles.granularity += WQ_HYSTERIS_FACTOR;
|
||||||
|
}
|
||||||
|
#undef WQ_HYSTERIS_FACTOR
|
||||||
|
|
||||||
|
wq->runs++;
|
||||||
|
wq->cycles.total += cycles;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf ("%s: cycles %d, new: best %d, worst %d\n",
|
||||||
|
__func__, cycles, wq->cycles.best, wq->cycles.granularity);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Is the queue done yet? */
|
||||||
|
if (listcount (wq->items) > 0)
|
||||||
|
wq->thread = thread_add_background (wq->master, work_queue_run, wq,
|
||||||
|
wq->spec.delay);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
91
lib/workqueue.h
Normal file
91
lib/workqueue.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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 hold and cycle times - millisec */
|
||||||
|
#define WORK_QUEUE_DEFAULT_HOLD 50 /* 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 */
|
||||||
|
struct thread *thread; /* thread, if one is active */
|
||||||
|
char *name; /* work queue name */
|
||||||
|
|
||||||
|
/* specification for this work queue */
|
||||||
|
struct {
|
||||||
|
/* 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, in ms */
|
||||||
|
unsigned int delay; /* min delay between queue runs, in ms */
|
||||||
|
} spec;
|
||||||
|
|
||||||
|
/* remaining fields should be opaque to users */
|
||||||
|
struct list *items; /* queue item list */
|
||||||
|
unsigned long runs; /* runs count */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int best;
|
||||||
|
unsigned int granularity;
|
||||||
|
unsigned long total;
|
||||||
|
} cycles; /* cycle counts */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* User API */
|
||||||
|
struct work_queue *work_queue_new (struct thread_master *, const char *);
|
||||||
|
void work_queue_free (struct work_queue *);
|
||||||
|
void work_queue_add (struct work_queue *, void *);
|
||||||
|
|
||||||
|
/* 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 */
|
Loading…
Reference in New Issue
Block a user