Skip to content

Commit 9c03660

Browse files
authored
Merge pull request #10 from fpistm/newlib
Use thread-safe memory manager using C runtime (Newlib)
2 parents 10766d7 + f7c63ad commit 9c03660

File tree

3 files changed

+181
-5
lines changed

3 files changed

+181
-5
lines changed

portable/MemMang/heap_useNewlib.c

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* \file heap_useNewlib.c
3+
* \brief Wrappers required to use newlib malloc-family within FreeRTOS.
4+
*
5+
* \par Overview
6+
* Route FreeRTOS memory management functions to newlib's malloc family.
7+
* Thus newlib and FreeRTOS share memory-management routines and memory pool,
8+
* and all newlib's internal memory-management requirements are supported.
9+
*
10+
* \author Dave Nadler
11+
* \date 2-July-2017
12+
*
13+
* \see http://www.nadler.com/embedded/newlibAndFreeRTOS.html
14+
* \see https://sourceware.org/newlib/libc.html#Reentrancy
15+
* \see https://sourceware.org/newlib/libc.html#malloc
16+
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fenv_005flock
17+
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fmalloc_005flock
18+
* \see https://sourceforge.net/p/freertos/feature-requests/72/
19+
* \see http://www.billgatliff.com/newlib.html
20+
* \see http://wiki.osdev.org/Porting_Newlib
21+
* \see http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
22+
*
23+
*
24+
* \copyright
25+
* (c) Dave Nadler 2017, All Rights Reserved.
26+
* Web: http://www.nadler.com
27+
28+
*
29+
* Redistribution and use in source and binary forms, with or without modification,
30+
* are permitted provided that the following conditions are met:
31+
*
32+
* - Use or redistributions of source code must retain the above copyright notice,
33+
* this list of conditions, ALL ORIGINAL COMMENTS, and the following disclaimer.
34+
*
35+
* - Redistributions in binary form must reproduce the above copyright notice, this
36+
* list of conditions and the following disclaimer in the documentation and/or
37+
* other materials provided with the distribution.
38+
*
39+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
40+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
41+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
43+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
46+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
48+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49+
*/
50+
51+
#include <stdlib.h> // maps to newlib...
52+
#include <malloc.h> // mallinfo...
53+
#include <errno.h> // ENOMEM
54+
55+
#include "newlib.h"
56+
#if (__NEWLIB__ != 2) || (__NEWLIB_MINOR__ != 5)
57+
#warning "This wrapper was verified for newlib version 2.5.0; please ensure newlib's external requirements for malloc-family are unchanged!"
58+
#endif
59+
60+
#include "FreeRTOS.h" // defines public interface we're implementing here
61+
#if !defined(configUSE_NEWLIB_REENTRANT) || (configUSE_NEWLIB_REENTRANT!=1)
62+
#warning "#define configUSE_NEWLIB_REENTRANT 1 // Required for thread-safety of newlib sprintf, strtok, etc..."
63+
// If you're *really* sure you don't need FreeRTOS's newlib reentrancy support, remove this warning...
64+
#endif
65+
#include "task.h"
66+
67+
// ================================================================================================
68+
// External routines required by newlib's malloc (sbrk/_sbrk, __malloc_lock/unlock)
69+
// ================================================================================================
70+
71+
#ifndef NDEBUG
72+
static int totalBytesProvidedBySBRK = 0;
73+
#endif
74+
extern char _end; // Defined in the linker script
75+
static int heapBytesRemaining = -1; // configTOTAL_HEAP_SIZE is not constant will be init later
76+
77+
//! sbrk/_sbrk version supporting reentrant newlib (depends upon above symbols defined by linker control file).
78+
char * sbrk(int incr) {
79+
static char *currentHeapEnd = &_end;
80+
vTaskSuspendAll(); // Note: safe to use before FreeRTOS scheduler started
81+
if (heapBytesRemaining == -1) {
82+
heapBytesRemaining = configTOTAL_HEAP_SIZE;
83+
}
84+
char *previousHeapEnd = currentHeapEnd;
85+
if (currentHeapEnd + incr > &_end + configTOTAL_HEAP_SIZE) {
86+
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
87+
{
88+
extern void vApplicationMallocFailedHook( void );
89+
vApplicationMallocFailedHook();
90+
}
91+
#elif 0
92+
// If you want to alert debugger or halt...
93+
while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)
94+
#else
95+
// If you prefer to believe your application will gracefully trap out-of-memory...
96+
_impure_ptr->_errno = ENOMEM; // newlib's thread-specific errno
97+
xTaskResumeAll();
98+
#endif
99+
return (char *)-1; // the malloc-family routine that called sbrk will return 0
100+
}
101+
currentHeapEnd += incr;
102+
heapBytesRemaining -= incr;
103+
#ifndef NDEBUG
104+
totalBytesProvidedBySBRK += incr;
105+
#endif
106+
xTaskResumeAll();
107+
return (char *) previousHeapEnd;
108+
}
109+
//! Synonym for sbrk.
110+
char * _sbrk(int incr) { return sbrk(incr); };
111+
112+
void __malloc_lock() { vTaskSuspendAll(); };
113+
void __malloc_unlock() { (void)xTaskResumeAll(); };
114+
115+
// newlib also requires implementing locks for the application's environment memory space,
116+
// accessed by newlib's setenv() and getenv() functions.
117+
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
118+
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
119+
void __env_lock() { vTaskSuspendAll(); };
120+
void __env_unlock() { (void)xTaskResumeAll(); };
121+
122+
/// /brief Wrap malloc/malloc_r to help debug who requests memory and why.
123+
/// Add to the linker command line: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r
124+
// Note: These functions are normally unused and stripped by linker.
125+
void *__wrap_malloc(size_t nbytes) {
126+
extern void * __real_malloc(size_t nbytes);
127+
void *p = __real_malloc(nbytes); // Solely for debug breakpoint...
128+
return p;
129+
};
130+
void *__wrap__malloc_r(void *reent, size_t nbytes) {
131+
extern void * __real__malloc_r(size_t nbytes);
132+
void *p = __real__malloc_r(nbytes); // Solely for debug breakpoint...
133+
return p;
134+
};
135+
136+
137+
// ================================================================================================
138+
// Implement FreeRTOS's memory API using newlib-provided malloc family.
139+
// ================================================================================================
140+
141+
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {
142+
void *p = malloc(xSize);
143+
return p;
144+
}
145+
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {
146+
free(pv);
147+
};
148+
149+
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {
150+
struct mallinfo mi = mallinfo();
151+
if (heapBytesRemaining == -1) {
152+
heapBytesRemaining = configTOTAL_HEAP_SIZE;
153+
}
154+
return mi.fordblks + heapBytesRemaining;
155+
}
156+
157+
// GetMinimumEverFree is not available in newlib's malloc implementation.
158+
// So, no implementation provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
159+
160+
//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
161+
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};

