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 --- demos/ARM7-AT91SAM7X-GCC/chconf.h | 255 ++++++++++++++------- demos/ARM7-AT91SAM7X-LWIP-GCC/chconf.h | 255 ++++++++++++++------- demos/ARM7-AT91SAM7X-LWIP-GCC/lwip/arch/sys_arch.c | 6 +- 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 +++++++++++++------- readme.txt | 9 + test/test.c | 8 +- test/test.h | 17 +- test/testdyn.c | 66 +++--- test/testheap.c | 119 +++++----- test/testmbox.c | 4 +- test/testqueues.c | 4 +- 22 files changed, 992 insertions(+), 612 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 diff --git a/demos/ARM7-AT91SAM7X-GCC/chconf.h b/demos/ARM7-AT91SAM7X-GCC/chconf.h index ba2e6d048..31c3c7a50 100644 --- a/demos/ARM7-AT91SAM7X-GCC/chconf.h +++ b/demos/ARM7-AT91SAM7X-GCC/chconf.h @@ -18,9 +18,9 @@ */ /** - * @file src/templates/chconf.h + * @file templates/chconf.h * @brief Configuration file template. - * @addtogroup Config + * @addtogroup config * @{ */ @@ -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,16 +248,21 @@ #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. */ #if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) -#define CH_USE_MAILBOXES TRUE +#define CH_USE_MAILBOXES TRUE #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. */ @@ -233,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. + */ +#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_MUTEXES or @p CH_USE_SEMAPHORES. + * @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__) @@ -243,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__) @@ -262,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. */ @@ -276,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__) @@ -285,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__) @@ -295,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__) @@ -304,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 @@ -333,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() { \ diff --git a/demos/ARM7-AT91SAM7X-LWIP-GCC/chconf.h b/demos/ARM7-AT91SAM7X-LWIP-GCC/chconf.h index e6a58ce12..b12b89b93 100644 --- a/demos/ARM7-AT91SAM7X-LWIP-GCC/chconf.h +++ b/demos/ARM7-AT91SAM7X-LWIP-GCC/chconf.h @@ -18,9 +18,9 @@ */ /** - * @file src/templates/chconf.h + * @file templates/chconf.h * @brief Configuration file template. - * @addtogroup Config + * @addtogroup config * @{ */ @@ -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,16 +248,21 @@ #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. */ #if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) -#define CH_USE_MAILBOXES TRUE +#define CH_USE_MAILBOXES TRUE #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. */ @@ -233,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. + */ +#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_MUTEXES or @p CH_USE_SEMAPHORES. + * @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__) @@ -243,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__) @@ -262,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. */ @@ -276,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__) @@ -285,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__) @@ -295,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__) @@ -304,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 @@ -333,41 +412,49 @@ /*===========================================================================*/ /** - * 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.*/ \ /* Space for the LWIP sys_timeouts structure.*/ \ void *p_lwipspace[1]; \ }; #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.*/ \ (tp)->p_lwipspace[0] = NULL; \ } #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() { \ diff --git a/demos/ARM7-AT91SAM7X-LWIP-GCC/lwip/arch/sys_arch.c b/demos/ARM7-AT91SAM7X-LWIP-GCC/lwip/arch/sys_arch.c index 7d39c9520..65b1b5314 100644 --- a/demos/ARM7-AT91SAM7X-LWIP-GCC/lwip/arch/sys_arch.c +++ b/demos/ARM7-AT91SAM7X-LWIP-GCC/lwip/arch/sys_arch.c @@ -66,7 +66,7 @@ void sys_init(void) { sys_sem_t sys_sem_new(u8_t count) { - sys_sem_t sem = chHeapAlloc(sizeof(Semaphore)); + sys_sem_t sem = chHeapAlloc(NULL, sizeof(Semaphore)); chSemInit(sem, (cnt_t)count); return sem; } @@ -97,7 +97,7 @@ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) { sys_mbox_t sys_mbox_new(int size) { sys_mbox_t mbox; - mbox = chHeapAlloc(sizeof(Mailbox) + sizeof(msg_t) * size); + mbox = chHeapAlloc(NULL, sizeof(Mailbox) + sizeof(msg_t) * size); chMBInit(mbox, (void *)(((uint8_t *)mbox) + sizeof(Mailbox)), size); return mbox; } @@ -147,7 +147,7 @@ struct sys_timeouts *sys_arch_timeouts(void) { sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) { size_t wsz = THD_WA_SIZE(stacksize); - void *wsp = chHeapAlloc(wsz); + void *wsp = chCoreAlloc(wsz); if (wsp == NULL) return NULL; return (sys_thread_t)chThdCreateStatic(wsp, wsz, prio, (tfunc_t)thread, arg); 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() { \ diff --git a/readme.txt b/readme.txt index 676f9918b..f361bde0c 100644 --- a/readme.txt +++ b/readme.txt @@ -7,6 +7,15 @@ Removed the old EMAC driver, updated the uIP WEB demo to use the new driver model. - NEW: Added a simple lwIP demo (web server) for the AT91SAM7X. +- NEW: Centralized memory heap manager. This simple allocator implements a + sbrk()-like API: chCoreAlloc(). The other allocators now use this manager + in order to get memory blocks. +- NEW: The heap allocator has been modified, now it is possible to have + multiple heaps. The default heap gets its memory from the new heap manager. +- CHANGE: Because the changes in the allocators some API prototypes changed: + chHeapAlloc(), chHeapStatus(), chThdCreateFromHeap(). +- CHANGE: Because the changes in the allocators some configuration options + changed, see the template chconf.h file. - CHANGE: renamed ./demos/ARM7-AT91SAM7X-WEB-GCC in ARM7-AT91SAM7X-UIP-GCC. *** 1.3.2 *** diff --git a/test/test.c b/test/test.c index 434ef1b8c..bbeb9adc4 100644 --- a/test/test.c +++ b/test/test.c @@ -59,11 +59,7 @@ static char *tokp; * Static working areas, the following areas can be used for threads or * used as temporary buffers. */ -WORKING_AREA(waT0, THREADS_STACK_SIZE); -WORKING_AREA(waT1, THREADS_STACK_SIZE); -WORKING_AREA(waT2, THREADS_STACK_SIZE); -WORKING_AREA(waT3, THREADS_STACK_SIZE); -WORKING_AREA(waT4, THREADS_STACK_SIZE); +union test_buffers test; /* * Pointers to the spawned threads. @@ -73,7 +69,7 @@ Thread *threads[MAX_THREADS]; /* * Pointers to the working areas. */ -void * const wa[5] = {waT0, waT1, waT2, waT3, waT4}; +void * const wa[5] = {test.waT0, test.waT1, test.waT2, test.waT3, test.waT4}; /* * Console output. diff --git a/test/test.h b/test/test.h index fca9da8b1..7b261b553 100644 --- a/test/test.h +++ b/test/test.h @@ -47,6 +47,17 @@ struct testcase { void (*execute)(void); }; +union test_buffers { + struct { + WORKING_AREA(waT0, THREADS_STACK_SIZE); + WORKING_AREA(waT1, THREADS_STACK_SIZE); + WORKING_AREA(waT2, THREADS_STACK_SIZE); + WORKING_AREA(waT3, THREADS_STACK_SIZE); + WORKING_AREA(waT4, THREADS_STACK_SIZE); + }; + uint8_t buffer[WA_SIZE * 5]; +}; + #ifdef __cplusplus extern "C" { #endif @@ -94,11 +105,7 @@ extern "C" { } extern Thread *threads[MAX_THREADS]; -extern WORKING_AREA(waT0, THREADS_STACK_SIZE); -extern WORKING_AREA(waT1, THREADS_STACK_SIZE); -extern WORKING_AREA(waT2, THREADS_STACK_SIZE); -extern WORKING_AREA(waT3, THREADS_STACK_SIZE); -extern WORKING_AREA(waT4, THREADS_STACK_SIZE); +extern union test_buffers test; extern void * const wa[]; extern bool_t test_timer_done; diff --git a/test/testdyn.c b/test/testdyn.c index 44e6ffaa4..07c3f92a0 100644 --- a/test/testdyn.c +++ b/test/testdyn.c @@ -70,50 +70,56 @@ static msg_t thread(void *p) { } #if CH_USE_HEAP + +static MemoryHeap heap1; + static char *dyn1_gettest(void) { return "Dynamic APIs, threads creation from heap"; } +static void dyn1_setup(void) { + + chHeapInit(&heap1, test.buffer, sizeof(union test_buffers)); +} + static void dyn1_execute(void) { size_t n, sz; void *p1; tprio_t prio = chThdGetPriority(); - /* Test skipped if the heap is already fragmented. */ - if ((n = chHeapStatus(&sz)) == 1) { - /* Starting threads from the heap. */ - threads[0] = chThdCreateFromHeap(THD_WA_SIZE(THREADS_STACK_SIZE), - prio-1, thread, "A"); - threads[1] = chThdCreateFromHeap(THD_WA_SIZE(THREADS_STACK_SIZE), - prio-2, thread, "B"); - /* Allocating the whole heap in order to make the thread creation fail.*/ - (void)chHeapStatus(&n); - p1 = chHeapAlloc(n); - threads[2] = chThdCreateFromHeap(THD_WA_SIZE(THREADS_STACK_SIZE), - prio-3, thread, "C"); - chHeapFree(p1); - - test_assert(1, (threads[0] != NULL) && - (threads[1] != NULL) && - (threads[2] == NULL) && - (threads[3] == NULL) && - (threads[4] == NULL), - "thread creation failed"); - - /* Claiming the memory from terminated threads. */ - test_wait_threads(); - test_assert_sequence(2, "AB"); - - /* Heap status checked again.*/ - test_assert(3, chHeapStatus(&n) == 1, "heap fragmented"); - test_assert(4, n == sz, "heap size changed"); - } + (void)chHeapStatus(&heap1, &sz); + /* Starting threads from the heap. */ + threads[0] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), + prio-1, thread, "A"); + threads[1] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), + prio-2, thread, "B"); + /* Allocating the whole heap in order to make the thread creation fail.*/ + (void)chHeapStatus(&heap1, &n); + p1 = chHeapAlloc(&heap1, n); + threads[2] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE), + prio-3, thread, "C"); + chHeapFree(p1); + + test_assert(1, (threads[0] != NULL) && + (threads[1] != NULL) && + (threads[2] == NULL) && + (threads[3] == NULL) && + (threads[4] == NULL), + "thread creation failed"); + + /* Claiming the memory from terminated threads. */ + test_wait_threads(); + test_assert_sequence(2, "AB"); + + /* Heap status checked again.*/ + test_assert(3, chHeapStatus(&heap1, &n) == 1, "heap fragmented"); + test_assert(4, n == sz, "heap size changed"); } const struct testcase testdyn1 = { dyn1_gettest, - NULL, + dyn1_setup, NULL, dyn1_execute }; diff --git a/test/testheap.c b/test/testheap.c index 6e68c11be..6545893ce 100644 --- a/test/testheap.c +++ b/test/testheap.c @@ -50,6 +50,8 @@ #define SIZE 16 +static MemoryHeap test_heap; + /** * @page test_heap_001 Allocation and fragmentation test * @@ -66,74 +68,73 @@ static char *heap1_gettest(void) { return "Heap, allocation and fragmentation test"; } +static void heap1_setup(void) { + + chHeapInit(&test_heap, test.buffer, sizeof(union test_buffers)); +} + static void heap1_execute(void) { void *p1, *p2, *p3; size_t n, sz; /* Test skipped if the heap is already fragmented. */ - if ((n = chHeapStatus(&sz)) == 1) { - test_print("--- Size : "); - test_printn(sz); - test_println(" bytes, not fragmented"); - - /* Same order */ - p1 = chHeapAlloc(SIZE); - p2 = chHeapAlloc(SIZE); - p3 = chHeapAlloc(SIZE); - chHeapFree(p1); /* Does not merge */ - chHeapFree(p2); /* Merges backward */ - chHeapFree(p3); /* Merges both sides */ - test_assert(1, chHeapStatus(&n) == 1, "heap fragmented"); - - /* Reverse order */ - p1 = chHeapAlloc(SIZE); - p2 = chHeapAlloc(SIZE); - p3 = chHeapAlloc(SIZE); - chHeapFree(p3); /* Merges forward */ - chHeapFree(p2); /* Merges forward */ - chHeapFree(p1); /* Merges forward */ - test_assert(2, chHeapStatus(&n) == 1, "heap fragmented"); - - /* Small fragments handling */ - p1 = chHeapAlloc(SIZE + 1); - p2 = chHeapAlloc(SIZE); - chHeapFree(p1); - test_assert(3, chHeapStatus(&n) == 2, "invalid state"); - p1 = chHeapAlloc(SIZE); - test_assert(4, chHeapStatus(&n) == 1, "heap fragmented"); - chHeapFree(p2); - chHeapFree(p1); - test_assert(5, chHeapStatus(&n) == 1, "heap fragmented"); - - /* Skip fragment handling */ - p1 = chHeapAlloc(SIZE); - p2 = chHeapAlloc(SIZE); - chHeapFree(p1); - test_assert(6, chHeapStatus(&n) == 2, "invalid state"); - p1 = chHeapAlloc(SIZE * 2); /* Skips first fragment */ - chHeapFree(p1); - chHeapFree(p2); - test_assert(7, chHeapStatus(&n) == 1, "heap fragmented"); - - /* Allocate all handling */ - (void)chHeapStatus(&n); - p1 = chHeapAlloc(n); - test_assert(8, chHeapStatus(&n) == 0, "not empty"); - chHeapFree(p1); - - test_assert(9, chHeapStatus(&n) == 1, "heap fragmented"); - test_assert(10, n == sz, "size changed"); - } - else { - test_print("--- Size : "); - test_printn(sz); - test_println(" bytes, fragmented, test skipped"); - } + (void)chHeapStatus(&test_heap, &sz); + test_print("--- Size : "); + test_printn(sz); + test_println(" bytes"); + + /* Same order */ + p1 = chHeapAlloc(&test_heap, SIZE); + p2 = chHeapAlloc(&test_heap, SIZE); + p3 = chHeapAlloc(&test_heap, SIZE); + chHeapFree(p1); /* Does not merge */ + chHeapFree(p2); /* Merges backward */ + chHeapFree(p3); /* Merges both sides */ + test_assert(1, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + + /* Reverse order */ + p1 = chHeapAlloc(&test_heap, SIZE); + p2 = chHeapAlloc(&test_heap, SIZE); + p3 = chHeapAlloc(&test_heap, SIZE); + chHeapFree(p3); /* Merges forward */ + chHeapFree(p2); /* Merges forward */ + chHeapFree(p1); /* Merges forward */ + test_assert(2, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + + /* Small fragments handling */ + p1 = chHeapAlloc(&test_heap, SIZE + 1); + p2 = chHeapAlloc(&test_heap, SIZE); + chHeapFree(p1); + test_assert(3, chHeapStatus(&test_heap, &n) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, SIZE); + test_assert(4, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + chHeapFree(p2); + chHeapFree(p1); + test_assert(5, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + + /* Skip fragment handling */ + p1 = chHeapAlloc(&test_heap, SIZE); + p2 = chHeapAlloc(&test_heap, SIZE); + chHeapFree(p1); + test_assert(6, chHeapStatus(&test_heap, &n) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment */ + chHeapFree(p1); + chHeapFree(p2); + test_assert(7, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + + /* Allocate all handling */ + (void)chHeapStatus(&test_heap, &n); + p1 = chHeapAlloc(&test_heap, n); + test_assert(8, chHeapStatus(&test_heap, &n) == 0, "not empty"); + chHeapFree(p1); + + test_assert(9, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); + test_assert(10, n == sz, "size changed"); } const struct testcase testheap1 = { heap1_gettest, - NULL, + heap1_setup, NULL, heap1_execute }; diff --git a/test/testmbox.c b/test/testmbox.c index 96cf543ce..3c23cf937 100644 --- a/test/testmbox.c +++ b/test/testmbox.c @@ -59,7 +59,7 @@ * variables are explicitly initialized in each test case. It is done in order * to test the macros. */ -static MAILBOX_DECL(mb1, waT0, MB_SIZE); +static MAILBOX_DECL(mb1, test.waT0, MB_SIZE); /** * @page test_mbox_001 Queuing and timeouts @@ -77,7 +77,7 @@ static char *mbox1_gettest(void) { static void mbox1_setup(void) { - chMBInit(&mb1, (msg_t *)waT0, MB_SIZE); + chMBInit(&mb1, (msg_t *)test.waT0, MB_SIZE); } static void mbox1_execute(void) { diff --git a/test/testqueues.c b/test/testqueues.c index aff42334c..e5e3a4c0b 100644 --- a/test/testqueues.c +++ b/test/testqueues.c @@ -63,8 +63,8 @@ static void notify(void) {} * variables are explicitly initialized in each test case. It is done in order * to test the macros. */ -static INPUTQUEUE_DECL(iq, waT0, TEST_QUEUES_SIZE, notify); -static OUTPUTQUEUE_DECL(oq, waT0, TEST_QUEUES_SIZE, notify); +static INPUTQUEUE_DECL(iq, test.waT0, TEST_QUEUES_SIZE, notify); +static OUTPUTQUEUE_DECL(oq, test.waT1, TEST_QUEUES_SIZE, notify); /** * @page test_queues_001 Input Queues functionality and APIs -- cgit v1.2.3