lib: Add Timer Wheel functionality

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2016-11-02 19:03:29 -04:00
parent d67f268e94
commit 1de1c5bed3
3 changed files with 236 additions and 2 deletions

View File

@ -24,7 +24,7 @@ libzebra_la_SOURCES = \
sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
imsg-buffer.c imsg.c skiplist.c \
qobj.c \
qobj.c wheel.c \
event_counter.c \
strlcpy.c \
strlcat.c
@ -45,7 +45,7 @@ pkginclude_HEADERS = \
workqueue.h route_types.h libospf.h nexthop.h json.h \
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
skiplist.h qobj.h \
skiplist.h qobj.h wheel.h \
event_counter.h
noinst_HEADERS = \

164
lib/wheel.c Normal file
View File

@ -0,0 +1,164 @@
/*
* Timer Wheel
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "zebra.h"
#include "linklist.h"
#include "thread.h"
#include "memory.h"
#include "wheel.h"
#include "log.h"
DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel")
DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List")
static int debug_timer_wheel = 1;
static int
wheel_timer_thread (struct thread *t)
{
struct listnode *node, *nextnode;
unsigned long long curr_slot;
unsigned int slots_to_skip = 1;
struct timer_wheel *wheel;
void *data;
wheel = THREAD_ARG(t);
THREAD_OFF(wheel->timer);
wheel->curr_slot += wheel->slots_to_skip;
curr_slot = wheel->curr_slot % wheel->slots;
if (debug_timer_wheel)
zlog_debug ("%s: Wheel Slot: %lld(%lld) count: %d",
__PRETTY_FUNCTION__,
wheel->curr_slot,
curr_slot, listcount(wheel->wheel_slot_lists[curr_slot]));
for (ALL_LIST_ELEMENTS (wheel->wheel_slot_lists[curr_slot], node, nextnode, data))
(*wheel->slot_run)(data);
while (list_isempty(wheel->wheel_slot_lists[(curr_slot + slots_to_skip) % wheel->slots]) &&
(curr_slot + slots_to_skip ) % wheel->slots != curr_slot)
slots_to_skip++;
wheel->slots_to_skip = slots_to_skip;
THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
wheel_timer_thread, wheel,
wheel->nexttime * slots_to_skip);
return 0;
}
struct timer_wheel *
wheel_init (struct thread_master *master, int period, size_t slots,
unsigned int (*slot_key) (void *),
void (*slot_run) (void *))
{
struct timer_wheel *wheel;
size_t i;
wheel = XCALLOC(MTYPE_TIMER_WHEEL, sizeof (struct timer_wheel));
wheel->slot_key = slot_key;
wheel->slot_run = slot_run;
wheel->period = period;
wheel->slots = slots;
wheel->curr_slot = 0;
wheel->master = master;
wheel->nexttime = period / slots;
wheel->wheel_slot_lists = XCALLOC(MTYPE_TIMER_WHEEL_LIST,
slots * sizeof (struct listnode *));
for (i = 0; i < slots; i++)
wheel->wheel_slot_lists[i] = list_new ();
THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
wheel_timer_thread, wheel,
wheel->nexttime);
return wheel;
}
void
wheel_delete (struct timer_wheel *wheel)
{
int i;
for (i = 0; i < wheel->slots; i++)
{
list_delete(wheel->wheel_slot_lists[i]);
}
THREAD_OFF(wheel->timer);
XFREE(MTYPE_TIMER_WHEEL_LIST, wheel->wheel_slot_lists);
XFREE(MTYPE_TIMER_WHEEL, wheel);
}
int
wheel_stop (struct timer_wheel *wheel)
{
THREAD_OFF(wheel->timer);
return 0;
}
int
wheel_start (struct timer_wheel *wheel)
{
if (!wheel->timer)
THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
wheel_timer_thread, wheel,
wheel->nexttime);
return 0;
}
int
wheel_add_item (struct timer_wheel *wheel, void *item)
{
long long slot;
slot = (*wheel->slot_key)(item);
if (debug_timer_wheel)
zlog_debug ("%s: Inserting %p: %lld %lld",
__PRETTY_FUNCTION__, item,
slot, slot % wheel->slots);
listnode_add (wheel->wheel_slot_lists[slot % wheel->slots], item);
return 0;
}
int
wheel_remove_item (struct timer_wheel *wheel, void *item)
{
long long slot;
slot = (*wheel->slot_key)(item);
if (debug_timer_wheel)
zlog_debug ("%s: Removing %p: %lld %lld",
__PRETTY_FUNCTION__, item,
slot, slot % wheel->slots);
listnode_delete (wheel->wheel_slot_lists[slot % wheel->slots], item);
return 0;
}

70
lib/wheel.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Timer Wheel
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; see the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef __WHEEL_H__
#define __WHEEL_H__
struct timer_wheel
{
struct thread_master *master;
int slots;
long long curr_slot;
unsigned int period;
unsigned int nexttime;
unsigned int slots_to_skip;
struct list **wheel_slot_lists;
struct thread *timer;
/*
* Key to determine what slot the item belongs in
*/
unsigned int (*slot_key) (void *);
void (*slot_run) (void *);
};
struct timer_wheel *wheel_init (struct thread_master *master, int period, size_t slots,
unsigned int (*slot_key) (void *),
void (*slot_run) (void *));
void wheel_delete (struct timer_wheel *);
/*
* Pause the Wheel from running
*/
int wheel_stop (struct timer_wheel *wheel);
/*
* Start the wheel from running again
*/
int wheel_start (struct timer_wheel *wheel);
/*
* Add item to a slot setup by the slot_key,
* possibly change next time pop.
*/
int wheel_add_item (struct timer_wheel *wheel, void *item);
/*
* Remove a item to a slot setup by the slot_key,
* possibly change next time pop.
*/
int wheel_remove_item (struct timer_wheel *wheel, void *item);
#endif