Start to fix talloc memlimits with talloc pools.
authorJeremy Allison <jra@samba.org>
Tue, 27 Aug 2013 19:36:23 +0000 (12:36 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 27 Aug 2013 22:44:19 +0000 (15:44 -0700)
Add the functions:

talloc_memlimit_grow(), talloc_memlimit_shrink(),
talloc_memlimit_update_on_free().

as replacements for talloc_memlimit_update().
The interface to talloc_memlimit_update() is very
hard to understand and use. The above functions
are (to me) much clearer.

The goal of these changes is to only update
the memlimits on malloc/free/realloc, not
on every pool allocation. That way we only
count pool creation as allocation from any
imposed limits, not allocation from an already
created pool.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Simo Sorce <idra@samba.org>
lib/talloc/talloc.c

index 76f0aeedfd4209f7d4cf6ac7aca4ec93cbed57e8..067d46f97d3100c2bc3fe53fc4f624166d2650c7 100644 (file)
@@ -238,6 +238,11 @@ struct talloc_memlimit {
 static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size);
 static bool talloc_memlimit_update(struct talloc_memlimit *limit,
                                   size_t old_size, size_t new_size);
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+                               size_t size);
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+                               size_t size);
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc);
 
 typedef int (*talloc_destructor_t)(void *);
 
@@ -2564,6 +2569,73 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
        return true;
 }
 
+/*
+  Update memory limits when freeing a talloc_chunk.
+*/
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
+{
+       if (!tc->limit) {
+               return;
+       }
+
+       /*
+        * Pool entries don't count. Only the pools
+        * themselves are counted as part of the memory
+        * limits.
+        */
+       if (tc->flags & TALLOC_FLAG_POOLMEM) {
+               return;
+       }
+
+       /*
+        * If we are part of a memory limited context hierarchy
+        * we need to subtract the memory used from the counters
+        */
+
+       talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE);
+
+       if (tc->limit->parent == tc) {
+               free(tc->limit);
+       }
+
+       tc->limit = NULL;
+}
+
+/*
+  Increase memory limit accounting after a malloc/realloc.
+*/
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+                               size_t size)
+{
+       struct talloc_memlimit *l;
+
+       for (l = limit; l != NULL; l = l->upper) {
+               size_t new_cur_size = l->cur_size + size;
+               if (new_cur_size < l->cur_size) {
+                       talloc_abort("logic error in talloc_memlimit_grow\n");
+                       return;
+               }
+               l->cur_size = new_cur_size;
+       }
+}
+
+/*
+  Decrease memory limit accounting after a free/realloc.
+*/
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+                               size_t size)
+{
+       struct talloc_memlimit *l;
+
+       for (l = limit; l != NULL; l = l->upper) {
+               if (l->cur_size < size) {
+                       talloc_abort("logic error in talloc_memlimit_shrink\n");
+                       return;
+               }
+               l->cur_size = l->cur_size - size;
+       }
+}
+
 static bool talloc_memlimit_update(struct talloc_memlimit *limit,
                                   size_t old_size, size_t new_size)
 {