Module: xenomai-forge
Branch: next
Commit: 4f454cdadfaa6ed4b2e73bd474c3151fd2aef940
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=4f454cdadfaa6ed4b2e73bd474c3151fd2aef940

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu May  9 12:22:05 2013 +0200

copperplate/heapobj-malloc: enforce hard limit on pool size

Applications may rely on hard limits when creating memory pools, to
detect over-consumption. Since the global malloc heap is virtually
illimited, we do allocation size accounting for each malloc-based
heap and reject over budget requests.

---

 include/copperplate/heapobj.h    |   52 ++++++--------------
 lib/copperplate/heapobj-malloc.c |   99 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/include/copperplate/heapobj.h b/include/copperplate/heapobj.h
index 2dad005..6eb874f 100644
--- a/include/copperplate/heapobj.h
+++ b/include/copperplate/heapobj.h
@@ -141,35 +141,6 @@ static inline char *pvstrdup(const char *ptr)
 #include <malloc.h>
 
 static inline
-void pvheapobj_destroy(struct heapobj *hobj)
-{
-}
-
-static inline
-int pvheapobj_extend(struct heapobj *hobj, size_t size, void *mem)
-{
-       return 0;
-}
-
-static inline
-void *pvheapobj_alloc(struct heapobj *hobj, size_t size)
-{
-       /*
-        * XXX: We don't want debug _nrt assertions to trigger when
-        * running over Cobalt if the user picked this allocator, so
-        * we make sure to call the glibc directly, not the Cobalt
-        * wrappers.
-        */
-       return __STD(malloc(size));
-}
-
-static inline
-void pvheapobj_free(struct heapobj *hobj, void *ptr)
-{
-       __STD(free(ptr));
-}
-
-static inline
 size_t pvheapobj_validate(struct heapobj *hobj, void *ptr)
 {
        /*
@@ -180,15 +151,14 @@ size_t pvheapobj_validate(struct heapobj *hobj, void *ptr)
        return malloc_usable_size(ptr);
 }
 
-static inline
-size_t pvheapobj_inquire(struct heapobj *hobj)
-{
-       struct mallinfo m = mallinfo();
-       return m.uordblks;
-}
-
 static inline void *pvmalloc(size_t size)
 {
+       /*
+        * NOTE: We don't want debug _nrt assertions to trigger when
+        * running over Cobalt if the user picked this allocator, so
+        * we make sure to call the glibc directly, not the Cobalt
+        * wrappers.
+        */
        return __STD(malloc(size));
 }
 
@@ -202,6 +172,16 @@ static inline char *pvstrdup(const char *ptr)
        return strdup(ptr);
 }
 
+void pvheapobj_destroy(struct heapobj *hobj);
+
+int pvheapobj_extend(struct heapobj *hobj, size_t size, void *mem);
+
+void *pvheapobj_alloc(struct heapobj *hobj, size_t size);
+
+void pvheapobj_free(struct heapobj *hobj, void *ptr);
+
+size_t pvheapobj_inquire(struct heapobj *hobj);
+
 #endif /* !CONFIG_XENO_TLSF */
 
 #ifdef CONFIG_XENO_PSHARED
diff --git a/lib/copperplate/heapobj-malloc.c b/lib/copperplate/heapobj-malloc.c
index 96814b9..ec44f89 100644
--- a/lib/copperplate/heapobj-malloc.c
+++ b/lib/copperplate/heapobj-malloc.c
@@ -20,19 +20,44 @@
 #include <stdio.h>
 #include <string.h>
 #include <malloc.h>
+#include <assert.h>
+#include <pthread.h>
+#include "copperplate/lock.h"
 #include "copperplate/heapobj.h"
 #include "copperplate/debug.h"
 
+struct malloc_heap {
+       pthread_mutex_t lock;
+       size_t used;
+};
+
 int __heapobj_init_private(struct heapobj *hobj, const char *name,
                           size_t size, void *mem)
 {
+       pthread_mutexattr_t mattr;
+       struct malloc_heap *mh;
+
        /*
         * There is no local pool when working with malloc, we just
         * use the global process arena. This should not be an issue
         * since this mode is aimed at debugging, particularly to be
         * used along with Valgrind.
+        *
+        * However, we maintain a control header to track the amount
+        * of memory currently consumed in each heap.
         */
-       hobj->pool = mem;       /* Never used. */
+       mh = malloc(sizeof(*mh));
+       if (mh == NULL)
+               return __bt(-ENOMEM);
+
+       __RT(pthread_mutexattr_init(&mattr));
+       __RT(pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT));
+       __RT(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE));
+       __RT(pthread_mutex_init(&mh->lock, &mattr));
+       __RT(pthread_mutexattr_destroy(&mattr));
+       mh->used = 0;
+
+       hobj->pool = mh;
        hobj->size = size;
        if (name)
                snprintf(hobj->name, sizeof(hobj->name), "%s", name);
@@ -48,6 +73,78 @@ int heapobj_init_array_private(struct heapobj *hobj, const 
char *name,
        return __bt(__heapobj_init_private(hobj, name, size * elems, NULL));
 }
 
+void pvheapobj_destroy(struct heapobj *hobj)
+{
+       struct malloc_heap *mh = hobj->pool;
+
+       __RT(pthread_mutex_destroy(&mh->lock));
+       __STD(free(mh));
+}
+
+int pvheapobj_extend(struct heapobj *hobj, size_t size, void *mem)
+{
+       struct malloc_heap *mh = hobj->pool;
+
+       write_lock_nocancel(&mh->lock);
+       hobj->size += size;
+       write_unlock(&mh->lock);
+
+       return 0;
+}
+
+static inline size_t __align_to(size_t size, size_t al)
+{
+       /* The alignment value must be a power of 2 */
+       return ((size+al-1)&(~(al-1)));
+}
+
+void *pvheapobj_alloc(struct heapobj *hobj, size_t size)
+{
+       struct malloc_heap *mh = hobj->pool;
+       void *ptr = NULL;
+
+       /* Align to match malloc_usable_size() */
+       size = __align_to(size, sizeof(unsigned long));
+       push_cleanup_lock(&mh->lock);
+       write_lock(&mh->lock);
+
+       /* Enforce hard limit. */
+       if (mh->used + size > hobj->size)
+               goto out;
+
+       ptr = __STD(malloc(size));
+       if (ptr == NULL)
+               goto out;
+
+       mh->used += size;
+out:
+       write_unlock(&mh->lock);
+       pop_cleanup_lock(&mh->lock);
+
+       return ptr;
+}
+
+void pvheapobj_free(struct heapobj *hobj, void *ptr)
+{
+       size_t size = malloc_usable_size(ptr);
+       struct malloc_heap *mh = hobj->pool;
+
+       push_cleanup_lock(&mh->lock);
+       write_lock(&mh->lock);
+       assert(hobj->size >= size);
+       mh->used -= size;
+       __STD(free(ptr));
+       write_unlock(&mh->lock);
+       pop_cleanup_lock(&mh->lock);
+}
+
+size_t pvheapobj_inquire(struct heapobj *hobj)
+{
+       struct malloc_heap *mh = hobj->pool;
+
+       return mh->used;
+}
+
 int heapobj_pkg_init_private(void)
 {
        return 0;


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to