[asterisk-commits] tilghman: branch 1.6.2 r266683 - in /branches/1.6.2: ./ main/manager.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jun 1 11:42:06 CDT 2010


Author: tilghman
Date: Tue Jun  1 11:42:03 2010
New Revision: 266683

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=266683
Log:
Merged revisions 266682 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
  r266682 | tilghman | 2010-06-01 11:41:00 -0500 (Tue, 01 Jun 2010) | 16 lines
  
  Eliminate stale manager events after a set interval, even if AMI clients don't query for them.
  
  Actions (or failures to act) by external clients should not cause memory leaks
  in Asterisk, especially when those continued leaks could cause Asterisk to
  misbehave later.
  
  (closes issue #17234)
   Reported by: mav3rick
   Patches: 
         20100510__issue17234.diff.txt uploaded by tilghman (license 14)
         20100517__issue17234__trunk.diff.txt uploaded by tilghman (license 14)
   Tested by: mav3rick, davidw
  
  (closes issue #17365)
   Reported by: davidw
........

Modified:
    branches/1.6.2/   (props changed)
    branches/1.6.2/main/manager.c

Propchange: branches/1.6.2/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.2/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.6.2/main/manager.c?view=diff&rev=266683&r1=266682&r2=266683
==============================================================================
--- branches/1.6.2/main/manager.c (original)
+++ branches/1.6.2/main/manager.c Tue Jun  1 11:42:03 2010
@@ -113,11 +113,12 @@
 	int usecount;		/*!< # of clients who still need the event */
 	int category;
 	unsigned int seq;	/*!< sequence number */
-	AST_LIST_ENTRY(eventqent) eq_next;
+	struct timeval tv;  /*!< When event was allocated */
+	AST_RWLIST_ENTRY(eventqent) eq_next;
 	char eventdata[1];	/*!< really variable size, allocated by append_event() */
 };
 
-static AST_LIST_HEAD_STATIC(all_events, eventqent);
+static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
 
 static int displayconnects = 1;
 static int allowmultiplelogin = 1;
@@ -222,8 +223,6 @@
 	int fd;
 };
 
-#define NEW_EVENT(m)	(AST_LIST_NEXT(m->session->last_ev, eq_next))
-
 static AST_LIST_HEAD_STATIC(sessions, mansession_session);
 
 /*! \brief user descriptor, as read from the config file.
@@ -332,14 +331,15 @@
 {
 	struct eventqent *ret;
 
-	AST_LIST_LOCK(&all_events);
-	ret = AST_LIST_LAST(&all_events);
+	AST_RWLIST_RDLOCK(&all_events);
+	ret = AST_RWLIST_LAST(&all_events);
 	/* the list is never empty now, but may become so when
 	 * we optimize it in the future, so be prepared.
 	 */
-	if (ret)
+	if (ret) {
 		ast_atomic_fetchadd_int(&ret->usecount, 1);
-	AST_LIST_UNLOCK(&all_events);
+	}
+	AST_RWLIST_UNLOCK(&all_events);
 	return ret;
 }
 
