Skip to content

Commit 897009a

Browse files
committed
Add thread-safe memory manager using C runtime (Newlib)
1 parent 10766d7 commit 897009a

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

portable/MemMang/heap_newlib.c

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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; // make sure to define these symbols in linker command file
75+
static int heapBytesRemaining = configTOTAL_HEAP_SIZE; // that's (&__HeapLimit)-(&__HeapBase)
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+
char *previousHeapEnd = currentHeapEnd;
82+
if (currentHeapEnd + incr > &_end + configTOTAL_HEAP_SIZE) {
83+
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
84+
{
85+
extern void vApplicationMallocFailedHook( void );
86+
vApplicationMallocFailedHook();
87+
}
88+
#elif 0
89+
// If you want to alert debugger or halt...
90+
while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)
91+
#else
92+
// If you prefer to believe your application will gracefully trap out-of-memory...
93+
_impure_ptr->_errno = ENOMEM; // newlib's thread-specific errno
94+
xTaskResumeAll();
95+
#endif
96+
return (char *)-1; // the malloc-family routine that called sbrk will return 0
97+
}
98+
currentHeapEnd += incr;
99+
heapBytesRemaining -= incr;
100+
#ifndef NDEBUG
101+
totalBytesProvidedBySBRK += incr;
102+
#endif
103+
xTaskResumeAll();
104+
return (char *) previousHeapEnd;
105+
}
106+
//! Synonym for sbrk.
107+
char * _sbrk(int incr) { return sbrk(incr); };
108+
109+
void __malloc_lock() { vTaskSuspendAll(); };
110+
void __malloc_unlock() { (void)xTaskResumeAll(); };
111+
112+
// newlib also requires implementing locks for the application's environment memory space,
113+
// accessed by newlib's setenv() and getenv() functions.
114+
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
115+
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
116+
void __env_lock() { vTaskSuspendAll(); };
117+
void __env_unlock() { (void)xTaskResumeAll(); };
118+
119+
/// /brief Wrap malloc/malloc_r to help debug who requests memory and why.
120+
/// Add to the linker command line: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r
121+
// Note: These functions are normally unused and stripped by linker.
122+
void *__wrap_malloc(size_t nbytes) {
123+
extern void * __real_malloc(size_t nbytes);
124+
void *p = __real_malloc(nbytes); // Solely for debug breakpoint...
125+
return p;
126+
};
127+
void *__wrap__malloc_r(void *reent, size_t nbytes) {
128+
extern void * __real__malloc_r(size_t nbytes);
129+
void *p = __real__malloc_r(nbytes); // Solely for debug breakpoint...
130+
return p;
131+
};
132+
133+
134+
// ================================================================================================
135+
// Implement FreeRTOS's memory API using newlib-provided malloc family.
136+
// ================================================================================================
137+
138+
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {
139+
void *p = malloc(xSize);
140+
return p;
141+
}
142+
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {
143+
free(pv);
144+
};
145+
146+
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {
147+
struct mallinfo mi = mallinfo();
148+
return mi.fordblks + heapBytesRemaining;
149+
}
150+
151+
// GetMinimumEverFree is not available in newlib's malloc implementation.
152+
// So, no implementation provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
153+
154+
//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
155+
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};

src/heap.c

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "../portable/MemMang/heap_4.c"
2525
#elif (configMEMMANG_HEAP_NB == 5)
2626
#include "../portable/MemMang/heap_5.c"
27+
#elif (configMEMMANG_HEAP_NB == -1)
28+
#include "../portable/MemMang/heap_newlib.c"
2729
#else
2830
#error "Wrong Memory allocation implementations defined"
2931
#endif

0 commit comments

Comments
 (0)