From 2c46df1916a25b7880416aee974a518cc607717a Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 16 Oct 2009 17:45:19 +0000 Subject: New heap manager. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1221 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/kernel/include/ch.h | 1 + os/kernel/include/heap.h | 47 +++++++- os/kernel/include/mem.h | 61 ----------- os/kernel/include/memcore.h | 74 +++++++++++++ os/kernel/include/threads.h | 4 +- os/kernel/kernel.mk | 1 + os/kernel/src/chheap.c | 222 +++++++++++++++++++++----------------- os/kernel/src/chmem.c | 94 ---------------- os/kernel/src/chmemcore.c | 99 +++++++++++++++++ os/kernel/src/chsys.c | 3 + os/kernel/src/chthreads.c | 7 +- os/kernel/templates/chconf.h | 248 +++++++++++++++++++++++++++++-------------- 12 files changed, 524 insertions(+), 337 deletions(-) delete mode 100644 os/kernel/include/mem.h create mode 100644 os/kernel/include/memcore.h delete mode 100644 os/kernel/src/chmem.c create mode 100644 os/kernel/src/chmemcore.c (limited to 'os/kernel') diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h index 46d917e29..fa30c0eaf 100644 --- a/os/kernel/include/ch.h +++ b/os/kernel/include/ch.h @@ -75,6 +75,7 @@ #include "events.h" #include "messages.h" #include "mailboxes.h" +#include "memcore.h" #include "heap.h" #include "mempools.h" #include "threads.h" diff --git a/os/kernel/include/heap.h b/os/kernel/include/heap.h index 4fbd48225..1f07faa91 100644 --- a/os/kernel/include/heap.h +++ b/os/kernel/include/heap.h @@ -27,17 +27,60 @@ #ifndef _HEAP_H_ #define _HEAP_H_ +#if CH_USE_HEAP + +/* + * Module dependancies check. + */ +#if !CH_USE_MEMCORE && !CH_USE_MALLOC_HEAP +#error "CH_USE_HEAP requires CH_USE_MEM" +#endif + +#if !CH_USE_MUTEXES && !CH_USE_SEMAPHORES +#error "CH_USE_HEAP requires CH_USE_MUTEXES and/or CH_USE_SEMAPHORES" +#endif + +typedef struct memory_heap MemoryHeap; + +/** + * @brief Memory heap block header. + */ +struct heap_header { + union { + struct heap_header *h_next; /**< @brief Next block in free list. */ + MemoryHeap *h_heap; /**< @brief Block owner heap. */ + }; + size_t h_size; /**< @brief Size of the memory block. */ +}; + +/** + * @brief Structure describing a memory heap. + */ +struct memory_heap { + memgetfunc_t h_provider; /**< @brief Memory blocks provider for + this heap. */ + struct heap_header h_free; /**< @brief Free blocks list header. */ +#if CH_USE_MUTEXES + Mutex h_mtx; /**< @brief Heap access mutex. */ +#else + Semaphore h_sem; /**< @brief Heap access semaphore. */ +#endif +}; + #ifdef __cplusplus extern "C" { #endif void heap_init(void); - void *chHeapAlloc(size_t size); + void chHeapInit(MemoryHeap *heapp, void *buf, size_t size); + void *chHeapAlloc(MemoryHeap *heapp, size_t size); void chHeapFree(void *p); - size_t chHeapStatus(size_t *sizep); + size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep); #ifdef __cplusplus } #endif +#endif /* CH_USE_HEAP */ + #endif /* _HEAP_H_ */ /** @} */ diff --git a/os/kernel/include/mem.h b/os/kernel/include/mem.h deleted file mode 100644 index c7f5ba07a..000000000 --- a/os/kernel/include/mem.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. - - This file is part of ChibiOS/RT. - - ChibiOS/RT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - ChibiOS/RT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/** - * @file mem.h - * @brief Low level memory manager macros and structures. - * @addtogroup coremem - * @{ - */ - -#ifndef _MEM_H_ -#define _MEM_H_ - -#if CH_USE_COREMEM - -/** - * @brief Memory alignment type. - */ -typedef void *align_t; - -/** - * @brief Alignment mask constant. - */ -#define MEM_ALIGN_MASK (sizeof(align_t) - 1) - -/** - * @brief Alignment helper macro. - */ -#define MEM_ALIGN_SIZE(p) (((size_t)(p) + ALIGN_MASK) & ~ALIGN_MASK) - -#ifdef __cplusplus -extern "C" { -#endif - void mem_init(void); - void *chMemAlloc(size_t size); - void *chMemAllocI(size_t size); -#ifdef __cplusplus -} -#endif - -#endif /* CH_USE_COREMEM */ - -#endif /* _MEM_H_ */ - -/** @} */ diff --git a/os/kernel/include/memcore.h b/os/kernel/include/memcore.h new file mode 100644 index 000000000..8f3fe4671 --- /dev/null +++ b/os/kernel/include/memcore.h @@ -0,0 +1,74 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file memcore.h + * @brief Core memory manager macros and structures. + * @addtogroup memcore + * @{ + */ + +#ifndef _MEMCORE_H_ +#define _MEMCORE_H_ + +#if CH_USE_MEMCORE + +/** + * @brief Memory alignment type. + */ +typedef void *align_t; + +/** + * @brief Memory get function. + * @note This type must be assignment compatible with the @p chMemAlloc() + * function. + */ +typedef void *(*memgetfunc_t)(size_t size); + +/** + * @brief Alignment mask constant. + */ +#define MEM_ALIGN_MASK (sizeof(align_t) - 1) + +/** + * @brief Alignment helper macro. + */ +#define MEM_ALIGN_SIZE(p) (((size_t)(p) + MEM_ALIGN_MASK) & ~MEM_ALIGN_MASK) + +/** + * @brief Returns whatever a pointer or memory size is aligned to + * the type @p align_t. + */ +#define MEM_IS_ALIGNED(p) (((size_t)(p) & MEM_ALIGN_MASK) == 0) + +#ifdef __cplusplus +extern "C" { +#endif + void core_init(void); + void *chCoreAlloc(size_t size); + void *chCoreAllocI(size_t size); +#ifdef __cplusplus +} +#endif + +#endif /* CH_USE_MEMCORE */ + +#endif /* _MEMCORE_H_ */ + +/** @} */ diff --git a/os/kernel/include/threads.h b/os/kernel/include/threads.h index 1b9850435..ccafc3e96 100644 --- a/os/kernel/include/threads.h +++ b/os/kernel/include/threads.h @@ -167,8 +167,8 @@ extern "C" { Thread *chThdCreateStatic(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg); #if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP - Thread *chThdCreateFromHeap(size_t size, tprio_t prio, - tfunc_t pf, void *arg); + Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size, + tprio_t prio, tfunc_t pf, void *arg); #endif #if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio, diff --git a/os/kernel/kernel.mk b/os/kernel/kernel.mk index adbe0af9c..47c8bb1d4 100644 --- a/os/kernel/kernel.mk +++ b/os/kernel/kernel.mk @@ -13,6 +13,7 @@ KERNSRC = ${CHIBIOS}/os/kernel/src/chsys.c \ ${CHIBIOS}/os/kernel/src/chmsg.c \ ${CHIBIOS}/os/kernel/src/chmboxes.c \ ${CHIBIOS}/os/kernel/src/chqueues.c \ + ${CHIBIOS}/os/kernel/src/chmemcore.c \ ${CHIBIOS}/os/kernel/src/chheap.c \ ${CHIBIOS}/os/kernel/src/chmempools.c diff --git a/os/kernel/src/chheap.c b/os/kernel/src/chheap.c index b5ad50505..e7a975f3d 100644 --- a/os/kernel/src/chheap.c +++ b/os/kernel/src/chheap.c @@ -28,41 +28,23 @@ #if CH_USE_HEAP -#if !CH_USE_MALLOC_HEAP - -#define MAGIC 0xF5A0 -#define ALIGN_TYPE void * -#define ALIGN_MASK (sizeof(ALIGN_TYPE) - 1) -#define ALIGN_SIZE(p) (((size_t)(p) + ALIGN_MASK) & ~ALIGN_MASK) - -struct header { - union { - struct header *h_next; - size_t h_magic; - }; - size_t h_size; -}; - -static struct { - struct header free; /* Guaranteed to be not adjacent to the heap */ +/* + * Defaults on the best synchronization mechanism available. + */ #if CH_USE_MUTEXES -#define H_LOCK() chMtxLock(&heap.hmtx) -#define H_UNLOCK() chMtxUnlock() - Mutex hmtx; -#elif CH_USE_SEMAPHORES -#define H_LOCK() chSemWait(&heap.hsem) -#define H_UNLOCK() chSemSignal(&heap.hsem) - Semaphore hsem; +#define H_LOCK(h) chMtxLock(&(h)->h_mtx) +#define H_UNLOCK(h) chMtxUnlock() #else -#error "The heap allocator requires mutexes or semaphores to be enabled" +#define H_LOCK(h) chSemWait(&(h)->h_sem) +#define H_UNLOCK(h) chSemSignal(&(h)->h_sem) #endif -#if CH_HEAP_SIZE > 0 - union { - ALIGN_TYPE alignment; - char buffer[ALIGN_SIZE(CH_HEAP_SIZE)]; - }; -#endif -} heap; + +#if !CH_USE_MALLOC_HEAP + +/** + * @brief Default heap descriptor. + */ +static MemoryHeap default_heap; /** * @brief Initializes the allocator subsystem. @@ -70,26 +52,40 @@ static struct { * @note Internal use only. */ void heap_init(void) { - struct header *hp; - -#if CH_HEAP_SIZE == 0 - extern char __heap_base__; - extern char __heap_end__; - - hp = (void *)&__heap_base__; - hp->h_size = &__heap_end__ - &__heap_base__ - sizeof(struct header); + default_heap.h_provider = chCoreAlloc; + default_heap.h_free.h_next = NULL; + default_heap.h_free.h_size = 0; +#if CH_USE_MUTEXES + chMtxInit(&default_heap.h_mtx); #else - hp = (void *)&heap.buffer[0]; - hp->h_size = (&heap.buffer[ALIGN_SIZE(CH_HEAP_SIZE)] - &heap.buffer[0]) - - sizeof(struct header); + chSemInit(&default_heap.h_sem, 1); #endif +} + +/** + * @brief Initializes a memory heap. + * + * @param[out] heapp pointer to a memory heap descriptor to be initialized + * @param[in] buf heap buffer base + * @param[in] size heap size + * + * @note Both the heap buffer base and the heap size must be aligned to + * the @p align_t type size. + */ +void chHeapInit(MemoryHeap *heapp, void *buf, size_t size) { + struct heap_header *hp; + + chDbgCheck(MEM_IS_ALIGNED(buf) && MEM_IS_ALIGNED(size), "chHeapInit"); + + heapp->h_provider = NULL; + heapp->h_free.h_next = hp = buf; + heapp->h_free.h_size = 0; hp->h_next = NULL; - heap.free.h_next = hp; - heap.free.h_size = 0; + hp->h_size = size - sizeof(struct heap_header); #if CH_USE_MUTEXES - chMtxInit(&heap.hmtx); + chMtxInit(&heapp->h_mtx); #else - chSemInit(&heap.hsem, 1); + chSemInit(&heapp->h_sem, 1); #endif } @@ -97,53 +93,75 @@ void heap_init(void) { * @brief Allocates a block of memory from the heap by using the first-fit * algorithm. * @details The allocated block is guaranteed to be properly aligned for a - * pointer data type. + * pointer data type (@p align_t). * + * @param[in] heapp pointer to a heap descriptor or @p NULL in order to access + * the default heap. * @param[in] size the size of the block to be allocated. Note that the * allocated block may be a bit bigger than the requested * size for alignment and fragmentation reasons. * @return A pointer to the allocated block. * @retval NULL if the block cannot be allocated. */ -void *chHeapAlloc(size_t size) { - struct header *qp, *hp, *fp; +void *chHeapAlloc(MemoryHeap *heapp, size_t size) { + struct heap_header *qp, *hp, *fp; - size = ALIGN_SIZE(size); - qp = &heap.free; - H_LOCK(); + if (heapp == NULL) + heapp = &default_heap; + + size = MEM_ALIGN_SIZE(size); + qp = &heapp->h_free; + H_LOCK(heapp); while (qp->h_next != NULL) { hp = qp->h_next; if (hp->h_size >= size) { - if (hp->h_size < size + sizeof(struct header)) { - /* Gets the whole block even if it is slightly bigger than the - requested size because the fragment would be too small to be - useful */ + if (hp->h_size < size + sizeof(struct heap_header)) { + /* + * Gets the whole block even if it is slightly bigger than the + * requested size because the fragment would be too small to be + * useful. + */ qp->h_next = hp->h_next; } else { - /* Block bigger enough, must split it */ - fp = (void *)((char *)(hp) + sizeof(struct header) + size); + /* + * Block bigger enough, must split it. + */ + fp = (void *)((uint8_t *)(hp) + sizeof(struct heap_header) + size); fp->h_next = hp->h_next; - fp->h_size = hp->h_size - sizeof(struct header) - size; + fp->h_size = hp->h_size - sizeof(struct heap_header) - size; qp->h_next = fp; hp->h_size = size; } - hp->h_magic = MAGIC; + hp->h_heap = heapp; - H_UNLOCK(); + H_UNLOCK(heapp); return (void *)(hp + 1); } qp = hp; } - H_UNLOCK(); + H_UNLOCK(heapp); + + /* + * More memory is required, tries to get it from the associated provider. + */ + if (heapp->h_provider) { + hp = heapp->h_provider(size + sizeof(struct heap_header)); + if (hp != NULL) { + hp->h_heap = heapp; + hp->h_size = size; + hp++; + return (void *)hp; + } + } return NULL; } -#define LIMIT(p) (struct header *)((char *)(p) + \ - sizeof(struct header) + \ - (p)->h_size) +#define LIMIT(p) (struct heap_header *)((uint8_t *)(p) + \ + sizeof(struct heap_header) + \ + (p)->h_size) /** * @brief Frees a previously allocated memory block. @@ -151,50 +169,59 @@ void *chHeapAlloc(size_t size) { * @param[in] p the memory block pointer */ void chHeapFree(void *p) { - struct header *qp, *hp; + struct heap_header *qp, *hp; + MemoryHeap *heapp; chDbgCheck(p != NULL, "chHeapFree"); - hp = (struct header *)p - 1; - chDbgAssert(hp->h_magic == MAGIC, - "chHeapFree(), #1", - "it is not magic"); - qp = &heap.free; - H_LOCK(); + hp = (struct heap_header *)p - 1; + heapp = hp->h_heap; + qp = &heapp->h_free; + H_LOCK(heapp); while (TRUE) { - chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), - "chHeapFree(), #2", + "chHeapFree(), #1", "within free block"); - if (((qp == &heap.free) || (hp > qp)) && + if (((qp == &heapp->h_free) || (hp > qp)) && ((qp->h_next == NULL) || (hp < qp->h_next))) { - /* Insertion after qp */ + /* + * Insertion after qp. + */ hp->h_next = qp->h_next; qp->h_next = hp; - /* Verifies if the newly inserted block should be merged */ + /* + * Verifies if the newly inserted block should be merged. + */ if (LIMIT(hp) == hp->h_next) { - /* Merge with the next block */ - hp->h_size += hp->h_next->h_size + sizeof(struct header); + /* + * Merge with the next block. + */ + hp->h_size += hp->h_next->h_size + sizeof(struct heap_header); hp->h_next = hp->h_next->h_next; } - if ((LIMIT(qp) == hp)) { /* Cannot happen when qp == &heap.free */ - /* Merge with the previous block */ - qp->h_size += hp->h_size + sizeof(struct header); + if ((LIMIT(qp) == hp)) { + /* + * Merge with the previous block. + */ + qp->h_size += hp->h_size + sizeof(struct heap_header); qp->h_next = hp->h_next; } - - H_UNLOCK(); - return; + break; } qp = qp->h_next; } + + H_UNLOCK(heapp); + return; } /** * @brief Reports the heap status. * + * @param[in] heapp pointer to a heap descriptor or @p NULL in order to access + * the default heap. * @param[in] sizep pointer to a variable that will receive the total * fragmented free space * @return The number of fragments in the heap. @@ -203,19 +230,22 @@ void chHeapFree(void *p) { * @note This function is not implemented when the @p CH_USE_MALLOC_HEAP * configuration option is used (it always returns zero). */ -size_t chHeapStatus(size_t *sizep) { - struct header *qp; +size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep) { + struct heap_header *qp; size_t n, sz; - H_LOCK(); + if (heapp == NULL) + heapp = &default_heap; + + H_LOCK(heapp); sz = 0; - for (n = 0, qp = &heap.free; qp->h_next; n++, qp = qp->h_next) + for (n = 0, qp = &heapp->h_free; qp->h_next; n++, qp = qp->h_next) sz += qp->h_next->h_size; if (sizep) *sizep = sz; - H_UNLOCK(); + H_UNLOCK(heapp); return n; } @@ -231,8 +261,6 @@ static Mutex hmtx; #define H_LOCK() chSemWait(&hsem) #define H_UNLOCK() chSemSignal(&hsem) static Semaphore hsem; -#else -#error "The heap allocator requires mutexes or semaphores to be enabled" #endif void heap_init(void) { @@ -244,9 +272,11 @@ void heap_init(void) { #endif } -void *chHeapAlloc(size_t size) { +void *chHeapAlloc(MemoryHeap *heapp, size_t size) { void *p; + chDbgCheck(heapp == NULL, "chHeapAlloc"); + H_LOCK(); p = malloc(size); H_UNLOCK(); @@ -262,7 +292,9 @@ void chHeapFree(void *p) { H_UNLOCK(); } -size_t chHeapStatus(size_t *sizep) { +size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep) { + + chDbgCheck(heapp == NULL, "chHeapStatus"); if (sizep) *sizep = 0; diff --git a/os/kernel/src/chmem.c b/os/kernel/src/chmem.c deleted file mode 100644 index 3ac45a6ae..000000000 --- a/os/kernel/src/chmem.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. - - This file is part of ChibiOS/RT. - - ChibiOS/RT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - ChibiOS/RT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/** - * @file chmem.c - * @brief Low level memory manager code. - * @addtogroup coremem - * @{ - */ - -#include - -#if CH_USE_COREMEM - -#if CH_COREMEM_SIZE == 0 - extern align_t __heap_base__; - extern align_t __heap_end__; -#else -align_t buffer[ALIGN_SIZE(CH_MEM_SIZE) / sizeof(align_t)]; -#endif - -static align_t *nextmem; -static align_t *endmem; - -void mem_init(void) { -#if CH_COREMEM_SIZE == 0 - nextmem = &__heap_base__; - endmem = &__heap_end__; -#else - nextmem = &buffer[0]; - endmem = &buffer[ALIGN_SIZE(CH_MEM_SIZE) / sizeof(align_t)]; -#endif -} - -/** - * @brief Allocates a block of memory. - * @details The size of the returned block is aligned to the alignment - * type @p align_t so it is not possible to allocate less than - * sizeof(align_t). - * - * - * @param[in] the size of the block to be allocated - * @return A pointer to the allocated memory block. - * @retval NULL allocation failed, core memory exhausted. - */ -void *chCoreAlloc(size_t size) { - void *p; - - chSysLock(); - p = chCoreAllocI(size); - chSysUnlock(); - return p; -} - -/** - * @brief Allocates a block of memory. - * @details The size of the returned block is aligned to the alignment - * type @p align_t so it is not possible to allocate less than - * sizeof(align_t). - * - * @param[in] the size of the block to be allocated. - * @return A pointer to the allocated memory block. - * @retval NULL allocation failed, core memory exhausted. - */ -void *chCoreAllocI(size_t size) { - void *p; - - size = ALIGN_SIZE(size); - if (nextmem + size > endmem) - return NULL; - p = nextmem; - nextmem += size; - return p; -} - -#endif /* CH_USE_COREMEM */ - -/** @} */ diff --git a/os/kernel/src/chmemcore.c b/os/kernel/src/chmemcore.c new file mode 100644 index 000000000..87ef6037a --- /dev/null +++ b/os/kernel/src/chmemcore.c @@ -0,0 +1,99 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file chmemcore.c + * @brief Core memory manager code. + * @addtogroup memcore + * @{ + */ + +#include + +#if CH_USE_MEMCORE + +#if CH_MEMCORE_SIZE == 0 + extern align_t __heap_base__; + extern align_t __heap_end__; +#else +align_t buffer[ALIGN_SIZE(CH_MEMCORE_SIZE) / sizeof(align_t)]; +#endif + +static align_t *nextmem; +static align_t *endmem; + +/** + * @brief Low level memory manager initialization. + * + * @note Internal use only. + */ +void core_init(void) { +#if CH_MEMCORE_SIZE == 0 + nextmem = &__heap_base__; + endmem = &__heap_end__; +#else + nextmem = &buffer[0]; + endmem = &buffer[ALIGN_SIZE(CH_MEMCORE_SIZE) / sizeof(align_t)]; +#endif +} + +/** + * @brief Allocates a block of memory. + * @details The size of the returned block is aligned to the alignment + * type @p align_t so it is not possible to allocate less than + * sizeof(align_t). + * + * + * @param[in] the size of the block to be allocated + * @return A pointer to the allocated memory block. + * @retval NULL allocation failed, core memory exhausted. + */ +void *chCoreAlloc(size_t size) { + void *p; + + chSysLock(); + p = chCoreAllocI(size); + chSysUnlock(); + return p; +} + +/** + * @brief Allocates a block of memory. + * @details The size of the returned block is aligned to the alignment + * type @p align_t so it is not possible to allocate less than + * sizeof(align_t). + * + * @param[in] the size of the block to be allocated. + * @return A pointer to the allocated memory block. + * @retval NULL allocation failed, core memory exhausted. + */ +void *chCoreAllocI(size_t size) { + void *p; + + size = MEM_ALIGN_SIZE(size); + if (nextmem + size > endmem) + return NULL; + p = nextmem; + nextmem += size; + return p; +} + +#endif /* CH_USE_MEMCORE */ + +/** @} */ diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c index 8ee7375f8..7d42eb644 100644 --- a/os/kernel/src/chsys.c +++ b/os/kernel/src/chsys.c @@ -61,6 +61,9 @@ void chSysInit(void) { port_init(); scheduler_init(); vt_init(); +#if CH_USE_MEMCORE + core_init(); +#endif #if CH_USE_HEAP heap_init(); #endif diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c index a3028867a..89d1d6329 100644 --- a/os/kernel/src/chthreads.c +++ b/os/kernel/src/chthreads.c @@ -124,6 +124,8 @@ Thread *chThdCreateStatic(void *wsp, size_t size, /** * @brief Creates a new thread allocating the memory from the heap. * + * @param[in] heapp heap from which allocate the memory or NULL for the + * default heap * @param[in] size size of the working area to be allocated * @param[in] prio the priority level for the new thread * @param[in] pf the thread function @@ -139,11 +141,12 @@ Thread *chThdCreateStatic(void *wsp, size_t size, * @p CH_USE_HEAP and @p CH_USE_WAITEXIT options are enabled * in @p chconf.h. */ -Thread *chThdCreateFromHeap(size_t size, tprio_t prio, tfunc_t pf, void *arg) { +Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size, + tprio_t prio, tfunc_t pf, void *arg) { void *wsp; Thread *tp; - wsp = chHeapAlloc(size); + wsp = chHeapAlloc(heapp, size); if (wsp == NULL) return NULL; tp = chThdInit(wsp, size, prio, pf, arg); diff --git a/os/kernel/templates/chconf.h b/os/kernel/templates/chconf.h index 819d3d1d0..31c3c7a50 100644 --- a/os/kernel/templates/chconf.h +++ b/os/kernel/templates/chconf.h @@ -32,29 +32,36 @@ /*===========================================================================*/ /** - * Frequency of the system timer that drives the system ticks. This also - * defines the system tick time unit. + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. */ #if !defined(CH_FREQUENCY) || defined(__DOXYGEN__) #define CH_FREQUENCY 1000 #endif /** - * This constant is the number of system ticks allowed for the threads before - * preemption occurs. This option is only meaningful if the option - * @p CH_USE_ROUNDROBIN is also active. + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the round robin mechanism. + * + * @note Disabling round robin makes the kernel more compact and generally + * faster but forbids multiple threads at the same priority level. */ #if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__) #define CH_TIME_QUANTUM 20 #endif /** - * If enabled then the use of nested @p chSysLock() / @p chSysUnlock() - * operations is allowed.
- * For performance and code size reasons the recommended setting is to leave - * this option disabled.
- * You can use this option if you need to merge ChibiOS/RT with external - * libraries that require nested lock/unlock operations. + * @brief Nested locks. + * @details If enabled then the use of nested @p chSysLock() / @p chSysUnlock() + * operations is allowed.
+ * For performance and code size reasons the recommended setting + * is to leave this option disabled.
+ * You may use this option if you need to merge ChibiOS/RT with + * external libraries that require nested lock/unlock operations. + * * @note The default is @p FALSE. */ #if !defined(CH_USE_NESTED_LOCKS) || defined(__DOXYGEN__) @@ -62,23 +69,18 @@ #endif /** - * If specified then the kernel performs the round robin scheduling algorithm - * on threads of equal priority. - * @note The default is @p TRUE. - */ -#if !defined(CH_USE_ROUNDROBIN) || defined(__DOXYGEN__) -#define CH_USE_ROUNDROBIN TRUE -#endif - -/** - * Number of RAM bytes to use as system heap. If set to zero then the whole - * available RAM is used as system heap. - * @note In order to use the whole RAM as system heap the linker script must + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must * provide the @p __heap_base__ and @p __heap_end__ symbols. - * @note Requires @p CH_USE_HEAP. + * @note Requires @p CH_USE_COREMEM. */ -#if !defined(CH_HEAP_SIZE) || defined(__DOXYGEN__) -#define CH_HEAP_SIZE 0 +#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__) +#define CH_MEMCORE_SIZE 0 #endif /*===========================================================================*/ @@ -86,8 +88,10 @@ /*===========================================================================*/ /** - * If specified then time efficient rather than space efficient code is used - * when two possible implementations exist. + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * * @note This is not related to the compiler optimization options. * @note The default is @p TRUE. */ @@ -96,18 +100,20 @@ #endif /** - * If enabled defines a CPU register to be used as storage for the global - * @p currp variable. Caching this variable in a register can greatly - * improve both space and time efficiency of the generated code. Another side - * effect is that one less register has to be saved during the context switch - * resulting in lower RAM usage and faster code. + * @brief Exotic optimization. + * @details If defined then a CPU register is used as storage for the global + * @p currp variable. Caching this variable in a register greatly + * improves both space and time OS efficiency. A side effect is that + * one less register has to be saved during the context switch + * resulting in lower RAM usage and faster context switch. + * * @note This option is only usable with the GCC compiler and is only useful * on processors with many registers like ARM cores. * @note If this option is enabled then ALL the libraries linked to the * ChibiOS/RT code must be recompiled with the GCC option @p * -ffixed-@. * @note This option must be enabled in the Makefile, it is listed here for - * documentation. + * documentation only. */ #if defined(__DOXYGEN__) #define CH_CURRP_REGISTER_CACHE "reg" @@ -118,7 +124,10 @@ /*===========================================================================*/ /** - * If specified then the @p chThdWait() function is included in the kernel. + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__) @@ -126,7 +135,9 @@ #endif /** - * If specified then the Semaphores APIs are included in the kernel. + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__) @@ -134,8 +145,10 @@ #endif /** - * If enabled then the threads are enqueued on semaphores by priority rather - * than FIFO order. + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * * @note The default is @p FALSE. Enable this if you have special requirements. * @note Requires @p CH_USE_SEMAPHORES. */ @@ -144,8 +157,10 @@ #endif /** - * If specified then the Semaphores the @p chSemWaitSignal() API is included - * in the kernel. + * @brief Atomic semaphore API. + * @details If enabled then the semaphores the @p chSemWaitSignal() API + * is included in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_SEMAPHORES. */ @@ -154,7 +169,9 @@ #endif /** - * If specified then the Mutexes APIs are included in the kernel. + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__) @@ -162,7 +179,10 @@ #endif /** - * If specified then the Conditional Variables APIs are included in the kernel. + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_MUTEXES. */ @@ -171,7 +191,10 @@ #endif /** - * If specified then the Conditional Variables APIs are included in the kernel. + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_CONDVARS. */ @@ -180,7 +203,9 @@ #endif /** - * If specified then the Event flags APIs are included in the kernel. + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__) @@ -188,8 +213,10 @@ #endif /** - * If specified then the @p chEvtWaitXXXTimeout() functions are included in - * the kernel. + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_EVENTS. */ @@ -198,7 +225,10 @@ #endif /** - * If specified then the Synchronous Messages APIs are included in the kernel. + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__) @@ -206,7 +236,10 @@ #endif /** - * If enabled then messages are served by priority rather than in FIFO order. + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * * @note The default is @p FALSE. Enable this if you have special requirements. * @note Requires @p CH_USE_MESSAGES. */ @@ -215,8 +248,10 @@ #endif /** - * If specified then the Asynchronous Messages (Mailboxes) APIs are included - * in the kernel. + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_SEMAPHORES. */ @@ -225,7 +260,9 @@ #endif /** - * If specified then the I/O queues APIs are included in the kernel. + * @brief I/O Queues APIs. + * @details If enabled then the I/O queues APIs are included in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_SEMAPHORES. */ @@ -234,9 +271,24 @@ #endif /** - * If specified then the memory heap allocator APIs are included in the kernel. + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * * @note The default is @p TRUE. - * @note Requires @p CH_USE_MUTEXES or @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) +#define CH_USE_MEMCORE TRUE +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_COREMEM and either @p CH_USE_MUTEXES or + * @p CH_USE_SEMAPHORES. * @note Mutexes are recommended. */ #if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) @@ -244,18 +296,24 @@ #endif /** - * If enabled enforces the use of the C-runtime @p malloc() and @p free() - * functions as backend for the system heap allocator. + * @brief C-runtime allocator. + * @details If enabled the the heap allocator APIs just wrap the C-runtime + * @p malloc() and @p free() functions. + * * @note The default is @p FALSE. * @note Requires @p CH_USE_HEAP. + * @note The C-runtime may or may not require @p CH_USE_COREMEM, see the + * appropriate documentation. */ #if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__) #define CH_USE_MALLOC_HEAP FALSE #endif /** - * If specified then the memory pools allocator APIs are included in the - * kernel. + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * * @note The default is @p TRUE. */ #if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__) @@ -263,8 +321,10 @@ #endif /** - * If specified then the dynamic threads creation APIs are included in the - * kernel. + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * * @note The default is @p TRUE. * @note Requires @p CH_USE_WAITEXIT. */ @@ -277,8 +337,10 @@ /*===========================================================================*/ /** - * Debug option, if enabled then the checks on the API functions input - * parameters are activated. + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * * @note The default is @p FALSE. */ #if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) @@ -286,9 +348,11 @@ #endif /** - * Debug option, if enabled then all the assertions in the kernel code are - * activated. This includes consistency checks inside the kernel, runtime - * anomalies and port-defined checks. + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * * @note The default is @p FALSE. */ #if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) @@ -296,8 +360,10 @@ #endif /** - * Debug option, if enabled the context switch circular trace buffer is - * activated. + * @brief Debug option, trace buffer. + * @details If enabled then the context switch circular trace buffer is + * activated. + * * @note The default is @p FALSE. */ #if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__) @@ -305,25 +371,37 @@ #endif /** - * Debug option, if enabled a runtime stack check is performed. + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. * @note The stack check is performed in a architecture/port dependent way. It - * may not be implemented at all. + * may not be implemented or some ports. */ #if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) #define CH_DBG_ENABLE_STACK_CHECK FALSE #endif /** - * Debug option, if enabled the threads working area is filled with a byte - * pattern when a thread is created. + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. */ #if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__) #define CH_DBG_FILL_THREADS FALSE #endif /** - * Debug option, if enabled a field is added to the @p Thread structure that - * counts the system ticks occurred while executing the thread. + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p Thread structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p TRUE. + * @note This debug option is defaulted to TRUE because it is required by + * some test cases into the test suite. */ #if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) #define CH_DBG_THREADS_PROFILING TRUE @@ -334,38 +412,46 @@ /*===========================================================================*/ /** - * User fields added to the end of the @p Thread structure. + * @brief Threads descriptor structure hook. + * @details User fields added to the end of the @p Thread structure. */ #if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__) #define THREAD_EXT_FIELDS \ struct { \ - /* Add thread custom fields here.*/ \ + /* Add threads custom fields here.*/ \ }; #endif /** - * User initialization code added to the @p chThdInit() API. - * @note It is invoked from within @p chThdInit(). + * @brief Threads initialization hook. + * @details User initialization code added to the @p chThdInit() API. + * + * @note It is invoked from within @p chThdInit() and implicitily from all + * the threads creation APIs. */ #if !defined(THREAD_EXT_INIT) || defined(__DOXYGEN__) #define THREAD_EXT_INIT(tp) { \ - /* Add thread initialization code here.*/ \ + /* Add threads initialization code here.*/ \ } #endif /** - * User finalization code added to the @p chThdExit() API. + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * * @note It is inserted into lock zone. + * @note It is also invoked when the threads simply return in order to + * terminate. */ #if !defined(THREAD_EXT_EXIT) || defined(__DOXYGEN__) #define THREAD_EXT_EXIT(tp) { \ - /* Add thread finalization code here.*/ \ + /* Add threads finalization code here.*/ \ } #endif /** - * Code inserted inside the idle thread loop immediately after an interrupt - * resumed execution. + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. */ #if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__) #define IDLE_LOOP_HOOK() { \ -- cgit v1.2.3