[libpri-commits] rmudgett: branch group/ccss r1423 - /team/group/ccss/

SVN commits to the libpri project libpri-commits at lists.digium.com
Sun Jan 17 17:43:57 CST 2010


Author: rmudgett
Date: Sun Jan 17 17:43:55 2010
New Revision: 1423

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1423
Log:
Change the PRI timers so the number of timers can grow dynamically.  (Up to a max size.)

For ETSI PTP and Q.SIG there could be hundreds of CCSS T_RETENTION timers
active.

Modified:
    team/group/ccss/pri.c
    team/group/ccss/pri_internal.h
    team/group/ccss/prisched.c

Modified: team/group/ccss/pri.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri.c?view=diff&rev=1423&r1=1422&r2=1423
==============================================================================
--- team/group/ccss/pri.c (original)
+++ team/group/ccss/pri.c Sun Jan 17 17:43:55 2010
@@ -293,6 +293,7 @@
 			pri_call_apdu_queue_cleanup(call);
 		}
 		free(p->msg_line);
+		free(p->sched.timer);
 		free(p);
 	}
 }

Modified: team/group/ccss/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_internal.h?view=diff&rev=1423&r1=1422&r2=1423
==============================================================================
--- team/group/ccss/pri_internal.h (original)
+++ team/group/ccss/pri_internal.h Sun Jan 17 17:43:55 2010
@@ -57,9 +57,6 @@
  */
 //#define QSIG_PATH_RESERVATION_SUPPORT	1
 
-/*! Maximum number of scheduled events active at the same time. */
-#define MAX_SCHED	(128 + 256) /* 256 CC supervision timer events */
-
 /*! Maximum number of facility ie's to handle per incoming message. */
 #define MAX_FACILITY_IES	8
 
@@ -81,7 +78,14 @@
 	struct pri_msg_line *msg_line;
 	struct pri *subchannel;	/* Sub-channel if appropriate */
 	struct pri *master;		/* Master channel if appropriate */
-	struct pri_sched pri_sched[MAX_SCHED];	/* Scheduled events */
+	struct {
+		/*! Dynamically allocated array of timers that can grow as needed. */
+		struct pri_sched *timer;
+		/*! Numer of timer slots in the allocated array of timers. */
+		unsigned num_slots;
+		/*! Maximum timer slots currently needed. */
+		unsigned max_used;
+	} sched;
 	int debug;			/* Debug stuff */
 	int state;			/* State of D-channel */
 	int switchtype;		/* Switch type */
@@ -795,18 +799,6 @@
 	enum CC_PARTY_A_AVAILABILITY party_a_status;
 	/*! Indirect timer id to abort indirect action events. */
 	int t_indirect;
-/*
- * BUGBUG t_retention needs to be handled specially.
- * For PTP and Q.SIG there could be hundreds of them active.
- * Something along the lines of using struct timeval and polling at half
- * the T_RETENTION time but no less than 10 seconds.
- * Also if the upper layer has disabled CC for this call, the upper layer
- * needs to immediately cancel CC when the CC available indication comes in.
- *
- * Idea: make the pri_sched[] dynamically allocated so it can grow as needed.
- * This is fairly simple to do and will save memory when slave D channels are
- * being used.
- */
 	/*!
 	 * \brief PTMP T_RETENTION timer id.
 	 * \note

Modified: team/group/ccss/prisched.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/prisched.c?view=diff&rev=1423&r1=1422&r2=1423
==============================================================================
--- team/group/ccss/prisched.c (original)
+++ team/group/ccss/prisched.c Sun Jan 17 17:43:55 2010
@@ -28,15 +28,72 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "libpri.h"
 #include "pri_internal.h"
 
 
+/*! Initial number of scheduled timer slots. */
+#define SCHED_EVENTS_INITIAL	128
+/*!
+ * Maximum number of scheduled timer slots.
+ * Should be a power of 2 multiple of SCHED_EVENTS_INITIAL.
+ */
+#define SCHED_EVENTS_MAX		8192
+
 /*! \brief The maximum number of timers that were active at once. */
-static int maxsched = 0;
+static unsigned maxsched = 0;
 
 /* Scheduler routines */
