tests/malloc: Allow malloc to fail when out of RAM, add heap test
cases. Fixes #76.
This commit is contained in:
parent
80b191af08
commit
8fffd14e50
4 changed files with 41 additions and 14 deletions
|
@ -81,13 +81,16 @@
|
||||||
unsigned cpu_sr;
|
unsigned cpu_sr;
|
||||||
char level1_int_disabled;
|
char level1_int_disabled;
|
||||||
|
|
||||||
/* Supervisor stack pointer entry. This is the "high water mark" of how far the
|
/* Supervisor stack pointer entry. On reset, sdk_user_start sets a
|
||||||
supervisor stack grew down before task started.
|
* tentative 512 byte supervisor stack size.
|
||||||
|
|
||||||
After tasks start, task stacks are all allocated from the heap and
|
When the scheduler starts, this changes to the "high water mark" of
|
||||||
FreeRTOS checks for stack overflow.
|
how far the supervisor stack grew down before task started.
|
||||||
|
|
||||||
|
After tasks start, task stacks are all allocated from the heap and
|
||||||
|
FreeRTOS checks for stack overflow.
|
||||||
*/
|
*/
|
||||||
static uint32_t xPortSupervisorStackPointer;
|
void *xPortSupervisorStackPointer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack initialization
|
* Stack initialization
|
||||||
|
@ -218,7 +221,7 @@ size_t xPortGetFreeHeapSize( void )
|
||||||
struct mallinfo mi = mallinfo();
|
struct mallinfo mi = mallinfo();
|
||||||
uint32_t brk_val = (uint32_t) sbrk(0);
|
uint32_t brk_val = (uint32_t) sbrk(0);
|
||||||
|
|
||||||
uint32_t sp = xPortSupervisorStackPointer;
|
intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
|
||||||
if(sp == 0) /* scheduler not started */
|
if(sp == 0) /* scheduler not started */
|
||||||
__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
|
__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
|
||||||
return sp - brk_val + mi.fordblks;
|
return sp - brk_val + mi.fordblks;
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <esp/uart.h>
|
#include <esp/uart.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
extern void *xPortSupervisorStackPointer;
|
||||||
|
|
||||||
IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
|
IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
|
||||||
{
|
{
|
||||||
extern char _heap_start; /* linker script defined */
|
extern char _heap_start; /* linker script defined */
|
||||||
|
@ -21,13 +23,16 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
|
||||||
if (heap_end == NULL)
|
if (heap_end == NULL)
|
||||||
heap_end = &_heap_start;
|
heap_end = &_heap_start;
|
||||||
prev_heap_end = heap_end;
|
prev_heap_end = heap_end;
|
||||||
/* TODO: Check stack collision
|
|
||||||
if (heap_end + incr > stack_ptr)
|
intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
|
||||||
{
|
if(sp == 0) /* scheduler not started */
|
||||||
_write (1, "_sbrk: Heap collided with stack\n", 32);
|
__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
|
||||||
while(1) {}
|
|
||||||
}
|
if ((intptr_t)heap_end + incr >= sp)
|
||||||
*/
|
{
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
return (caddr_t)-1;
|
||||||
|
}
|
||||||
heap_end += incr;
|
heap_end += incr;
|
||||||
|
|
||||||
return (caddr_t) prev_heap_end;
|
return (caddr_t) prev_heap_end;
|
||||||
|
|
|
@ -232,7 +232,7 @@ SECTIONS
|
||||||
_heap_start = ABSOLUTE(.);
|
_heap_start = ABSOLUTE(.);
|
||||||
/* _stack_sentry = ALIGN(0x8); */
|
/* _stack_sentry = ALIGN(0x8); */
|
||||||
} >dram0_0_seg :dram0_0_bss_phdr
|
} >dram0_0_seg :dram0_0_bss_phdr
|
||||||
/* __stack = 0x3ffc8000; */
|
/* __stack = 0x3ffc8000; <-- this value seems a bit odd, stack on sdk_user_start is ~0x3ffffce9 */
|
||||||
|
|
||||||
.lit4 : ALIGN(4)
|
.lit4 : ALIGN(4)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
|
|
||||||
DEFINE_SOLO_TESTCASE(02_heap_simple)
|
DEFINE_SOLO_TESTCASE(02_heap_simple)
|
||||||
|
DEFINE_SOLO_TESTCASE(02_heap_full)
|
||||||
|
|
||||||
/* Simple heap accounting tests */
|
/* Simple heap accounting tests */
|
||||||
static void a_02_heap_simple()
|
static void a_02_heap_simple()
|
||||||
|
@ -35,3 +36,21 @@ static void a_02_heap_simple()
|
||||||
TEST_ASSERT_UINT32_WITHIN_MESSAGE(100, freeheap, after, "Free heap size after freeing buffer should be close to initial");
|
TEST_ASSERT_UINT32_WITHIN_MESSAGE(100, freeheap, after, "Free heap size after freeing buffer should be close to initial");
|
||||||
TEST_PASS;
|
TEST_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure malloc behaves when out of memory */
|
||||||
|
static void a_02_heap_full()
|
||||||
|
{
|
||||||
|
void *x = malloc(65536);
|
||||||
|
TEST_ASSERT_NULL_MESSAGE(x, "Allocating 64kB should fail and return null");
|
||||||
|
|
||||||
|
void *y = malloc(32768);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(y, "Allocating 32kB should succeed");
|
||||||
|
|
||||||
|
void *z = malloc(32768);
|
||||||
|
TEST_ASSERT_NULL_MESSAGE(z, "Allocating second 32kB should fail");
|
||||||
|
|
||||||
|
free(y);
|
||||||
|
z = malloc(32768);
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(z, "Allocating 32kB should succeed after first block freed");
|
||||||
|
TEST_PASS;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue