[svn-commits] trunk r8877 - in /trunk: ./ channels/ include/asterisk/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue Jan 31 14:20:35 MST 2006


Author: markster
Date: Sun Jan 29 21:13:33 2006
New Revision: 8877

URL: http://svn.digium.com/view/asterisk?rev=8877&view=rev
Log:
Merge Rizzo's waitfor update (bug #4584)

Modified:
    trunk/channel.c
    trunk/channels/chan_agent.c
    trunk/channels/chan_features.c
    trunk/include/asterisk/channel.h

Modified: trunk/channel.c
URL: http://svn.digium.com/view/asterisk/trunk/channel.c?rev=8877&r1=8876&r2=8877&view=diff
==============================================================================
--- trunk/channel.c (original)
+++ trunk/channel.c Sun Jan 29 21:13:33 2006
@@ -604,7 +604,10 @@
 		return NULL;
 	}
 	
-	for (x=0; x<AST_MAX_FDS - 1; x++)
+	/* Don't bother initializing the last two FD here, because they
+	   will *always* be set just a few lines down (AST_TIMING_FD,
+	   AST_ALERT_FD). */
+	for (x=0; x<AST_MAX_FDS - 2; x++)
 		tmp->fds[x] = -1;
 
 #ifdef ZAPTEL_OPTIMIZATIONS
@@ -636,9 +639,9 @@
 		tmp->alertpipe[0] = tmp->alertpipe[1] = -1;
 
 	/* Always watch the alertpipe */
-	tmp->fds[AST_MAX_FDS-1] = tmp->alertpipe[0];
+	tmp->fds[AST_ALERT_FD] = tmp->alertpipe[0];
 	/* And timing pipe */
-	tmp->fds[AST_MAX_FDS-2] = tmp->timingfd;
+	tmp->fds[AST_TIMING_FD] = tmp->timingfd;
 	strcpy(tmp->name, "**Unknown**");
 	/* Initial state */
 	tmp->_state = AST_STATE_DOWN;
@@ -1414,6 +1417,7 @@
 			chan->generator->release(chan, chan->generatordata);
 		chan->generatordata = NULL;
 		chan->generator = NULL;
+		chan->fds[AST_GENERATOR_FD] = -1;
 		ast_clear_flag(chan, AST_FLAG_WRITE_INT);
 		ast_settimeout(chan, 0, NULL, NULL);
 	}
@@ -1470,56 +1474,8 @@
 /*! \brief Wait for x amount of time on a file descriptor to have input.  */
 int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 {
-	struct timeval start = { 0 , 0 };
-	int res;
-	int x, y;
 	int winner = -1;
-	int spoint;
-	struct pollfd *pfds;
-	
-	pfds = alloca(sizeof(struct pollfd) * n);
-	if (!pfds) {
-		ast_log(LOG_ERROR, "Out of memory\n");
-		return -1;
-	}
-	if (*ms > 0)
-		start = ast_tvnow();
-	y = 0;
-	for (x=0; x < n; x++) {
-		if (fds[x] > -1) {
-			pfds[y].fd = fds[x];
-			pfds[y].events = POLLIN | POLLPRI;
-			y++;
-		}
-	}
-	res = poll(pfds, y, *ms);
-	if (res < 0) {
-		/* Simulate a timeout if we were interrupted */
-		if (errno != EINTR)
-			*ms = -1;
-		else
-			*ms = 0;
-		return -1;
-	}
-	spoint = 0;
-	for (x=0; x < n; x++) {
-		if (fds[x] > -1) {
-			if ((res = ast_fdisset(pfds, fds[x], y, &spoint))) {
-				winner = fds[x];
-				if (exception) {
-					if (res & POLLPRI)
-						*exception = -1;
-					else
-						*exception = 0;
-				}
-			}
-		}
-	}
-	if (*ms > 0) {
-		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
-		if (*ms < 0)
-			*ms = 0;
-	}
+	ast_waitfor_nandfds(NULL, 0, fds, n, exception, &winner, ms);
 	return winner;
 }
 
@@ -1532,13 +1488,19 @@
 	int res;
 	long rms;
 	int x, y, max;
-	int spoint;
+	int sz;
 	time_t now = 0;
-	long whentohangup = 0, havewhen = 0, diff;
+	long whentohangup = 0, diff;
 	struct ast_channel *winner = NULL;
-
-	pfds = alloca(sizeof(struct pollfd) * (n * AST_MAX_FDS + nfds));
-	if (!pfds) {
+	struct fdmap {
+		int chan;
+		int fdno;
+	} *fdmap;
+
+	sz = n * AST_MAX_FDS + nfds;
+	pfds = alloca(sizeof(struct pollfd) * sz);
+	fdmap = alloca(sizeof(struct fdmap) * sz);
+	if (!pfds || !fdmap) {
 		ast_log(LOG_ERROR, "Out of memory\n");
 		*outfd = -1;
 		return NULL;
@@ -1552,15 +1514,6 @@
 	/* Perform any pending masquerades */
 	for (x=0; x < n; x++) {
 		ast_mutex_lock(&c[x]->lock);
-		if (c[x]->whentohangup) {
-			if (!havewhen)
-				time(&now);
-			diff = c[x]->whentohangup - now;
-			if (!havewhen || (diff < whentohangup)) {
-				havewhen++;
-				whentohangup = diff;
-			}
-		}
 		if (c[x]->masq) {
 			if (ast_do_masquerade(c[x])) {
 				ast_log(LOG_WARNING, "Masquerade failed\n");
@@ -1569,40 +1522,52 @@
 				return NULL;
 			}
 		}
+		if (c[x]->whentohangup) {
+			if (!whentohangup)
+				time(&now);
+			diff = c[x]->whentohangup - now;
+			if (diff < 1) {
+				/* Should already be hungup */
+				c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+				ast_mutex_unlock(&c[x]->lock);
+				return c[x];
+			}
+			if (!whentohangup || (diff < whentohangup))
+				whentohangup = diff;
+		}
 		ast_mutex_unlock(&c[x]->lock);
 	}
-
+	/* Wait full interval */
 	rms = *ms;
-	
-	if (havewhen) {
-		if ((*ms < 0) || (whentohangup * 1000 < *ms)) {
-			rms =  whentohangup * 1000;
-		}
-	}
+	if (whentohangup) {
+		rms = (whentohangup - now) * 1000;	/* timeout in milliseconds */
+		if (*ms >= 0 && *ms < rms)		/* original *ms still smaller */
+			rms =  *ms;
+	}
+	/*
+	 * Build the pollfd array, putting the channels' fds first,
+	 * followed by individual fds. Order is important because
+	 * individual fd's must have priority over channel fds.
+	 */
 	max = 0;
-	for (x=0; x < n; x++) {
-		for (y=0; y< AST_MAX_FDS; y++) {
-			if (c[x]->fds[y] > -1) {
-				pfds[max].fd = c[x]->fds[y];
-				pfds[max].events = POLLIN | POLLPRI;
-				pfds[max].revents = 0;
-				max++;
-			}
+	for (x=0; x<n; x++) {
+		for (y=0; y<AST_MAX_FDS; y++) {
+			fdmap[max].fdno = y;  /* fd y is linked to this pfds */
+			fdmap[max].chan = x;  /* channel x is linked to this pfds */
+			max += ast_add_fd(&pfds[max], c[x]->fds[y]);
 		}
 		CHECK_BLOCKING(c[x]);
 	}
-	for (x=0; x < nfds; x++) {
-		if (fds[x] > -1) {
-			pfds[max].fd = fds[x];
-			pfds[max].events = POLLIN | POLLPRI;
-			pfds[max].revents = 0;
-			max++;
-		}
-	}
+	/* Add the individual fds */
+	for (x=0; x<nfds; x++) {
+		fdmap[max].chan = -1;
+		max += ast_add_fd(&pfds[max], fds[x]);
+	}
+
 	if (*ms > 0) 
 		start = ast_tvnow();
 	
-	if (sizeof(int) == 4) {
+	if (sizeof(int) == 4) {	/* XXX fix timeout > 600000 on linux x86-32 */
 		do {
 			int kbrms = rms;
 			if (kbrms > 600000)
@@ -1614,65 +1579,49 @@
 	} else {
 		res = poll(pfds, max, rms);
 	}
-	
-	if (res < 0) {
-		for (x=0; x < n; x++) 
-			ast_clear_flag(c[x], AST_FLAG_BLOCKING);
-		/* Simulate a timeout if we were interrupted */
-		if (errno != EINTR)
-			*ms = -1;
-		else {
-			/* Just an interrupt */
-#if 0
-			*ms = 0;
-#endif			
-		}
+	for (x=0; x<n; x++)
+		ast_clear_flag(c[x], AST_FLAG_BLOCKING);
+	if (res < 0) { /* Simulate a timeout if we were interrupted */
+		*ms = (errno != EINTR) ? -1 : 0;
 		return NULL;
-        } else {
-        	/* If no fds signalled, then timeout. So set ms = 0
-		   since we may not have an exact timeout.
-		*/
+	}
+	if (whentohangup) {   /* if we have a timeout, check who expired */
+		time(&now);
+		for (x=0; x<n; x++) {
+			if (c[x]->whentohangup && now >= c[x]->whentohangup) {
+				c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
+				if (winner == NULL)
+					winner = c[x];
+			}
+		}
+	}
+	if (res == 0) { /* no fd ready, reset timeout and done */
+		*ms = 0;	/* XXX use 0 since we may not have an exact timeout. */
+		return winner;
+	}
+	/*
+	 * Then check if any channel or fd has a pending event.
+	 * Remember to check channels first and fds last, as they
+	 * must have priority on setting 'winner'
+	 */
+	for (x = 0; x < max; x++) {
+		res = pfds[x].revents;
 		if (res == 0)
-			*ms = 0;
-	}
-
-	if (havewhen)
-		time(&now);
-	spoint = 0;
-	for (x=0; x < n; x++) {
-		ast_clear_flag(c[x], AST_FLAG_BLOCKING);
-		if (havewhen && c[x]->whentohangup && (now > c[x]->whentohangup)) {
-			c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
-			if (!winner)
-				winner = c[x];
-		}
-		for (y=0; y < AST_MAX_FDS; y++) {
-			if (c[x]->fds[y] > -1) {
-				if ((res = ast_fdisset(pfds, c[x]->fds[y], max, &spoint))) {
-					if (res & POLLPRI)
-						ast_set_flag(c[x], AST_FLAG_EXCEPTION);
-					else
-						ast_clear_flag(c[x], AST_FLAG_EXCEPTION);
-					c[x]->fdno = y;
-					winner = c[x];
-				}
-			}
-		}
-	}
-	for (x=0; x < nfds; x++) {
-		if (fds[x] > -1) {
-			if ((res = ast_fdisset(pfds, fds[x], max, &spoint))) {
-				if (outfd)
-					*outfd = fds[x];
-				if (exception) {	
-					if (res & POLLPRI) 
-						*exception = -1;
-					else
-						*exception = 0;
-				}
-				winner = NULL;
-			}
-		}	
+			continue;
+		if (fdmap[x].chan >= 0) {	/* this is a channel */
+			winner = c[fdmap[x].chan];	/* override previous winners */
+			if (res & POLLPRI)
+				ast_set_flag(winner, AST_FLAG_EXCEPTION);
+			else
+				ast_clear_flag(winner, AST_FLAG_EXCEPTION);
+			winner->fdno = fdmap[x].fdno;
+		} else {			/* this is an fd */
+			if (outfd)
+				*outfd = pfds[x].fd;
+			if (exception)
+				*exception = (res & POLLPRI) ? -1 : 0;
+			winner = NULL;
+		}
 	}
 	if (*ms > 0) {
 		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
@@ -1689,16 +1638,11 @@
 
 int ast_waitfor(struct ast_channel *c, int ms)
 {
-	struct ast_channel *chan;
 	int oldms = ms;
 
-	chan = ast_waitfor_n(&c, 1, &ms);
-	if (ms < 0) {
-		if (oldms < 0)
-			return 0;
-		else
-			return -1;
-	}
+	ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
+	if ((ms < 0) && (oldms < 0))
+		ms = 0;
 	return ms;
 }
 
@@ -1856,7 +1800,7 @@
 		read(chan->alertpipe[0], &blah, sizeof(blah));
 	}
 #ifdef ZAPTEL_OPTIMIZATIONS
-	if ((chan->timingfd > -1) && (chan->fdno == AST_MAX_FDS - 2) && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {
+	if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {
 		ast_clear_flag(chan, AST_FLAG_EXCEPTION);
 		blah = -1;
 		/* IF we can't get event, assume it's an expired as-per the old interface */
@@ -1898,8 +1842,19 @@
 			return f;
 		} else
 			ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name);
-	}
+	} else
 #endif
+	/* Check for AST_GENERATOR_FD if not null.  If so, call generator with -1
+	   arguments now so it can do whatever it needs to. */
+	if (chan->fds[AST_GENERATOR_FD] > -1 && chan->fdno == AST_GENERATOR_FD) {
+		void *tmp = chan->generatordata;
+		chan->generatordata = NULL;     /* reset to let ast_write get through */
+		chan->generator->generate(chan, tmp, -1, -1);
+		chan->generatordata = tmp;
+		f = &null_frame;
+		return f;
+	}
+
 	/* Check for pending read queue */
 	if (chan->readq) {
 		f = chan->readq;
@@ -3088,9 +3043,10 @@
 	
 	/* Keep the same language.  */
 	ast_copy_string(original->language, clone->language, sizeof(original->language));
-	/* Copy the FD's */
+	/* Copy the FD's other than the generator fd */
 	for (x = 0; x < AST_MAX_FDS; x++) {
-		original->fds[x] = clone->fds[x];
+		if (x != AST_GENERATOR_FD)
+			original->fds[x] = clone->fds[x];
 	}
 	clone_variables(original, clone);
 	AST_LIST_HEAD_INIT_NOLOCK(&clone->varshead);
@@ -3114,7 +3070,7 @@
 	clone->cid = tmpcid;
 	
 	/* Restore original timing file descriptor */
-	original->fds[AST_MAX_FDS - 2] = original->timingfd;
+	original->fds[AST_TIMING_FD] = original->timingfd;
 	
 	/* Our native formats are different now */
 	original->nativeformats = clone->nativeformats;

Modified: trunk/channels/chan_agent.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_agent.c?rev=8877&r1=8876&r2=8877&view=diff
==============================================================================
--- trunk/channels/chan_agent.c (original)
+++ trunk/channels/chan_agent.c Sun Jan 29 21:13:33 2006
@@ -233,10 +233,10 @@
 	int x; \
 	if (p->chan) { \
 		for (x=0;x<AST_MAX_FDS;x++) {\
-			if (x != AST_MAX_FDS - 2) \
+			if (x != AST_TIMING_FD) \
 				ast->fds[x] = p->chan->fds[x]; \
 		} \
-		ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
+		ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
 	} \
 } while(0)
 
@@ -445,10 +445,7 @@
 	CHECK_FORMATS(ast, p);
 	if (p->chan) {
 		ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
-		if (ast->fdno == AST_MAX_FDS - 3)
-			p->chan->fdno = AST_MAX_FDS - 2;
-		else
-			p->chan->fdno = ast->fdno;
+		p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
 		f = ast_read(p->chan);
 	} else
 		f = &null_frame;

Modified: trunk/channels/chan_features.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_features.c?rev=8877&r1=8876&r2=8877&view=diff
==============================================================================
--- trunk/channels/chan_features.c (original)
+++ trunk/channels/chan_features.c Sun Jan 29 21:13:33 2006
@@ -170,8 +170,8 @@
 	p->subs[index].owner->timingfd = p->subs[index].timingfdbackup;
 	p->subs[index].owner->alertpipe[0] = p->subs[index].alertpipebackup[0];
 	p->subs[index].owner->alertpipe[1] = p->subs[index].alertpipebackup[1];
-	p->subs[index].owner->fds[AST_MAX_FDS-1] = p->subs[index].alertpipebackup[0];
-	p->subs[index].owner->fds[AST_MAX_FDS-2] = p->subs[index].timingfdbackup;
+	p->subs[index].owner->fds[AST_ALERT_FD] = p->subs[index].alertpipebackup[0];
+	p->subs[index].owner->fds[AST_TIMING_FD] = p->subs[index].timingfdbackup;
 }
 
 static void update_features(struct feature_pvt *p, int index)

Modified: trunk/include/asterisk/channel.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/channel.h?rev=8877&r1=8876&r2=8877&view=diff
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Sun Jan 29 21:13:33 2006
@@ -119,6 +119,14 @@
 #define MAX_MUSICCLASS		20
 
 #define AST_MAX_FDS		8
+/*
+ * We have AST_MAX_FDS file descriptors in a channel.
+ * Some of them have a fixed use:
+ */
+#define AST_ALERT_FD	(AST_MAX_FDS-1)		/* used for alertpipe */
+#define AST_TIMING_FD	(AST_MAX_FDS-2)		/* used for timingfd */
+#define AST_AGENT_FD	(AST_MAX_FDS-3) /* used by agents for pass thru */
+#define AST_GENERATOR_FD	(AST_MAX_FDS-4) /* used by generator */
 
 enum ast_bridge_result {
 	AST_BRIDGE_COMPLETE = 0,
@@ -1124,16 +1132,31 @@
 
 /* Misc. functions below */
 
+/* if fd is a valid descriptor, set *pfd with the descriptor
+ * Return 1 (not -1!) if added, 0 otherwise (so we can add the
+ * return value to the index into the array)
+ */
+static inline int ast_add_fd(struct pollfd *pfd, int fd)
+{
+	pfd->fd = fd;
+	pfd->events = POLLIN | POLLPRI;
+	return fd >= 0;
+}
+
 /* Helper function for migrating select to poll */
 static inline int ast_fdisset(struct pollfd *pfds, int fd, int max, int *start)
 {
 	int x;
-	for (x=start ? *start : 0;x<max;x++)
+	int dummy=0;
+
+	if (fd < 0)
+		return 0;
+	if (!start)
+		start = &dummy;
+	for (x = *start; x<max; x++)
 		if (pfds[x].fd == fd) {
-			if (start) {
-				if (x==*start)
-					(*start)++;
-			}
+			if (x == *start)
+				(*start)++;
 			return pfds[x].revents;
 		}
 	return 0;



More information about the svn-commits mailing list