From 6d5aeb7cddb344d335eb6f36d822ce57d4c7625d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 2 Sep 2009 19:49:58 +0000 Subject: [PATCH] Cleaned up scheduled events handling code. * Fixed pri_schedule_event() to return 0 on error instead of -1. Zero is a safer value to return. Users would not think that a timer was scheduled. * Fixed potential for pri_schedule_del() to write out of bounds of pri_sched[]. The out of bounds access could occur when pri_schedule_event() returned -1. * Made use all pri_sched[] entries. pri_sched[0] was previously unused. * Removed some unneeded code and recursion since scheduling only runs on master D channel structures. * Added doxygen comments. * Renamed struct pri *pri variables to struct pri *ctrl in this file. git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1059 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- prisched.c | 165 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 54 deletions(-) diff --git a/prisched.c b/prisched.c index c5bc24b..536b696 100644 --- a/prisched.c +++ b/prisched.c @@ -33,25 +33,43 @@ #include "pri_internal.h" +/*! \brief The maximum number of timers that were active at once. */ static int maxsched = 0; /* Scheduler routines */ -int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data) + +/*! + * \brief Start a timer to schedule an event. + * + * \param ctrl D channel controller. + * \param ms Number of milliseconds to scheduled event. + * \param function Callback function to call when timeout. + * \param data Value to give callback function when timeout. + * + * \retval 0 if scheduler table is full and could not schedule the event. + * \retval id Scheduled event id. + */ +int pri_schedule_event(struct pri *ctrl, int ms, void (*function)(void *data), void *data) { int x; struct timeval tv; + /* Scheduling runs on master channels only */ - while (pri->master) - pri = pri->master; - for (x=1;xpri_sched[x].callback) - break; - if (x == MAX_SCHED) { - pri_error(pri, "No more room in scheduler\n"); - return -1; + while (ctrl->master) { + ctrl = ctrl->master; + } + for (x = 0; x < MAX_SCHED; ++x) { + if (!ctrl->pri_sched[x].callback) { + break; + } + } + if (x == MAX_SCHED) { + pri_error(ctrl, "No more room in scheduler\n"); + return 0; + } + if (x >= maxsched) { + maxsched = x + 1; } - if (x > maxsched) - maxsched = x; gettimeofday(&tv, NULL); tv.tv_sec += ms / 1000; tv.tv_usec += (ms % 1000) * 1000; @@ -59,71 +77,110 @@ int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), vo tv.tv_usec -= 1000000; tv.tv_sec += 1; } - pri->pri_sched[x].when = tv; - pri->pri_sched[x].callback = function; - pri->pri_sched[x].data = data; - return x; + ctrl->pri_sched[x].when = tv; + ctrl->pri_sched[x].callback = function; + ctrl->pri_sched[x].data = data; + return x + 1; } -struct timeval *pri_schedule_next(struct pri *pri) +/*! + * \brief Determine the time of the next scheduled event to expire. + * + * \param ctrl D channel controller. + * + * \return Time of the next scheduled event to expire or NULL if no timers active. + */ +struct timeval *pri_schedule_next(struct pri *ctrl) { struct timeval *closest = NULL; int x; - /* Check subchannels */ - if (pri->subchannel) - closest = pri_schedule_next(pri->subchannel); - for (x=1;xpri_sched[x].callback && - (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) || - ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) && - (closest->tv_usec > pri->pri_sched[x].when.tv_usec)))) - closest = &pri->pri_sched[x].when; + + /* Scheduling runs on master channels only */ + while (ctrl->master) { + ctrl = ctrl->master; + } + for (x = 0; x < MAX_SCHED; ++x) { + if (ctrl->pri_sched[x].callback && (!closest + || (closest->tv_sec > ctrl->pri_sched[x].when.tv_sec) + || ((closest->tv_sec == ctrl->pri_sched[x].when.tv_sec) + && (closest->tv_usec > ctrl->pri_sched[x].when.tv_usec)))) { + closest = &ctrl->pri_sched[x].when; + } } return closest; } -static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv) +/*! + * \internal + * \brief Run all expired timers or return an event generated by an expired timer. + * + * \param ctrl D channel controller. + * \param tv Current time. + * + * \return Event for upper layer to process or NULL if all expired timers run. + */ +static pri_event *__pri_schedule_run(struct pri *ctrl, struct timeval *tv) { int x; void (*callback)(void *); void *data; - pri_event *e; - if (pri->subchannel) { - if ((e = __pri_schedule_run(pri->subchannel, tv))) { - return e; - } + + /* Scheduling runs on master channels only */ + while (ctrl->master) { + ctrl = ctrl->master; } - for (x=1;xpri_sched[x].callback && - ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) || - ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) && - (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) { - pri->schedev = 0; - callback = pri->pri_sched[x].callback; - data = pri->pri_sched[x].data; - pri->pri_sched[x].callback = NULL; - pri->pri_sched[x].data = NULL; - callback(data); - if (pri->schedev) - return &pri->ev; - } + for (x = 0; x < MAX_SCHED; ++x) { + if (ctrl->pri_sched[x].callback && ((ctrl->pri_sched[x].when.tv_sec < tv->tv_sec) + || ((ctrl->pri_sched[x].when.tv_sec == tv->tv_sec) + && (ctrl->pri_sched[x].when.tv_usec <= tv->tv_usec)))) { + /* This timer has expired. */ + ctrl->schedev = 0; + callback = ctrl->pri_sched[x].callback; + data = ctrl->pri_sched[x].data; + ctrl->pri_sched[x].callback = NULL; + callback(data); + if (ctrl->schedev) { + return &ctrl->ev; + } + } } return NULL; } -pri_event *pri_schedule_run(struct pri *pri) +/*! + * \brief Run all expired timers or return an event generated by an expired timer. + * + * \param ctrl D channel controller. + * + * \return Event for upper layer to process or NULL if all expired timers run. + */ +pri_event *pri_schedule_run(struct pri *ctrl) { struct timeval tv; + gettimeofday(&tv, NULL); - return __pri_schedule_run(pri, &tv); + return __pri_schedule_run(ctrl, &tv); } - -void pri_schedule_del(struct pri *pri,int id) +/*! + * \brief Delete a scheduled event. + * + * \param ctrl D channel controller. + * \param id Scheduled event id to delete. + * 0 is a disabled/unscheduled event id that is ignored. + * 1 - MAX_SCHED is a valid event id. + * + * \return Nothing + */ +void pri_schedule_del(struct pri *ctrl, int id) { - while (pri->master) - pri = pri->master; - if ((id >= MAX_SCHED) || (id < 0)) - pri_error(pri, "Asked to delete sched id %d???\n", id); - pri->pri_sched[id].callback = NULL; + /* Scheduling runs on master channels only */ + while (ctrl->master) { + ctrl = ctrl->master; + } + if (0 < id && id <= MAX_SCHED) { + ctrl->pri_sched[id - 1].callback = NULL; + } else if (id) { + pri_error(ctrl, "Asked to delete sched id %d???\n", id); + } }