+
+/*!
+ * \internal
+ * \brief Increase the number of scheduler timer slots available.
+ *
+ * \param ctrl D channel controller.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int pri_schedule_grow(struct pri *ctrl)
+{
+	unsigned num_slots;
+	struct pri_sched *timers;
+
+	/* Determine how many slots in the new timer table. */
+	if (ctrl->sched.num_slots) {
+		if (SCHED_EVENTS_MAX <= ctrl->sched.num_slots) {
+			/* Cannot grow the timer table any more. */
+			return -1;
+		}
+		num_slots = ctrl->sched.num_slots * 2;
+		if (SCHED_EVENTS_MAX < num_slots) {
+			num_slots = SCHED_EVENTS_MAX;
+		}
+	} else {
+		num_slots = SCHED_EVENTS_INITIAL;
+	}
+
+	/* Get and initialize the new timer table. */
+	timers = calloc(num_slots, sizeof(struct pri_sched));
+	if (!timers) {
+		/* Could not get a new timer table. */
+		return -1;
+	}
+	if (ctrl->sched.timer) {
+		/* Copy over the old timer table. */
+		memcpy(timers, ctrl->sched.timer,
+			ctrl->sched.num_slots * sizeof(struct pri_sched));
+		free(ctrl->sched.timer);
+	}
+
+	/* Put the new timer table in place. */
+	ctrl->sched.timer = timers;
+	ctrl->sched.num_slots = num_slots;
+	return 0;
+}
 
 /*!
  * \brief Start a timer to schedule an event.
@@ -51,21 +108,25 @@
  */
 int pri_schedule_event(struct pri *ctrl, int ms, void (*function)(void *data), void *data)
 {
-	int x;
+	unsigned max_used;
+	unsigned x;
 	struct timeval tv;
 
 	/* 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_MASTER(ctrl);
+
+	max_used = ctrl->sched.max_used;
+	for (x = 0; x < max_used; ++x) {
+		if (!ctrl->sched.timer[x].callback) {
 			break;
 		}
 	}
-	if (x == MAX_SCHED) {
+	if (x == ctrl->sched.num_slots && pri_schedule_grow(ctrl)) {
 		pri_error(ctrl, "No more room in scheduler\n");
 		return 0;
+	}
+	if (ctrl->sched.max_used <= x) {
+		ctrl->sched.max_used = x + 1;
 	}
 	if (x >= maxsched) {
 		maxsched = x + 1;
@@ -77,9 +138,9 @@
 		tv.tv_usec -= 1000000;
 		tv.tv_sec += 1;
 	}
-	ctrl->pri_sched[x].when = tv;
-	ctrl->pri_sched[x].callback = function;
-	ctrl->pri_sched[x].data = data;
+	ctrl->sched.timer[x].when = tv;
+	ctrl->sched.timer[x].callback = function;
+	ctrl->sched.timer[x].data = data;
 	return x + 1;
 }
 
@@ -93,19 +154,28 @@
 struct timeval *pri_schedule_next(struct pri *ctrl)
 {
 	struct timeval *closest = NULL;
-	int x;
-
-	/* 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;
-		}
+	unsigned x;
+
+	/* Scheduling runs on master channels only */
+	ctrl = PRI_MASTER(ctrl);
+
+	/* Scan the scheduled timer slots backwards so we can update the max_used value. */
+	for (x = ctrl->sched.max_used; x--;) {
+		if (ctrl->sched.timer[x].callback) {
+			if (!closest) {
+				/* This is the highest sheduled timer slot in use. */
+				closest = &ctrl->sched.timer[x].when;
+				ctrl->sched.max_used = x + 1;
+			} else if ((closest->tv_sec > ctrl->sched.timer[x].when.tv_sec)
+				|| ((closest->tv_sec == ctrl->sched.timer[x].when.tv_sec)
+					&& (closest->tv_usec > ctrl->sched.timer[x].when.tv_usec))) {
+				closest = &ctrl->sched.timer[x].when;
+			}
+		}
+	}
+	if (!closest) {
+		/* No scheduled timer slots are active. */
+		ctrl->sched.max_used = 0;
 	}
 	return closest;
 }
@@ -121,23 +191,25 @@
  */
 static pri_event *__pri_schedule_run(struct pri *ctrl, struct timeval *tv)
 {
-	int x;
+	unsigned x;
+	unsigned max_used;
 	void (*callback)(void *);
 	void *data;
 
 	/* 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)))) {
+	ctrl = PRI_MASTER(ctrl);
+
+	max_used = ctrl->sched.max_used;
+	for (x = 0; x < max_used; ++x) {
+		if (ctrl->sched.timer[x].callback
+			&& ((ctrl->sched.timer[x].when.tv_sec < tv->tv_sec)
+			|| ((ctrl->sched.timer[x].when.tv_sec == tv->tv_sec)
+			&& (ctrl->sched.timer[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 = ctrl->sched.timer[x].callback;
+			data = ctrl->sched.timer[x].data;
+			ctrl->sched.timer[x].callback = NULL;
 			callback(data);
 			if (ctrl->schedev) {
 				return &ctrl->ev;
@@ -175,12 +247,12 @@
 void pri_schedule_del(struct pri *ctrl, int id)
 {
 	/* 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;
+	ctrl = PRI_MASTER(ctrl);
+
+	if (0 < id && id <= ctrl->sched.num_slots) {
+		ctrl->sched.timer[id - 1].callback = NULL;
 	} else if (id) {
-		pri_error(ctrl, "Asked to delete sched id %d???\n", id);
-	}
-}
+		pri_error(ctrl, "Asked to delete sched id %d??? num_slots=%d\n", id,
+			ctrl->sched.num_slots);
+	}
+}




More information about the libpri-commits mailing list