[libpri-commits] rmudgett: branch 1.4 r1059 - /branches/1.4/prisched.c

SVN commits to the libpri project libpri-commits at lists.digium.com
Wed Sep 2 14:50:01 CDT 2009


Author: rmudgett
Date: Wed Sep  2 14:49:58 2009
New Revision: 1059

URL: http://svn.asterisk.org/svn-view/libpri?view=rev&rev=1059
Log:
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.

Modified:
    branches/1.4/prisched.c

Modified: branches/1.4/prisched.c
URL: http://svn.asterisk.org/svn-view/libpri/branches/1.4/prisched.c?view=diff&rev=1059&r1=1058&r2=1059
==============================================================================
--- branches/1.4/prisched.c (original)
+++ branches/1.4/prisched.c Wed Sep  2 14:49:58 2009
@@ -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;x<MAX_SCHED;x++)
-		if (!pri->pri_sched[x].callback)
+	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(pri, "No more room in scheduler\n");
-		return -1;
+		pri_error(ctrl, "No more room in scheduler\n");
+		return 0;
 	}
-	if (x > maxsched)
-		maxsched = x;
+	if (x >= maxsched) {
+		maxsched = x + 1;
+	}
 	gettimeofday(&tv, NULL);
 	tv.tv_sec += ms / 1000;
 	tv.tv_usec += (ms % 1000) * 1000;
@@ -59,71 +77,110 @@
 		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;x<MAX_SCHED;x++) {
-		if (pri->pri_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 = 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;
+			}
 		}
-	}
-	for (x=1;x<MAX_SCHED;x++) {
-		if (pri->pri_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;
-	    }
 	}
 	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);
+	}
 }




More information about the libpri-commits mailing list