@@ -350,14 +350,24 @@
 static void purge_events(void)
 {
 	struct eventqent *ev;
-
-	AST_LIST_LOCK(&all_events);
-	while ( (ev = AST_LIST_FIRST(&all_events)) &&
-	    ev->usecount == 0 && AST_LIST_NEXT(ev, eq_next)) {
-		AST_LIST_REMOVE_HEAD(&all_events, eq_next);
+	struct timeval now = ast_tvnow();
+
+	AST_RWLIST_WRLOCK(&all_events);
+	while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
+	    ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
+		AST_RWLIST_REMOVE_HEAD(&all_events, eq_next);
 		ast_free(ev);
 	}
-	AST_LIST_UNLOCK(&all_events);
+
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next) {
+		/* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
+		if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
+			AST_RWLIST_REMOVE_CURRENT(eq_next);
+			ast_free(ev);
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+	AST_RWLIST_UNLOCK(&all_events);
 }
 
 /*!
@@ -770,13 +780,13 @@
 	case CLI_GENERATE:
 		return NULL;
 	}
-	AST_LIST_LOCK(&all_events);
-	AST_LIST_TRAVERSE(&all_events, s, eq_next) {
+	AST_RWLIST_RDLOCK(&all_events);
+	AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
 		ast_cli(a->fd, "Usecount: %d\n", s->usecount);
 		ast_cli(a->fd, "Category: %d\n", s->category);
 		ast_cli(a->fd, "Event:\n%s", s->eventdata);
 	}
-	AST_LIST_UNLOCK(&all_events);
+	AST_RWLIST_UNLOCK(&all_events);
 
 	return CLI_SUCCESS;
 }
@@ -812,21 +822,17 @@
 	AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
 };
 
-/*
- * Decrement the usecount for the event; if it goes to zero,
- * (why check for e->next ?) wakeup the
- * main thread, which is in charge of freeing the record.
- * Returns the next record.
- */
-static struct eventqent *unref_event(struct eventqent *e)
-{
-	ast_atomic_fetchadd_int(&e->usecount, -1);
-	return AST_LIST_NEXT(e, eq_next);
-}
-
-static void ref_event(struct eventqent *e)
-{
-	ast_atomic_fetchadd_int(&e->usecount, 1);
+static struct eventqent *advance_event(struct eventqent *e)
+{
+	struct eventqent *next;
+
+	AST_RWLIST_RDLOCK(&all_events);
+	if ((next = AST_RWLIST_NEXT(e, eq_next))) {
+		ast_atomic_fetchadd_int(&next->usecount, 1);
+		ast_atomic_fetchadd_int(&e->usecount, -1);
+	}
+	AST_RWLIST_UNLOCK(&all_events);
+	return next;
 }
 
 /*
@@ -847,7 +853,7 @@
 		fclose(session->f);
 	ast_mutex_destroy(&session->__lock);
 	ast_free(session);
-	unref_event(eqe);
+	ast_atomic_fetchadd_int(&eqe->usecount, -1);
 }
 
 static void destroy_session(struct mansession_session *session)
@@ -1638,8 +1644,9 @@
 
 	for (x = 0; x < timeout || timeout < 0; x++) {
 		ast_mutex_lock(&s->session->__lock);
-		if (NEW_EVENT(s))
+		if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
 			needexit = 1;
+		}
 		/* We can have multiple HTTP session point to the same mansession entry.
 		 * The way we deal with it is not very nice: newcomers kick out the previous
 		 * HTTP session. XXX this needs to be improved.
@@ -1661,15 +1668,14 @@
 	ast_debug(1, "Finished waiting for an event!\n");
 	ast_mutex_lock(&s->session->__lock);
 	if (s->session->waiting_thread == pthread_self()) {
-		struct eventqent *eqe;
+		struct eventqent *eqe = s->session->last_ev;
 		astman_send_response(s, m, "Success", "Waiting for Event completed.");
-		while ( (eqe = NEW_EVENT(s)) ) {
-			ref_event(eqe);
+		while ((eqe = advance_event(eqe))) {
 			if (((s->session->readperm & eqe->category) == eqe->category) &&
 			    ((s->session->send_events & eqe->category) == eqe->category)) {
 				astman_append(s, "%s", eqe->eventdata);
 			}
-			s->session->last_ev = unref_event(s->session->last_ev);
+			s->session->last_ev = eqe;
 		}
 		astman_append(s,
 			"Event: WaitEventComplete\r\n"
@@ -2682,17 +2688,16 @@
 
 	ast_mutex_lock(&s->session->__lock);
 	if (s->session->f != NULL) {
-		struct eventqent *eqe;
-
-		while ( (eqe = NEW_EVENT(s)) ) {
-			ref_event(eqe);
+		struct eventqent *eqe = s->session->last_ev;
+
+		while ((eqe = advance_event(eqe))) {
 			if (!ret && s->session->authenticated &&
 			    (s->session->readperm & eqe->category) == eqe->category &&
 			    (s->session->send_events & eqe->category) == eqe->category) {
 				if (send_string(s, eqe->eventdata) < 0)
 					ret = -1;	/* don't send more */
 			}
-			s->session->last_ev = unref_event(s->session->last_ev);
+			s->session->last_ev = eqe;
 		}
 	}
 	ast_mutex_unlock(&s->session->__lock);
@@ -3307,12 +3312,13 @@
 	tmp->usecount = 0;
 	tmp->category = category;
 	tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
-	AST_LIST_NEXT(tmp, eq_next) = NULL;
+	tmp->tv = ast_tvnow();
+	AST_RWLIST_NEXT(tmp, eq_next) = NULL;
 	strcpy(tmp->eventdata, str);
 
-	AST_LIST_LOCK(&all_events);
-	AST_LIST_INSERT_TAIL(&all_events, tmp, eq_next);
-	AST_LIST_UNLOCK(&all_events);
+	AST_RWLIST_WRLOCK(&all_events);
+	AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
+	AST_RWLIST_UNLOCK(&all_events);
 
 	return 0;
 }




More information about the asterisk-commits mailing list