Module: xenomai-forge Branch: next Commit: 7cf44bdf70b963d41d39fa419f16b787267b777d URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=7cf44bdf70b963d41d39fa419f16b787267b777d
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 | 98 +++++++++++++++++++++++++++++++++++++- 2 files changed, 113 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..2e4e399 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,77 @@ 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; + + push_cleanup_lock(&mh->lock); + write_lock(&mh->lock); + + /* Enforce hard limit. */ + if (mh->used + size > hobj->size) + goto out; + + /* Fix up and align request to match malloc_usable_size() */ + ptr = __STD(malloc(__align_to(size + 4, sizeof(unsigned long)))); + 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