src/FreeRTOSConfig_Default.h

+15-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@
8484
*----------------------------------------------------------*/
8585

8686
/* Begin custom definitions for STM32 */
87-
/* Default (3) Memory allocation implementations (heap_[1-5].c) */
87+
/* Define memory allocation implementations to use:
88+
* 1 to 5 for heap_[1-5].c
89+
* -1 for heap_useNewlib.c
90+
* Default -1 see heap.c
91+
*/
8892
/*#define configMEMMANG_HEAP_NB 3*/
8993
/* End custom definitions for STM32 */
9094

@@ -93,15 +97,23 @@
9397
#include <stdint.h>
9498
extern uint32_t SystemCoreClock;
9599
#endif
100+
extern char _end; /* Defined in the linker script */
101+
extern char _estack; /* Defined in the linker script */
102+
extern char _Min_Stack_Size; /* Defined in the linker script */
96103

97104
#define configUSE_PREEMPTION 1
98105
#define configUSE_IDLE_HOOK 1
99106
#define configUSE_TICK_HOOK 1
100107
#define configCPU_CLOCK_HZ (SystemCoreClock)
101108
#define configTICK_RATE_HZ ((TickType_t)1000)
102109
#define configMAX_PRIORITIES (7)
103-
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
104-
#define configTOTAL_HEAP_SIZE ((size_t)(15 * 1024))
110+
/*
111+
* _Min_Stack_Size is often set to 0x400 in the linker script
112+
* Use it divided by 8 to set minmimal stack size of a task to 128 by default.
113+
* End user will have to properly configure those value depending to their needs.
114+
*/
115+
#define configMINIMAL_STACK_SIZE ((uint16_t)((uint32_t)&_Min_Stack_Size/8))
116+
#define configTOTAL_HEAP_SIZE ((size_t)(&_estack - _Min_Stack_Size - &_end))
105117
#define configMAX_TASK_NAME_LEN (16)
106118
#define configUSE_TRACE_FACILITY 1
107119
#define configUSE_16_BIT_TICKS 0

src/heap.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* @file heap.c
33
* @author Frederic Pillon <[email protected]> for STMicroelectronics.
44
* @brief Provide Memory allocation implementations included in the FreeRTOS source
5+
* heap_useNewlib - thread-safe memory manager using C runtime (Newlib)
56
* heap_1 - the very simplest, does not permit memory to be freed
67
* heap_2 - permits memory to be freed, but not does coalescence adjacent free blocks.
78
* heap_3 - simply wraps the standard malloc() and free() for thread safety
@@ -11,10 +12,12 @@
1112
#include "FreeRTOS.h"
1213

1314
#ifndef configMEMMANG_HEAP_NB
14-
#define configMEMMANG_HEAP_NB 3
15+
#define configMEMMANG_HEAP_NB -1
1516
#endif
1617

17-
#if (configMEMMANG_HEAP_NB == 1)
18+
#if (configMEMMANG_HEAP_NB == -1)
19+
#include "../portable/MemMang/heap_useNewlib.c"
20+
#elif (configMEMMANG_HEAP_NB == 1)
1821
#include "../portable/MemMang/heap_1.c"
1922
#elif (configMEMMANG_HEAP_NB == 2)
2023
#include "../portable/MemMang/heap_2.c"

0 commit comments

Comments
 (0)