[PATCH] Fix memory freeing at exit

From: Krzysztof Oledzki <ole#ans.pl>
Date: Fri, 30 May 2008 00:00:06 +0200


From 4983c53d3e3be3916fab484b3d0dd36b609b95db Mon Sep 17 00:00:00 2001 From: Krzysztof Piotr Oledzki <ole#ans.pl> Date: Thu, 29 May 2008 23:53:44 +0200
Subject: [MEDIUM] Fix memory freeing at exit

New functions implemented:

Add missing pool_destroy2 calls:

Implement all task stopping:

before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.

after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.

before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.

after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.

Still not perfect but significant improvement.

---
 include/proto/acl.h    |    3 +++
 include/proto/fd.h     |    5 +++++
 include/types/server.h |    1 +
 src/acl.c              |   16 ++++++++++++++++
 src/appsession.c       |   27 +++++++++++++++++----------
 src/checks.c           |    2 ++
 src/fd.c               |   16 ++++++++++++++++
 src/haproxy.c          |   32 +++++++++++++++++++++++++++-----
 src/memory.c           |    2 ++
 9 files changed, 89 insertions(+), 15 deletions(-)

diff --git a/include/proto/acl.h b/include/proto/acl.h
index 4e2b301..8b0c5e0 100644
--- a/include/proto/acl.h
+++ b/include/proto/acl.h
@@ -47,6 +47,9 @@ struct acl_keyword *find_acl_kw(const char *kw);
  */
 struct acl_expr *parse_acl_expr(const char **args);
 
+/* Purge everything in the acl <acl>, then return <acl>. */
+struct acl *prune_acl(struct acl *acl);
+
 /* Parse an ACL with the name starting at <args>[0], and with a list of already
  * known ACLs in <acl>. If the ACL was not in the list, it will be added.
  * A pointer to that ACL is returned.
diff --git a/include/proto/fd.h b/include/proto/fd.h
index 74b04b2..1cba33b 100644
--- a/include/proto/fd.h
+++ b/include/proto/fd.h
@@ -46,6 +46,11 @@ void disable_poller(const char *poller_name);
 int init_pollers();
 
 /*
+ * Deinitialize the pollers.
+ */
+void deinit_pollers();
+
+/*
  * Some pollers may lose their connection after a fork(). It may be necessary
  * to create initialize part of them again. Returns 0 in case of failure,
  * otherwise 1. The fork() function may be NULL if unused. In case of error,
diff --git a/include/types/server.h b/include/types/server.h
index 0e2183e..462db2b 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -84,6 +84,7 @@ struct server {
 	int maxqueue;				/* maximum number of pending connections allowed */
 	struct list pendconns;			/* pending connections */
 	struct task *queue_mgt;			/* the task associated to the queue processing */
+	struct task *check;                     /* the task associated to the health check processing */
 
 	struct sockaddr_in addr;		/* the address to connect to */
 	struct sockaddr_in source_addr;		/* the address to which we want to bind for connect() */
diff --git a/src/acl.c b/src/acl.c
index aa095c5..96b21de 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -567,6 +567,22 @@ struct acl_expr *parse_acl_expr(const char **args)
 	return NULL;
 }
 
+/* Purge everything in the acl <acl>, then return <acl>. */
+struct acl *prune_acl(struct acl *acl) {
+
+	struct acl_expr *expr, *exprb;
+
+	free(acl->name);
+
+	list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
+		LIST_DEL(&expr->list);
+		prune_acl_expr(expr);
+		free(expr);
+	}
+
+	return acl;
+}
+
 /* Parse an ACL with the name starting at <args>[0], and with a list of already
  * known ACLs in <acl>. If the ACL was not in the list, it will be added.
  * A pointer to that ACL is returned.
diff --git a/src/appsession.c b/src/appsession.c
index 9b6868c..e1a01cc 100644
--- a/src/appsession.c
+++ b/src/appsession.c
@@ -27,7 +27,7 @@
 
 #include <proto/task.h>
 
-
+static struct task *appsess_refresh = NULL;
 struct pool_head *pool2_appsess;
 struct app_pool apools;
 int have_appsession;
@@ -87,17 +87,17 @@ int appsession_init(void)
 int appsession_task_init(void)
 {
 	static int initialized = 0;
-	struct task *t;
 	if (!initialized) {
-		if ((t = pool_alloc2(pool2_task)) == NULL)
+		if ((appsess_refresh = pool_alloc2(pool2_task)) == NULL)
 			return -1;
-		t->wq = NULL;
-		t->qlist.p = NULL;
-		t->state = TASK_IDLE;
-		t->context = NULL;
-		tv_ms_add(&t->expire, &now, TBLCHKINT);
-		t->process = appsession_refresh;
-		task_queue(t);
+
+		appsess_refresh->wq = NULL;
+		appsess_refresh->qlist.p = NULL;
+		appsess_refresh->state = TASK_IDLE;
+		appsess_refresh->context = NULL;
+		tv_ms_add(&appsess_refresh->expire, &now, TBLCHKINT);
+		appsess_refresh->process = appsession_refresh;
+		task_queue(appsess_refresh);
 		initialized ++;
 	}
 	return 0;
@@ -168,6 +168,13 @@ void appsession_cleanup( void )
 		appsession_hash_destroy(&(p->htbl_proxy));
 		p = p->next;
 	}
+
+	if (appsess_refresh) {
+		task_delete(appsess_refresh);
+		task_free(appsess_refresh);
+		appsess_refresh = NULL;
+	}
+
 }/* end appsession_cleanup() */
 
 
