For a namespace clean function, implement
_sbrk
, otherwise implement
sbrk
. This is one function for which there is
no default minimal implementation. It is important that it is
implemented wherever possible, since malloc
depends on it, and in turn many other functions depend on
malloc
. In this application note, the OpenRISC 1000
implementation is used as an example.
As noted earlier (Section 5.2.2), the heap on
the OpenRISC 1000 grows up from the end of loaded program space, and the
stack grows down from the top of memory. The linker defines the
symbol _end
, which will be the start of the
heap, whilst the C runtime initialization places the address of
the last work in memory in the global variable
_stack
.
Caution | |
---|---|
|
Within a C program these two variables are referred to without their leading underscore—the C compiler prepends all variable names with underscore.
#include <errno.h> #undef errno extern int errno; #define STACK_BUFFER 65536 /* Reserved stack space in bytes. */ void * _sbrk (int nbytes) { /* Symbol defined by linker map */ extern int end; /* start of free memory (as symbol) */ /* Value set by crt0.S */ extern void *stack; /* end of free memory */ /* The statically held previous end of the heap, with its initialization. */ static void *heap_ptr = (void *)&end; /* Previous end */ if ((stack - (heap_ptr + nbytes)) > STACK_BUFFER ) { void *base = heap_ptr; heap_ptr += nbytes; return base; } else { errno = ENOMEM; return (void *) -1; } } /* _sbrk () */
The program always tries to keep a minimum of 65,536 (216) bytes spare for the stack.
Note | |
---|---|
This implementation defines |
Important | |
---|---|
The problem is that this now makes the function
non-reentrant. If the function were interrupted after the
assignment to
For simple systems, it would be sufficient to avoid using this
function in interrupt service routines. However the problem then
knowing which functions might call The problem cannot even be completely avoided by using reentrant functions (see Section 5.4), since just providing a per thread data structure does not help. The end of heap is a single global value. The only full solution is to surround the update of the global variable by a semaphore, and failing the allocation if the region is blocked (we cannot wait, or deadlock would result). |