/*
|
* Copyright (C) 2008-2011 Philippe Gerum <rpm@xenomai.org>.
|
*
|
* This library is free software; you can redistribute it and/or
|
* modify it under the terms of the GNU Lesser General Public
|
* License as published by the Free Software Foundation; either
|
* version 2 of the License, or (at your option) any later version.
|
*
|
* This library is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* Lesser General Public License for more details.
|
|
* You should have received a copy of the GNU Lesser General Public
|
* License along with this library; if not, write to the Free Software
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
*/
|
|
#ifndef _COPPERPLATE_HEAPOBJ_H
|
#define _COPPERPLATE_HEAPOBJ_H
|
|
#include <sys/types.h>
|
#include <stdint.h>
|
#include <string.h>
|
#include <assert.h>
|
#include <errno.h>
|
#include <pthread.h>
|
#include <xeno_config.h>
|
#include <boilerplate/wrappers.h>
|
#include <boilerplate/list.h>
|
#include <copperplate/reference.h>
|
#include <boilerplate/lock.h>
|
#include <copperplate/debug.h>
|
|
struct heapobj {
|
union {
|
dref_type(void *) pool_ref;
|
void *pool;
|
};
|
size_t size;
|
char name[32];
|
#ifdef CONFIG_XENO_PSHARED
|
char fsname[256];
|
#endif
|
};
|
|
struct sysgroup {
|
int thread_count;
|
struct listobj thread_list;
|
int heap_count;
|
struct listobj heap_list;
|
pthread_mutex_t lock;
|
};
|
|
#ifdef __cplusplus
|
extern "C" {
|
#endif
|
|
int heapobj_pkg_init_private(void);
|
|
int __heapobj_init_private(struct heapobj *hobj, const char *name,
|
size_t size, void *mem);
|
|
int heapobj_init_array_private(struct heapobj *hobj, const char *name,
|
size_t size, int elems);
|
#ifdef __cplusplus
|
}
|
#endif
|
|
#ifdef CONFIG_XENO_TLSF
|
|
size_t get_used_size(void *pool);
|
void destroy_memory_pool(void *pool);
|
size_t add_new_area(void *pool, size_t size, void *mem);
|
void *malloc_ex(size_t size, void *pool);
|
void free_ex(void *pool, void *ptr);
|
void *tlsf_malloc(size_t size);
|
void tlsf_free(void *ptr);
|
size_t malloc_usable_size_ex(void *ptr, void *pool);
|
|
static inline
|
void pvheapobj_destroy(struct heapobj *hobj)
|
{
|
destroy_memory_pool(hobj->pool);
|
}
|
|
static inline
|
int pvheapobj_extend(struct heapobj *hobj, size_t size, void *mem)
|
{
|
hobj->size = add_new_area(hobj->pool, size, mem);
|
if (hobj->size == (size_t)-1)
|
return __bt(-EINVAL);
|
|
return 0;
|
}
|
|
static inline
|
void *pvheapobj_alloc(struct heapobj *hobj, size_t size)
|
{
|
return malloc_ex(size, hobj->pool);
|
}
|
|
static inline
|
void pvheapobj_free(struct heapobj *hobj, void *ptr)
|
{
|
free_ex(ptr, hobj->pool);
|
}
|
|
static inline
|
size_t pvheapobj_validate(struct heapobj *hobj, void *ptr)
|
{
|
return malloc_usable_size_ex(ptr, hobj->pool);
|
}
|
|
static inline
|
size_t pvheapobj_inquire(struct heapobj *hobj)
|
{
|
return get_used_size(hobj->pool);
|
}
|
|
static inline void *pvmalloc(size_t size)
|
{
|
return tlsf_malloc(size);
|
}
|
|
static inline void pvfree(void *ptr)
|
{
|
tlsf_free(ptr);
|
}
|
|
static inline char *pvstrdup(const char *ptr)
|
{
|
char *str;
|
|
str = (char *)pvmalloc(strlen(ptr) + 1);
|
if (str == NULL)
|
return NULL;
|
|
return strcpy(str, ptr);
|
}
|
|
#elif defined(CONFIG_XENO_HEAPMEM)
|
|
#include <stdlib.h>
|
#include <boilerplate/heapmem.h>
|
|
extern struct heap_memory heapmem_main;
|
|
static inline
|
void pvheapobj_destroy(struct heapobj *hobj)
|
{
|
heapmem_destroy((struct heap_memory *)hobj->pool);
|
if (hobj->pool != (void *)&heapmem_main)
|
__STD(free(hobj->pool));
|
}
|
|
static inline
|
int pvheapobj_extend(struct heapobj *hobj, size_t size, void *mem)
|
{
|
return heapmem_extend((struct heap_memory *)hobj->pool,
|
mem, size);
|
}
|
|
static inline
|
void *pvheapobj_alloc(struct heapobj *hobj, size_t size)
|
{
|
return heapmem_alloc((struct heap_memory *)hobj->pool, size);
|
}
|
|
static inline
|
void pvheapobj_free(struct heapobj *hobj, void *ptr)
|
{
|
heapmem_free((struct heap_memory *)hobj->pool, ptr);
|
}
|
|
static inline
|
size_t pvheapobj_validate(struct heapobj *hobj, void *ptr)
|
{
|
ssize_t size = heapmem_check((struct heap_memory *)hobj->pool, ptr);
|
return size < 0 ? 0 : size;
|
}
|
|
static inline
|
size_t pvheapobj_inquire(struct heapobj *hobj)
|
{
|
return heapmem_used_size((struct heap_memory *)hobj->pool);
|
}
|
|
static inline void *pvmalloc(size_t size)
|
{
|
return heapmem_alloc(&heapmem_main, size);
|
}
|
|
static inline void pvfree(void *ptr)
|
{
|
heapmem_free(&heapmem_main, ptr);
|
}
|
|
static inline char *pvstrdup(const char *ptr)
|
{
|
char *str;
|
|
str = (char *)pvmalloc(strlen(ptr) + 1);
|
if (str == NULL)
|
return NULL;
|
|
return strcpy(str, ptr);
|
}
|
|
#else /* !CONFIG_XENO_HEAPMEM, i.e. malloc */
|
|
#include <stdlib.h>
|
|
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));
|
}
|
|
static inline void pvfree(void *ptr)
|
{
|
__STD(free(ptr));
|
}
|
|
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);
|
|
size_t pvheapobj_validate(struct heapobj *hobj, void *ptr);
|
|
#endif /* !CONFIG_XENO_HEAPMEM */
|
|
#ifdef CONFIG_XENO_PSHARED
|
|
extern void *__main_heap;
|
|
extern struct hash_table *__main_catalog;
|
#define main_catalog (*((struct hash_table *)__main_catalog))
|
|
extern struct sysgroup *__main_sysgroup;
|
|
struct sysgroup_memspec {
|
/** next member in sysgroup list. */
|
struct holder next;
|
};
|
|
static inline void *mainheap_ptr(memoff_t off)
|
{
|
return off ? (void *)__memptr(__main_heap, off) : NULL;
|
}
|
|
static inline memoff_t mainheap_off(void *addr)
|
{
|
return addr ? (memoff_t)__memoff(__main_heap, addr) : 0;
|
}
|
|
/*
|
* ptr shall point to a block of memory allocated within the main heap
|
* if non-null; such address is always 8-byte aligned. Handles of
|
* shared heap pointers are returned with bit #0 set, which serves as
|
* a special tag detected in mainhead_deref(). A null pointer is
|
* always translated as a null handle.
|
*/
|
#define mainheap_ref(ptr, type) \
|
({ \
|
type handle; \
|
assert(__builtin_types_compatible_p(typeof(type), unsigned long) || \
|
__builtin_types_compatible_p(typeof(type), uintptr_t)); \
|
assert(ptr == NULL || __memchk(__main_heap, ptr)); \
|
handle = (type)mainheap_off(ptr); \
|
handle|1; \
|
})
|
/*
|
* Handles of shared heap-based pointers have bit #0 set. Other values
|
* are not translated, and the return value is the original handle
|
* cast to a pointer. A null handle is always returned unchanged.
|
*/
|
#define mainheap_deref(handle, type) \
|
({ \
|
type *ptr; \
|
assert(__builtin_types_compatible_p(typeof(handle), unsigned long) || \
|
__builtin_types_compatible_p(typeof(handle), uintptr_t)); \
|
ptr = (handle & 1) ? (type *)mainheap_ptr(handle & ~1UL) : (type *)handle; \
|
ptr; \
|
})
|
|
static inline void
|
__sysgroup_add(struct sysgroup_memspec *obj, struct listobj *q, int *countp)
|
{
|
write_lock_nocancel(&__main_sysgroup->lock);
|
(*countp)++;
|
list_append(&obj->next, q);
|
write_unlock(&__main_sysgroup->lock);
|
}
|
|
#define sysgroup_add(__group, __obj) \
|
__sysgroup_add(__obj, &(__main_sysgroup->__group ## _list), \
|
&(__main_sysgroup->__group ## _count))
|
|
static inline void
|
__sysgroup_remove(struct sysgroup_memspec *obj, int *countp)
|
{
|
write_lock_nocancel(&__main_sysgroup->lock);
|
(*countp)--;
|
list_remove(&obj->next);
|
write_unlock(&__main_sysgroup->lock);
|
}
|
|
#define sysgroup_remove(__group, __obj) \
|
__sysgroup_remove(__obj, &(__main_sysgroup->__group ## _count))
|
|
static inline void sysgroup_lock(void)
|
{
|
read_lock_nocancel(&__main_sysgroup->lock);
|
}
|
|
static inline void sysgroup_unlock(void)
|
{
|
read_unlock(&__main_sysgroup->lock);
|
}
|
|
#define sysgroup_count(__group) \
|
(__main_sysgroup->__group ## _count)
|
|
#define for_each_sysgroup(__obj, __tmp, __group) \
|
list_for_each_entry_safe(__obj, __tmp, &(__main_sysgroup->__group ## _list), next)
|
|
int heapobj_pkg_init_shared(void);
|
|
int heapobj_init(struct heapobj *hobj, const char *name,
|
size_t size);
|
|
static inline int __heapobj_init(struct heapobj *hobj, const char *name,
|
size_t size, void *unused)
|
{
|
/* Can't work on user-defined memory in shared mode. */
|
return heapobj_init(hobj, name, size);
|
}
|
|
int heapobj_init_array(struct heapobj *hobj, const char *name,
|
size_t size, int elems);
|
|
void heapobj_destroy(struct heapobj *hobj);
|
|
int heapobj_extend(struct heapobj *hobj,
|
size_t size, void *mem);
|
|
void *heapobj_alloc(struct heapobj *hobj,
|
size_t size);
|
|
void heapobj_free(struct heapobj *hobj,
|
void *ptr);
|
|
size_t heapobj_validate(struct heapobj *hobj,
|
void *ptr);
|
|
size_t heapobj_inquire(struct heapobj *hobj);
|
|
size_t heapobj_get_size(struct heapobj *hobj);
|
|
int heapobj_bind_session(const char *session);
|
|
void heapobj_unbind_session(void);
|
|
int heapobj_unlink_session(const char *session);
|
|
void *xnmalloc(size_t size);
|
|
void xnfree(void *ptr);
|
|
char *xnstrdup(const char *ptr);
|
|
#else /* !CONFIG_XENO_PSHARED */
|
|
struct sysgroup_memspec {
|
};
|
|
/*
|
* Whether an object is laid in some shared heap. Never if pshared
|
* mode is disabled.
|
*/
|
static inline int pshared_check(void *heap, void *addr)
|
{
|
return 0;
|
}
|
|
#ifdef __cplusplus
|
#define __check_ref_width(__dst, __src) \
|
({ \
|
assert(sizeof(__dst) >= sizeof(__src)); \
|
(typeof(__dst))__src; \
|
})
|
#else
|
#define __check_ref_width(__dst, __src) \
|
__builtin_choose_expr( \
|
sizeof(__dst) >= sizeof(__src), (typeof(__dst))__src, \
|
((void)0))
|
#endif
|
|
#define mainheap_ref(ptr, type) \
|
({ \
|
type handle; \
|
handle = __check_ref_width(handle, ptr); \
|
assert(ptr == NULL || __memchk(__main_heap, ptr)); \
|
handle; \
|
})
|
#define mainheap_deref(handle, type) \
|
({ \
|
type *ptr; \
|
ptr = __check_ref_width(ptr, handle); \
|
ptr; \
|
})
|
|
#define sysgroup_add(__group, __obj) do { } while (0)
|
#define sysgroup_remove(__group, __obj) do { } while (0)
|
|
static inline int heapobj_pkg_init_shared(void)
|
{
|
return 0;
|
}
|
|
static inline int __heapobj_init(struct heapobj *hobj, const char *name,
|
size_t size, void *mem)
|
{
|
return __heapobj_init_private(hobj, name, size, mem);
|
}
|
|
static inline int heapobj_init(struct heapobj *hobj, const char *name,
|
size_t size)
|
{
|
return __heapobj_init_private(hobj, name, size, NULL);
|
}
|
|
static inline int heapobj_init_array(struct heapobj *hobj, const char *name,
|
size_t size, int elems)
|
{
|
return heapobj_init_array_private(hobj, name, size, elems);
|
}
|
|
static inline void heapobj_destroy(struct heapobj *hobj)
|
{
|
pvheapobj_destroy(hobj);
|
}
|
|
static inline int heapobj_extend(struct heapobj *hobj,
|
size_t size, void *mem)
|
{
|
return pvheapobj_extend(hobj, size, mem);
|
}
|
|
static inline void *heapobj_alloc(struct heapobj *hobj,
|
size_t size)
|
{
|
return pvheapobj_alloc(hobj, size);
|
}
|
|
static inline void heapobj_free(struct heapobj *hobj,
|
void *ptr)
|
{
|
pvheapobj_free(hobj, ptr);
|
}
|
|
static inline size_t heapobj_validate(struct heapobj *hobj,
|
void *ptr)
|
{
|
return pvheapobj_validate(hobj, ptr);
|
}
|
|
static inline size_t heapobj_inquire(struct heapobj *hobj)
|
{
|
return pvheapobj_inquire(hobj);
|
}
|
|
static inline int heapobj_bind_session(const char *session)
|
{
|
return -ENOSYS;
|
}
|
|
static inline int heapobj_unlink_session(const char *session)
|
{
|
return 0;
|
}
|
|
static inline void heapobj_unbind_session(void) { }
|
|
static inline void *xnmalloc(size_t size)
|
{
|
return pvmalloc(size);
|
}
|
|
static inline void xnfree(void *ptr)
|
{
|
pvfree(ptr);
|
}
|
|
static inline char *xnstrdup(const char *ptr)
|
{
|
return pvstrdup(ptr);
|
}
|
|
#endif /* !CONFIG_XENO_PSHARED */
|
|
static inline const char *heapobj_name(struct heapobj *hobj)
|
{
|
return hobj->name;
|
}
|
|
static inline size_t heapobj_size(struct heapobj *hobj)
|
{
|
return hobj->size;
|
}
|
|
#endif /* _COPPERPLATE_HEAPOBJ_H */
|