diff --git a/src/checks.c b/src/checks.c
index 0b8756b..be26711 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -848,6 +848,8 @@ int start_checks() {
 				return -1;
 			}
 
+			s->check = t;
+
 			t->wq = NULL;
 			t->qlist.p = NULL;
 			t->state = TASK_IDLE;
diff --git a/src/fd.c b/src/fd.c
index 9c370fa..eaaaabf 100644
--- a/src/fd.c
+++ b/src/fd.c
@@ -87,6 +87,22 @@ int init_pollers()
 }
 
 /*
+ * Deinitialize the pollers.
+ */
+void deinit_pollers() {
+
+	struct poller *bp;
+	int p;
+
+	for (p = 0; p < nbpollers; p++) {
+		bp = &pollers[p];
+
+		if (bp && bp->pref)
+			bp->term(bp);
+	}
+}
+
+/*
  * Lists the known pollers on <out>.
  * Should be performed only before initialization.
  */
diff --git a/src/haproxy.c b/src/haproxy.c
index b42728e..4b6bdf8 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -646,6 +646,7 @@ void deinit(void)
 	struct listener *l,*l_next;
 	struct acl_cond *cond, *condb;
 	struct hdr_exp *exp, *expb;
+	struct acl *acl, *aclb;
 	int i;
   
 	while (p) {
@@ -718,10 +719,15 @@ void deinit(void)
 		}
 
 		/* FIXME: this must also be freed :
-		 *  - ACLs
 		 *  - uri_auth (but it's shared)
 		 */
 
+		list_for_each_entry_safe(acl, aclb, &p->acl, list) {
+			LIST_DEL(&acl->list);
+			prune_acl(acl);
+			free(acl);
+		}
+
 		if (p->appsession_name)
 			free(p->appsession_name);
 
@@ -745,10 +751,21 @@ void deinit(void)
 			free(h);
 			h = h_next;
 		}/* end while(h) */
-	
+
 		s = p->srv;
 		while (s) {
 			s_next = s->next;
+
+			if (s->check) {
+				task_delete(s->check);
+				task_free(s->check);
+			}
+
+			if (s->queue_mgt) {
+				task_delete(s->queue_mgt);
+				task_free(s->queue_mgt);
+			}
+
 			if (s->id)
 				free(s->id);
 	    
@@ -758,16 +775,17 @@ void deinit(void)
 			free(s);
 			s = s_next;
 		}/* end while(s) */
-	
+
 		l = p->listen;
 		while (l) {
 			l_next = l->next;
 			free(l);
 			l = l_next;
 		}/* end while(l) */
-	
+
 		pool_destroy2(p->req_cap_pool);
 		pool_destroy2(p->rsp_cap_pool);
+		pool_destroy2(p->hdr_idx_pool);
 		p0 = p;
 		p = p->next;
 		free(p0);
@@ -783,11 +801,12 @@ void deinit(void)
     
 	if (fdtab)            free(fdtab);
 	fdtab = NULL;
-    
+
 	pool_destroy2(pool2_session);
 	pool_destroy2(pool2_buffer);
 	pool_destroy2(pool2_requri);
 	pool_destroy2(pool2_task);
+	pool_destroy2(pool2_tree64);
 	pool_destroy2(pool2_capture);
 	pool_destroy2(pool2_appsess);
 	pool_destroy2(pool2_pendconn);
@@ -796,6 +815,9 @@ void deinit(void)
 		pool_destroy2(apools.serverid);
 		pool_destroy2(apools.sessid);
 	}
+
+	deinit_pollers();
+
 } /* end deinit() */
 
 /* sends the signal <sig> to all pids found in <oldpids> */
diff --git a/src/memory.c b/src/memory.c
index b157cf0..2fe3766 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -11,6 +11,7 @@
  */
 
 #include <common/config.h>
+#include <common/debug.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -51,6 +52,7 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
 			if (flags & entry->flags & MEM_F_SHARED) {
 				/* we can share this one */
 				pool = entry;
+				DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);
 				break;
 			}
 		}
-- 
1.5.5.1
Received on 2008/05/30 00:00

This archive was generated by hypermail 2.2.0 : 2008/05/30 00:15 CEST