OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/linux/uClibc/libc/stdlib/malloc
    from Rev 1325 to Rev 1765
    Reverse comparison

Rev 1325 → Rev 1765

/heap_free.c
0,0 → 1,89
/*
* libc/stdlib/malloc/heap_free.c -- return memory to a heap
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
 
#include "heap.h"
 
 
/* Return the block of memory at MEM, of size SIZE, to HEAP. */
struct heap_free_area *
__heap_free (struct heap *heap, void *mem, size_t size)
{
struct heap_free_area *fa, *prev_fa;
void *end = (char *)mem + size;
 
HEAP_DEBUG (heap, "before __heap_free");
 
/* Find the right position in the free-list entry to place the new block.
This is the most speed critical loop in this malloc implementation:
since we use a simple linked-list for the free-list, and we keep it in
address-sorted order, it can become very expensive to insert something
in the free-list when it becomes fragmented and long. [A better
implemention would use a balanced tree or something for the free-list,
though that bloats the code-size and complexity quite a bit.] */
for (prev_fa = 0, fa = heap->free_areas; fa; prev_fa = fa, fa = fa->next)
if (unlikely (HEAP_FREE_AREA_END (fa) >= mem))
break;
 
if (fa && HEAP_FREE_AREA_START (fa) <= end)
/* The free-area FA is adjacent to the new block, merge them. */
{
size_t fa_size = fa->size + size;
 
if (HEAP_FREE_AREA_START (fa) == end)
/* FA is just after the new block, grow down to encompass it. */
{
/* See if FA can now be merged with its predecessor. */
if (prev_fa && mem == HEAP_FREE_AREA_END (prev_fa))
/* Yup; merge PREV_FA's info into FA. */
{
fa_size += prev_fa->size;
__heap_link_free_area_after (heap, fa, prev_fa->prev);
}
}
else
/* FA is just before the new block, expand to encompass it. */
{
struct heap_free_area *next_fa = fa->next;
 
/* See if FA can now be merged with its successor. */
if (next_fa && end == HEAP_FREE_AREA_START (next_fa))
/* Yup; merge FA's info into NEXT_FA. */
{
fa_size += next_fa->size;
__heap_link_free_area_after (heap, next_fa, prev_fa);
fa = next_fa;
}
else
/* FA can't be merged; move the descriptor for it to the tail-end
of the memory block. */
{
/* The new descriptor is at the end of the extended block,
SIZE bytes later than the old descriptor. */
fa = (struct heap_free_area *)((char *)fa + size);
/* Update links with the neighbors in the list. */
__heap_link_free_area (heap, fa, prev_fa, next_fa);
}
}
 
fa->size = fa_size;
}
else
/* Make the new block into a separate free-list entry. */
fa = __heap_add_free_area (heap, mem, size, prev_fa, fa);
 
HEAP_DEBUG (heap, "after __heap_free");
 
return fa;
}
/free.c
0,0 → 1,262
/*
* libc/stdlib/malloc/free.c -- free function
*
* Copyright (C) 2002,03 NEC Electronics Corporation
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
 
#include "malloc.h"
#include "heap.h"
 
 
static void
free_to_heap (void *mem, struct heap *heap)
{
size_t size;
struct heap_free_area *fa;
 
/* Check for special cases. */
if (unlikely (! mem))
return;
 
/* Normal free. */
 
MALLOC_DEBUG (1, "free: 0x%lx (base = 0x%lx, total_size = %d)",
(long)mem, (long)MALLOC_BASE (mem), MALLOC_SIZE (mem));
 
size = MALLOC_SIZE (mem);
mem = MALLOC_BASE (mem);
 
__heap_lock (heap);
 
/* Put MEM back in the heap, and get the free-area it was placed in. */
fa = __heap_free (heap, mem, size);
 
/* See if the free-area FA has grown big enough that it should be
unmapped. */
if (HEAP_FREE_AREA_SIZE (fa) < MALLOC_UNMAP_THRESHOLD)
/* Nope, nothing left to do, just release the lock. */
__heap_unlock (heap);
else
/* Yup, try to unmap FA. */
{
unsigned long start = (unsigned long)HEAP_FREE_AREA_START (fa);
unsigned long end = (unsigned long)HEAP_FREE_AREA_END (fa);
#ifndef MALLOC_USE_SBRK
# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
struct malloc_mmb *mmb, *prev_mmb;
unsigned long mmb_start, mmb_end;
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
unsigned long unmap_start, unmap_end;
# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
#endif /* !MALLOC_USE_SBRK */
 
#ifdef MALLOC_USE_SBRK
/* Get the sbrk lock so that the two possible calls to sbrk below
are guaranteed to be contiguous. */
__malloc_lock_sbrk ();
/* When using sbrk, we only shrink the heap from the end. It would
be possible to allow _both_ -- shrinking via sbrk when possible,
and otherwise shrinking via munmap, but this results in holes in
memory that prevent the brk from every growing back down; since
we only ever grow the heap via sbrk, this tends to produce a
continuously growing brk (though the actual memory is unmapped),
which could eventually run out of address space. Note that
`sbrk(0)' shouldn't normally do a system call, so this test is
reasonably cheap. */
if ((void *)end != sbrk (0))
{
MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)",
start, end, end - start);
__malloc_unlock_sbrk ();
__heap_unlock (heap);
return;
}
#endif
 
MALLOC_DEBUG (0, "unmapping: 0x%lx - 0x%lx (%ld bytes)",
start, end, end - start);
 
/* Remove FA from the heap. */
__heap_delete (heap, fa);
 
if (__heap_is_empty (heap))
/* We want to avoid the heap from losing all memory, so reserve
a bit. This test is only a heuristic -- the existance of
another free area, even if it's smaller than
MALLOC_MIN_SIZE, will cause us not to reserve anything. */
{
/* Put the reserved memory back in the heap; we asssume that
MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so
we use the latter unconditionally here. */
__heap_free (heap, (void *)start, MALLOC_MIN_SIZE);
start += MALLOC_MIN_SIZE;
}
 
#ifdef MALLOC_USE_SBRK
 
/* Release the heap lock; we're still holding the sbrk lock. */
__heap_unlock (heap);
/* Lower the brk. */
sbrk (start - end);
/* Release the sbrk lock too; now we hold no locks. */
__malloc_unlock_sbrk ();
 
#else /* !MALLOC_USE_SBRK */
 
# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
/* Using the uClinux broken munmap, we have to only munmap blocks
exactly as we got them from mmap, so scan through our list of
mmapped blocks, and return them in order. */
 
MALLOC_MMB_DEBUG (1, "walking mmb list for region 0x%x[%d]...",
start, end - start);
 
prev_mmb = 0;
mmb = __malloc_mmapped_blocks;
while (mmb
&& ((mmb_end = (mmb_start = (unsigned long)mmb->mem) + mmb->size)
<= end))
{
MALLOC_MMB_DEBUG (1, "considering mmb at 0x%x: 0x%x[%d]",
(unsigned)mmb, mmb_start, mmb_end - mmb_start);
 
if (mmb_start >= start
/* If the space between START and MMB_START is non-zero, but
too small to return to the heap, we can't unmap MMB. */
&& (start == mmb_start
|| mmb_start - start > HEAP_MIN_FREE_AREA_SIZE))
{
struct malloc_mmb *next_mmb = mmb->next;
 
if (mmb_end != end && mmb_end + HEAP_MIN_FREE_AREA_SIZE > end)
/* There's too little space left at the end to deallocate
this block, so give up. */
break;
 
MALLOC_MMB_DEBUG (1, "unmapping mmb at 0x%x: 0x%x[%d]",
(unsigned)mmb, mmb_start, mmb_end - mmb_start);
 
if (mmb_start != start)
/* We're going to unmap a part of the heap that begins after
start, so put the intervening region back into the heap. */
{
MALLOC_MMB_DEBUG (0, "putting intervening region back into heap: 0x%x[%d]",
start, mmb_start - start);
__heap_free (heap, (void *)start, mmb_start - start);
}
 
MALLOC_MMB_DEBUG_INDENT (-1);
 
/* Unlink MMB from the list. */
if (prev_mmb)
prev_mmb->next = next_mmb;
else
__malloc_mmapped_blocks = next_mmb;
 
/* Start searching again from the end of this block. */
start = mmb_end;
 
/* We have to unlock the heap before we recurse to free the mmb
descriptor, because we might be unmapping from the mmb
heap. */
__heap_unlock (heap);
 
/* Release the descriptor block we used. */
free_to_heap (mmb, &__malloc_mmb_heap);
 
/* Do the actual munmap. */
munmap ((void *)mmb_start, mmb_end - mmb_start);
 
__heap_lock (heap);
 
# ifdef __UCLIBC_HAS_THREADS__
/* In a multi-threaded program, it's possible that PREV_MMB has
been invalidated by another thread when we released the
heap lock to do the munmap system call, so just start over
from the beginning of the list. It sucks, but oh well;
it's probably not worth the bother to do better. */
prev_mmb = 0;
mmb = __malloc_mmapped_blocks;
# else
mmb = next_mmb;
# endif
}
else
{
prev_mmb = mmb;
mmb = mmb->next;
}
 
MALLOC_MMB_DEBUG_INDENT (-1);
}
 
if (start != end)
/* Hmm, well there's something we couldn't unmap, so put it back
into the heap. */
{
MALLOC_MMB_DEBUG (0, "putting tail region back into heap: 0x%x[%d]",
start, end - start);
__heap_free (heap, (void *)start, end - start);
}
 
/* Finally release the lock for good. */
__heap_unlock (heap);
 
MALLOC_MMB_DEBUG_INDENT (-1);
 
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
 
/* MEM/LEN may not be page-aligned, so we have to page-align them,
and return any left-over bits on the end to the heap. */
unmap_start = MALLOC_ROUND_UP_TO_PAGE_SIZE (start);
unmap_end = MALLOC_ROUND_DOWN_TO_PAGE_SIZE (end);
 
/* We have to be careful that any left-over bits are large enough to
return. Note that we _don't check_ to make sure there's room to
grow/shrink the start/end by another page, we just assume that
the unmap threshold is high enough so that this is always safe
(i.e., it should probably be at least 3 pages). */
if (unmap_start > start)
{
if (unmap_start - start < HEAP_MIN_FREE_AREA_SIZE)
unmap_start += MALLOC_PAGE_SIZE;
__heap_free (heap, (void *)start, unmap_start - start);
}
if (end > unmap_end)
{
if (end - unmap_end < HEAP_MIN_FREE_AREA_SIZE)
unmap_end -= MALLOC_PAGE_SIZE;
__heap_free (heap, (void *)unmap_end, end - unmap_end);
}
 
/* Release the heap lock before we do the system call. */
__heap_unlock (heap);
 
if (unmap_end > unmap_start)
/* Finally, actually unmap the memory. */
munmap ((void *)unmap_start, unmap_end - unmap_start);
 
# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
 
#endif /* MALLOC_USE_SBRK */
}
 
MALLOC_DEBUG_INDENT (-1);
}
 
void
free (void *mem)
{
free_to_heap (mem, &__malloc_heap);
}
/realloc.c
0,0 → 1,91
/*
* libc/stdlib/malloc/realloc.c -- realloc function
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <string.h>
#include <errno.h>
 
#include "malloc.h"
#include "heap.h"
 
 
void *
realloc (void *mem, size_t new_size)
{
size_t size;
char *base_mem;
 
/* Check for special cases. */
if (! mem)
return malloc (new_size);
if (! new_size)
{
free (mem);
return malloc (new_size);
}
 
/* Normal realloc. */
 
base_mem = MALLOC_BASE (mem);
size = MALLOC_SIZE (mem);
 
/* Include extra space to record the size of the allocated block.
Also make sure that we're dealing in a multiple of the heap
allocation unit (SIZE is already guaranteed to be so).*/
new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE);
 
MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)",
(long)mem, new_size, (long)base_mem, size);
 
if (new_size > size)
/* Grow the block. */
{
size_t extra = new_size - size;
 
__heap_lock (&__malloc_heap);
extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
__heap_unlock (&__malloc_heap);
 
if (extra)
/* Record the changed size. */
MALLOC_SET_SIZE (base_mem, size + extra);
else
/* Our attempts to extend MEM in place failed, just
allocate-and-copy. */
{
void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
if (new_mem)
{
memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
free (mem);
}
mem = new_mem;
}
}
else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size)
/* Shrink the block. */
{
__heap_lock (&__malloc_heap);
__heap_free (&__malloc_heap, base_mem + new_size, size - new_size);
__heap_unlock (&__malloc_heap);
MALLOC_SET_SIZE (base_mem, new_size);
}
 
if (mem)
MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)",
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
else
MALLOC_DEBUG (-1, "realloc: returning 0");
 
return mem;
}
/heap.h
0,0 → 1,254
/*
* libc/stdlib/malloc/heap.h -- heap allocator used for malloc
*
* Copyright (C) 2002,03 NEC Electronics Corporation
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <features.h>
 
 
/* On multi-threaded systems, the heap includes a lock. */
#ifdef __UCLIBC_HAS_THREADS__
# include <pthread.h>
# define HEAP_USE_LOCKING
#endif
 
 
/* The heap allocates in multiples of, and aligned to, HEAP_GRANULARITY.
HEAP_GRANULARITY must be a power of 2. Malloc depends on this being the
same as MALLOC_ALIGNMENT. */
#define HEAP_GRANULARITY_TYPE double
#define HEAP_GRANULARITY (sizeof (HEAP_GRANULARITY_TYPE))
 
 
/* A heap is a collection of memory blocks, from which smaller blocks
of memory can be allocated. */
struct heap
{
/* A list of memory in the heap available for allocation. */
struct heap_free_area *free_areas;
 
#ifdef HEAP_USE_LOCKING
/* A lock that can be used by callers to control access to the heap.
The heap code _does not_ use this lock, it's merely here for the
convenience of users! */
pthread_mutex_t lock;
#endif
};
 
/* The HEAP_INIT macro can be used as a static initializer for a heap
variable. The HEAP_INIT_WITH_FA variant is used to initialize a heap
with an initial static free-area; its argument FA should be declared
using HEAP_DECLARE_STATIC_FREE_AREA. */
#ifdef HEAP_USE_LOCKING
# define HEAP_INIT { 0, PTHREAD_MUTEX_INITIALIZER }
# define HEAP_INIT_WITH_FA(fa) { &fa._fa, PTHREAD_MUTEX_INITIALIZER }
#else
# define HEAP_INIT { 0 }
# define HEAP_INIT_WITH_FA(fa) { &fa._fa }
#endif
 
/* A free-list area `header'. These are actually stored at the _ends_ of
free areas (to make allocating from the beginning of the area simpler),
so one might call it a `footer'. */
struct heap_free_area
{
size_t size;
struct heap_free_area *next, *prev;
};
 
/* Return the address of the end of the frea area FA. */
#define HEAP_FREE_AREA_END(fa) ((void *)(fa + 1))
/* Return the address of the beginning of the frea area FA. FA is
evaulated multiple times. */
#define HEAP_FREE_AREA_START(fa) ((void *)((char *)(fa + 1) - (fa)->size))
/* Return the size of the frea area FA. */
#define HEAP_FREE_AREA_SIZE(fa) ((fa)->size)
 
/* This rather clumsy macro allows one to declare a static free-area for
passing to HEAP_INIT_WITH_FA initializer macro. This is only use for
which NAME is allowed. */
#define HEAP_DECLARE_STATIC_FREE_AREA(name, size) \
static struct \
{ \
HEAP_GRANULARITY_TYPE aligned_space; \
char space[HEAP_ADJUST_SIZE(size) \
- sizeof (struct heap_free_area) \
- HEAP_GRANULARITY]; \
struct heap_free_area _fa; \
} name = { (HEAP_GRANULARITY_TYPE)0, "", { HEAP_ADJUST_SIZE(size), 0, 0 } }
 
 
/* Rounds SZ up to be a multiple of HEAP_GRANULARITY. */
#define HEAP_ADJUST_SIZE(sz) \
(((sz) + HEAP_GRANULARITY - 1) & ~(HEAP_GRANULARITY - 1))
 
 
/* The minimum allocatable size. */
#define HEAP_MIN_SIZE HEAP_ADJUST_SIZE (sizeof (struct heap_free_area))
 
/* The minimum size of a free area; if allocating memory from a free-area
would make the free-area smaller than this, the allocation is simply
given the whole free-area instead. It must include at least enough room
to hold a struct heap_free_area, plus some extra to avoid excessive heap
fragmentation (thus increasing speed). This is only a heuristic -- it's
possible for smaller free-areas than this to exist (say, by realloc
returning the tail-end of a previous allocation), but __heap_alloc will
try to get rid of them when possible. */
#define HEAP_MIN_FREE_AREA_SIZE \
HEAP_ADJUST_SIZE (sizeof (struct heap_free_area) + 32)
 
 
/* branch-prediction macros; they may already be defined by libc. */
#ifndef likely
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
#define likely(cond) __builtin_expect(!!(int)(cond), 1)
#define unlikely(cond) __builtin_expect((int)(cond), 0)
#else
#define likely(cond) (cond)
#define unlikely(cond) (cond)
#endif
#endif /* !likely */
 
 
/* Define HEAP_DEBUGGING to cause the heap routines to emit debugging info
to stderr when the variable __heap_debug is set to true. */
#ifdef HEAP_DEBUGGING
extern int __heap_debug;
#define HEAP_DEBUG(heap, str) (__heap_debug ? __heap_dump (heap, str) : 0)
#else
#define HEAP_DEBUG(heap, str) (void)0
#endif
 
/* Output a text representation of HEAP to stderr, labelling it with STR. */
extern void __heap_dump (struct heap *heap, const char *str);
 
/* Do some consistency checks on HEAP. If they fail, output an error
message to stderr, and exit. STR is printed with the failure message. */
extern void __heap_check (struct heap *heap, const char *str);
 
 
#ifdef HEAP_USE_LOCKING
# define __heap_lock(heap) __pthread_mutex_lock (&(heap)->lock)
# define __heap_unlock(heap) __pthread_mutex_unlock (&(heap)->lock)
#else /* !__UCLIBC_HAS_THREADS__ */
/* Without threads, mutex operations are a nop. */
# define __heap_lock(heap) (void)0
# define __heap_unlock(heap) (void)0
#endif /* HEAP_USE_LOCKING */
 
 
/* Delete the free-area FA from HEAP. */
static inline void
__heap_delete (struct heap *heap, struct heap_free_area *fa)
{
if (fa->next)
fa->next->prev = fa->prev;
if (fa->prev)
fa->prev->next = fa->next;
else
heap->free_areas = fa->next;
}
 
 
/* Link the free-area FA between the existing free-area's PREV and NEXT in
HEAP. PREV and NEXT may be 0; if PREV is 0, FA is installed as the
first free-area. */
static inline void
__heap_link_free_area (struct heap *heap, struct heap_free_area *fa,
struct heap_free_area *prev,
struct heap_free_area *next)
{
fa->next = next;
fa->prev = prev;
 
if (prev)
prev->next = fa;
else
heap->free_areas = fa;
if (next)
next->prev = fa;
}
 
/* Update the mutual links between the free-areas PREV and FA in HEAP.
PREV may be 0, in which case FA is installed as the first free-area (but
FA may not be 0). */
static inline void
__heap_link_free_area_after (struct heap *heap,
struct heap_free_area *fa,
struct heap_free_area *prev)
{
if (prev)
prev->next = fa;
else
heap->free_areas = fa;
fa->prev = prev;
}
 
/* Add a new free-area MEM, of length SIZE, in between the existing
free-area's PREV and NEXT in HEAP, and return a pointer to its header.
PREV and NEXT may be 0; if PREV is 0, MEM is installed as the first
free-area. */
static inline struct heap_free_area *
__heap_add_free_area (struct heap *heap, void *mem, size_t size,
struct heap_free_area *prev,
struct heap_free_area *next)
{
struct heap_free_area *fa = (struct heap_free_area *)
((char *)mem + size - sizeof (struct heap_free_area));
 
fa->size = size;
 
__heap_link_free_area (heap, fa, prev, next);
 
return fa;
}
 
 
/* Allocate SIZE bytes from the front of the free-area FA in HEAP, and
return the amount actually allocated (which may be more than SIZE). */
static inline size_t
__heap_free_area_alloc (struct heap *heap,
struct heap_free_area *fa, size_t size)
{
size_t fa_size = fa->size;
 
if (fa_size < size + HEAP_MIN_FREE_AREA_SIZE)
/* There's not enough room left over in FA after allocating the block, so
just use the whole thing, removing it from the list of free areas. */
{
__heap_delete (heap, fa);
/* Remember that we've alloced the whole area. */
size = fa_size;
}
else
/* Reduce size of FA to account for this allocation. */
fa->size = fa_size - size;
 
return size;
}
 
 
/* Allocate and return a block at least *SIZE bytes long from HEAP.
*SIZE is adjusted to reflect the actual amount allocated (which may be
greater than requested). */
extern void *__heap_alloc (struct heap *heap, size_t *size);
 
/* Allocate SIZE bytes at address MEM in HEAP. Return the actual size
allocated, or 0 if we failed. */
extern size_t __heap_alloc_at (struct heap *heap, void *mem, size_t size);
 
/* Return the memory area MEM of size SIZE to HEAP.
Returns the heap free area into which the memory was placed. */
extern struct heap_free_area *__heap_free (struct heap *heap,
void *mem, size_t size);
 
/* Return true if HEAP contains absolutely no memory. */
#define __heap_is_empty(heap) (! (heap)->free_areas)
/heap_debug.c
0,0 → 1,142
/*
* libc/stdlib/malloc/heap_debug.c -- optional heap debugging routines
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
 
#include "malloc.h"
#include "heap.h"
 
 
#ifdef HEAP_DEBUGGING
int __heap_debug = 0;
#endif
 
 
static void
__heap_dump_freelist (struct heap *heap)
{
struct heap_free_area *fa;
for (fa = heap->free_areas; fa; fa = fa->next)
__malloc_debug_printf (0,
"0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx",
(long)fa,
(long)HEAP_FREE_AREA_START (fa),
(long)HEAP_FREE_AREA_END (fa),
fa->size,
(long)fa->prev,
(long)fa->next);
}
 
/* Output a text representation of HEAP to stderr, labelling it with STR. */
void
__heap_dump (struct heap *heap, const char *str)
{
static int recursed = 0;
 
if (! recursed)
{
__heap_check (heap, str);
 
recursed = 1;
 
__malloc_debug_printf (1, "%s: heap @0x%lx:", str, (long)heap);
__heap_dump_freelist (heap);
__malloc_debug_indent (-1);
 
recursed = 0;
}
}
 
 
/* Output an error message to stderr, and exit. STR is printed with the
failure message. */
static void
__heap_check_failure (struct heap *heap, struct heap_free_area *fa,
const char *str, char *fmt, ...)
{
va_list val;
 
if (str)
fprintf (stderr, "\nHEAP CHECK FAILURE %s: ", str);
else
fprintf (stderr, "\nHEAP CHECK FAILURE: ");
 
va_start (val, fmt);
vfprintf (stderr, fmt, val);
va_end (val);
 
putc ('\n', stderr);
 
__malloc_debug_set_indent (0);
__malloc_debug_printf (1, "heap dump:");
__heap_dump_freelist (heap);
 
exit (22);
}
 
/* Do some consistency checks on HEAP. If they fail, output an error
message to stderr, and exit. STR is printed with the failure message. */
void
__heap_check (struct heap *heap, const char *str)
{
typedef unsigned long ul_t;
struct heap_free_area *fa, *prev;
struct heap_free_area *first_fa = heap->free_areas;
 
if (first_fa && first_fa->prev)
__heap_check_failure (heap, first_fa, str,
"first free-area has non-zero prev pointer:\n\
first free-area = 0x%lx\n\
(0x%lx)->prev = 0x%lx\n",
(ul_t)first_fa,
(ul_t)first_fa, (ul_t)first_fa->prev);
 
for (prev = 0, fa = first_fa; fa; prev = fa, fa = fa->next)
{
if (((ul_t)HEAP_FREE_AREA_END (fa) & (HEAP_GRANULARITY - 1))
|| (fa->size & (HEAP_GRANULARITY - 1)))
__heap_check_failure (heap, fa, str, "alignment error:\n\
(0x%lx)->start = 0x%lx\n\
(0x%lx)->size = 0x%lx\n",
(ul_t)fa,
(ul_t)HEAP_FREE_AREA_START (fa),
(ul_t)fa, fa->size);
 
if (fa->prev != prev)
__heap_check_failure (heap, fa, str, "prev pointer corrupted:\n\
(0x%lx)->next = 0x%lx\n\
(0x%lx)->prev = 0x%lx\n",
(ul_t)prev, (ul_t)prev->next,
(ul_t)fa, (ul_t)fa->prev);
 
if (prev)
{
ul_t start = (ul_t)HEAP_FREE_AREA_START (fa);
ul_t prev_end = (ul_t)HEAP_FREE_AREA_END (prev);
 
if (prev_end >= start)
__heap_check_failure (heap, fa, str,
"start %s with prev free-area end:\n\
(0x%lx)->prev = 0x%lx\n\
(0x%lx)->start = 0x%lx\n\
(0x%lx)->end = 0x%lx\n",
(prev_end == start ? "unmerged" : "overlaps"),
(ul_t)fa, (ul_t)prev,
(ul_t)fa, start,
(ul_t)prev, prev_end);
}
}
}
/heap_alloc.c
0,0 → 1,51
/*
* libc/stdlib/malloc/heap_alloc.c -- allocate memory from a heap
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
 
#include "heap.h"
 
 
/* Allocate and return a block at least *SIZE bytes long from HEAP.
*SIZE is adjusted to reflect the actual amount allocated (which may be
greater than requested). */
void *
__heap_alloc (struct heap *heap, size_t *size)
{
struct heap_free_area *fa;
size_t _size = *size;
void *mem = 0;
 
_size = HEAP_ADJUST_SIZE (_size);
if (_size < sizeof (struct heap_free_area))
/* Because we sometimes must use a freed block to hold a free-area node,
we must make sure that every allocated block can hold one. */
_size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area));
 
HEAP_DEBUG (heap, "before __heap_alloc");
 
/* Look for a free area that can contain _SIZE bytes. */
for (fa = heap->free_areas; fa; fa = fa->next)
if (fa->size >= _size)
{
/* Found one! */
mem = HEAP_FREE_AREA_START (fa);
*size = __heap_free_area_alloc (heap, fa, _size);
break;
}
 
HEAP_DEBUG (heap, "after __heap_alloc");
 
return mem;
}
/malloc.c
0,0 → 1,211
/*
* libc/stdlib/malloc/malloc.c -- malloc function
*
* Copyright (C) 2002,03 NEC Electronics Corporation
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
 
#include "malloc.h"
#include "heap.h"
 
 
/* The malloc heap. We provide a bit of initial static space so that
programs can do a little mallocing without mmaping in more space. */
HEAP_DECLARE_STATIC_FREE_AREA (initial_fa, 256);
struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa);
 
#if defined(MALLOC_USE_LOCKING) && defined(MALLOC_USE_SBRK)
/* A lock protecting our use of sbrk. */
malloc_mutex_t __malloc_sbrk_lock;
#endif /* MALLOC_USE_LOCKING && MALLOC_USE_SBRK */
 
 
#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
/* A list of all malloc_mmb structures describing blocsk that
malloc has mmapped, ordered by the block address. */
struct malloc_mmb *__malloc_mmapped_blocks = 0;
 
/* A heap used for allocating malloc_mmb structures. We could allocate
them from the main heap, but that tends to cause heap fragmentation in
annoying ways. */
HEAP_DECLARE_STATIC_FREE_AREA (initial_mmb_fa, 48); /* enough for 3 mmbs */
struct heap __malloc_mmb_heap = HEAP_INIT_WITH_FA (initial_mmb_fa);
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
 
 
static void *
malloc_from_heap (size_t size, struct heap *heap)
{
void *mem;
 
MALLOC_DEBUG (1, "malloc: %d bytes", size);
 
/* Include extra space to record the size of the allocated block. */
size += MALLOC_HEADER_SIZE;
 
__heap_lock (heap);
 
/* First try to get memory that's already in our heap. */
mem = __heap_alloc (heap, &size);
 
__heap_unlock (heap);
 
if (unlikely (! mem))
/* We couldn't allocate from the heap, so grab some more
from the system, add it to the heap, and try again. */
{
/* If we're trying to allocate a block bigger than the default
MALLOC_HEAP_EXTEND_SIZE, make sure we get enough to hold it. */
void *block;
size_t block_size
= (size < MALLOC_HEAP_EXTEND_SIZE
? MALLOC_HEAP_EXTEND_SIZE
: MALLOC_ROUND_UP_TO_PAGE_SIZE (size));
 
/* Allocate the new heap block. */
#ifdef MALLOC_USE_SBRK
 
__malloc_lock_sbrk ();
 
/* Use sbrk we can, as it's faster than mmap, and guarantees
contiguous allocation. */
block = sbrk (block_size);
if (likely (block != (void *)-1))
{
/* Because sbrk can return results of arbitrary
alignment, align the result to a MALLOC_ALIGNMENT boundary. */
long aligned_block = MALLOC_ROUND_UP ((long)block, MALLOC_ALIGNMENT);
if (block != (void *)aligned_block)
/* Have to adjust. We should only have to actually do this
the first time (after which we will have aligned the brk
correctly). */
{
/* Move the brk to reflect the alignment; our next allocation
should start on exactly the right alignment. */
sbrk (aligned_block - (long)block);
block = (void *)aligned_block;
}
}
 
__malloc_unlock_sbrk ();
 
#else /* !MALLOC_USE_SBRK */
 
/* Otherwise, use mmap. */
block = mmap (0, block_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
 
#endif /* MALLOC_USE_SBRK */
 
if (likely (block != (void *)-1))
{
#if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)
struct malloc_mmb *mmb, *prev_mmb, *new_mmb;
#endif
 
MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)",
(long)block, (long)block + block_size, block_size);
 
/* Get back the heap lock. */
__heap_lock (heap);
 
/* Put BLOCK into the heap. */
__heap_free (heap, block, block_size);
 
MALLOC_DEBUG_INDENT (-1);
 
/* Try again to allocate. */
mem = __heap_alloc (heap, &size);
 
__heap_unlock (heap);
 
#if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)
/* Insert a record of BLOCK in sorted order into the
__malloc_mmapped_blocks list. */
 
for (prev_mmb = 0, mmb = __malloc_mmapped_blocks;
mmb;
prev_mmb = mmb, mmb = mmb->next)
if (block < mmb->mem)
break;
 
new_mmb = malloc_from_heap (sizeof *new_mmb, &__malloc_mmb_heap);
new_mmb->next = mmb;
new_mmb->mem = block;
new_mmb->size = block_size;
 
if (prev_mmb)
prev_mmb->next = new_mmb;
else
__malloc_mmapped_blocks = new_mmb;
 
MALLOC_MMB_DEBUG (0, "new mmb at 0x%x: 0x%x[%d]",
(unsigned)new_mmb,
(unsigned)new_mmb->mem, block_size);
#endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
}
}
 
if (likely (mem))
/* Record the size of the block and get the user address. */
{
mem = MALLOC_SETUP (mem, size);
 
MALLOC_DEBUG (-1, "malloc: returning 0x%lx (base:0x%lx, total_size:%ld)",
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
}
else
MALLOC_DEBUG (-1, "malloc: returning 0");
 
return mem;
}
 
void *
malloc (size_t size)
{
void *mem;
#ifdef MALLOC_DEBUGGING
static int debugging_initialized = 0;
if (! debugging_initialized)
{
debugging_initialized = 1;
__malloc_debug_init ();
}
if (__malloc_check)
__heap_check (&__malloc_heap, "malloc");
#endif
 
#ifdef __MALLOC_GLIBC_COMPAT__
if (unlikely (size == 0))
size++;
#else
/* Some programs will call malloc (0). Lets be strict and return NULL */
if (unlikely (size == 0))
return 0;
#endif
 
/* Check if they are doing something dumb like malloc(-1) */
if (unlikely(((unsigned long)size > (unsigned long)(MALLOC_HEADER_SIZE*-2))))
goto oom;
 
mem = malloc_from_heap (size, &__malloc_heap);
if (unlikely (!mem))
{
oom:
__set_errno (ENOMEM);
return 0;
}
 
return mem;
}
/memalign.c
0,0 → 1,94
/*
* libc/stdlib/malloc/memalign.c -- memalign (`aligned malloc') function
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
 
#include "malloc.h"
#include "heap.h"
 
 
#define MAX(x,y) ((x) > (y) ? (x) : (y))
 
/*
______________________ TOTAL _________________________
/ \
+---------------+-------------------------+--------------+
| | | |
+---------------+-------------------------+--------------+
\____ INIT ____/ \______ RETURNED _______/ \____ END ___/
*/
 
void *
memalign (size_t alignment, size_t size)
{
void *mem, *base;
unsigned long tot_addr, tot_end_addr, addr, end_addr;
struct heap *heap = &__malloc_heap;
 
/* Make SIZE something we like. */
size = HEAP_ADJUST_SIZE (size);
 
/* Use malloc to do the initial allocation, since it deals with getting
system memory. We over-allocate enough to be sure that we'll get
enough memory to hold a properly aligned block of size SIZE,
_somewhere_ in the result. */
mem = malloc (size + 2 * alignment);
if (! mem)
/* Allocation failed, we can't do anything. */
return 0;
if (alignment < MALLOC_ALIGNMENT)
return mem;
 
/* Remember the base-address, of the allocation, although we normally
use the user-address for calculations, since that's where the
alignment matters. */
base = MALLOC_BASE (mem);
 
/* The bounds of the initial allocation. */
tot_addr = (unsigned long)mem;
tot_end_addr = (unsigned long)base + MALLOC_SIZE (mem);
 
/* Find a likely place inside MEM with the right alignment. */
addr = MALLOC_ROUND_UP (tot_addr, alignment);
 
/* Unless TOT_ADDR was already aligned correctly, we need to return the
initial part of MEM to the heap. */
if (addr != tot_addr)
{
size_t init_size = addr - tot_addr;
 
/* Ensure that memory returned to the heap is large enough. */
if (init_size < HEAP_MIN_SIZE)
{
addr = MALLOC_ROUND_UP (tot_addr + HEAP_MIN_SIZE, alignment);
init_size = addr - tot_addr;
}
 
__heap_free (heap, base, init_size);
 
/* Remember that we've freed the initial part of MEM. */
base += init_size;
}
 
/* Return the end part of MEM to the heap, unless it's too small. */
end_addr = addr + size;
if (end_addr + MALLOC_REALLOC_MIN_FREE_SIZE < tot_end_addr)
__heap_free (heap, (void *)end_addr, tot_end_addr - end_addr);
else
/* We didn't free the end, so include it in the size. */
end_addr = tot_end_addr;
 
return MALLOC_SETUP (base, end_addr - (unsigned long)base);
}
/heap_alloc_at.c
0,0 → 1,47
/*
* libc/stdlib/malloc/heap_alloc_at.c -- allocate at a specific address
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
 
#include "heap.h"
 
 
/* Allocate SIZE bytes at address MEM in HEAP. Return the actual size
allocated, or 0 if we failed. */
size_t
__heap_alloc_at (struct heap *heap, void *mem, size_t size)
{
struct heap_free_area *fa;
size_t alloced = 0;
 
size = HEAP_ADJUST_SIZE (size);
 
HEAP_DEBUG (heap, "before __heap_alloc_at");
 
/* Look for a free area that can contain SIZE bytes. */
for (fa = heap->free_areas; fa; fa = fa->next)
{
void *fa_mem = HEAP_FREE_AREA_START (fa);
if (fa_mem <= mem)
{
if (fa_mem == mem && fa->size >= size)
/* FA has the right addr, and is big enough! */
alloced = __heap_free_area_alloc (heap, fa, size);
break;
}
}
 
HEAP_DEBUG (heap, "after __heap_alloc_at");
 
return alloced;
}
/Makefile
0,0 → 1,58
# Makefile for uClibc
#
# Copyright (C) 2002,03 NEC Electronics Corporation
# Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Library General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program 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 Library General Public License for more
# details.
#
# You should have received a copy of the GNU Library General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Derived in part from the Linux-8086 C library, the GNU C Library, and several
# other sundry sources. Files within this library are copyright by their
# respective copyright holders.
 
TOPDIR=../../../
include $(TOPDIR)Rules.mak
 
CSRC = malloc.c calloc.c free.c realloc.c memalign.c \
heap_alloc.c heap_alloc_at.c heap_free.c
 
# Turn on malloc debugging if requested
ifeq ($(UCLIBC_MALLOC_DEBUGGING),y)
CSRC += malloc_debug.c heap_debug.c
CFLAGS += -DMALLOC_DEBUGGING -DHEAP_DEBUGGING
ifeq ($(UCLIBC_UCLINUX_BROKEN_MUNMAP),y)
CFLAGS += -DMALLOC_MMB_DEBUGGING
endif
endif
 
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
 
all: $(OBJS) $(LIBC)
 
$(LIBC): ar-target
 
ar-target: $(OBJS)
$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
 
malloc.o free.o realloc.o memalign.o: malloc.h
$(COBJS): heap.h
 
# Depend on uClinux_config.h to cache changes in __UCLIBC_MALLOC_DEBUGGING__
$(COBJS): %.o : %.c ../../../include/bits/uClibc_config.h
$(CC) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
 
clean:
$(RM) *.[oa] *~ core
/malloc.h
0,0 → 1,214
/*
* libc/stdlib/malloc/malloc.h -- small malloc implementation
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
/* The alignment we guarantee for malloc return values. */
#define MALLOC_ALIGNMENT (sizeof (double))
 
/* The system pagesize we assume; we really ought to get it with
getpagesize, but gee, how annoying. */
#define MALLOC_PAGE_SIZE 4096
 
/* The minimum size of block we request from the the system to extend the
heap for small allocations (we may request a bigger block if necessary to
satisfy a particularly big request). */
#define MALLOC_HEAP_EXTEND_SIZE MALLOC_PAGE_SIZE
 
/* When a heap free-area grows above this size, try to unmap it, releasing
the memory back to the system. */
#define MALLOC_UNMAP_THRESHOLD (8*MALLOC_PAGE_SIZE)
/* When unmapping a free-area, retain this many bytes if it's the only one,
to avoid completely emptying the heap. This is only a heuristic -- the
existance of another free area, even if it's smaller than
MALLOC_MIN_SIZE, will cause us not to reserve anything. */
#define MALLOC_MIN_SIZE (2*MALLOC_PAGE_SIZE)
 
/* When realloc shrinks an allocation, it only does so if more than this
many bytes will be freed; it must at at least HEAP_MIN_SIZE. Larger
values increase speed (by reducing heap fragmentation) at the expense of
space. */
#define MALLOC_REALLOC_MIN_FREE_SIZE (HEAP_MIN_SIZE + 16)
 
 
/* For systems with an MMU, use sbrk to map/unmap memory for the malloc
heap, instead of mmap/munmap. This is a tradeoff -- sbrk is faster than
mmap/munmap, and guarantees contiguous allocation, but is also less
flexible, and causes the heap to only be shrinkable from the end. */
#ifdef __UCLIBC_HAS_MMU__
# define MALLOC_USE_SBRK
#endif
 
 
/* The current implementation of munmap in uClinux doesn't work correctly:
it requires that ever call to munmap exactly match a corresponding call
to mmap (that is, it doesn't allow you to unmap only part of a
previously allocated block, or to unmap two contiguous blocks with a
single call to munmap). This behavior is broken, and uClinux should be
fixed; however, until it is, we add code to work around the problem in
malloc. */
#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
 
/* A structure recording a block of memory mmapped by malloc. */
struct malloc_mmb
{
void *mem; /* the mmapped block */
size_t size; /* its size */
struct malloc_mmb *next;
};
 
/* A list of all malloc_mmb structures describing blocsk that malloc has
mmapped, ordered by the block address. */
extern struct malloc_mmb *__malloc_mmapped_blocks;
 
/* A heap used for allocating malloc_mmb structures. We could allocate
them from the main heap, but that tends to cause heap fragmentation in
annoying ways. */
extern struct heap __malloc_mmb_heap;
 
/* Define MALLOC_MMB_DEBUGGING to cause malloc to emit debugging info about
about mmap block allocation/freeing by the `uclinux broken munmap' code
to stderr, when the variable __malloc_mmb_debug is set to true. */
#ifdef MALLOC_MMB_DEBUGGING
# include <stdio.h>
extern int __malloc_mmb_debug;
# define MALLOC_MMB_DEBUG(indent, fmt, args...) \
(__malloc_mmb_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0)
# define MALLOC_MMB_DEBUG_INDENT(indent) \
(__malloc_mmb_debug ? __malloc_debug_indent (indent) : 0)
# ifndef MALLOC_DEBUGGING
# define MALLOC_DEBUGGING
# endif
#else /* !MALLOC_MMB_DEBUGGING */
# define MALLOC_MMB_DEBUG(fmt, args...) (void)0
# define MALLOC_MMB_DEBUG_INDENT(indent) (void)0
#endif /* MALLOC_MMB_DEBUGGING */
 
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
 
 
/* The size of a malloc allocation is stored in a size_t word
MALLOC_ALIGNMENT bytes prior to the start address of the allocation:
 
+--------+---------+-------------------+
| SIZE |(unused) | allocation ... |
+--------+---------+-------------------+
^ BASE ^ ADDR
^ ADDR - MALLOC_ALIGN
*/
 
/* The amount of extra space used by the malloc header. */
#define MALLOC_HEADER_SIZE MALLOC_ALIGNMENT
 
/* Set up the malloc header, and return the user address of a malloc block. */
#define MALLOC_SETUP(base, size) \
(MALLOC_SET_SIZE (base, size), (void *)((char *)base + MALLOC_HEADER_SIZE))
/* Set the size of a malloc allocation, given the base address. */
#define MALLOC_SET_SIZE(base, size) (*(size_t *)(base) = (size))
 
/* Return base-address of a malloc allocation, given the user address. */
#define MALLOC_BASE(addr) ((void *)((char *)addr - MALLOC_HEADER_SIZE))
/* Return the size of a malloc allocation, given the user address. */
#define MALLOC_SIZE(addr) (*(size_t *)MALLOC_BASE(addr))
 
 
/* Locking for multithreaded apps. */
#ifdef __UCLIBC_HAS_THREADS__
 
# include <pthread.h>
 
# define MALLOC_USE_LOCKING
 
typedef pthread_mutex_t malloc_mutex_t;
# define MALLOC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
 
# ifdef MALLOC_USE_SBRK
/* This lock is used to serialize uses of the `sbrk' function (in both
malloc and free, sbrk may be used several times in succession, and
things will break if these multiple calls are interleaved with another
thread's use of sbrk!). */
extern malloc_mutex_t __malloc_sbrk_lock;
# define __malloc_lock_sbrk() __pthread_mutex_lock (&__malloc_sbrk_lock)
# define __malloc_unlock_sbrk() __pthread_mutex_unlock (&__malloc_sbrk_lock)
# endif /* MALLOC_USE_SBRK */
 
#else /* !__UCLIBC_HAS_THREADS__ */
 
/* Without threads, mutex operations are a nop. */
# define __malloc_lock_sbrk() (void)0
# define __malloc_unlock_sbrk() (void)0
 
#endif /* __UCLIBC_HAS_THREADS__ */
 
 
/* branch-prediction macros; they may already be defined by libc. */
#ifndef likely
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
#define likely(cond) __builtin_expect(!!(int)(cond), 1)
#define unlikely(cond) __builtin_expect((int)(cond), 0)
#else
#define likely(cond) (cond)
#define unlikely(cond) (cond)
#endif
#endif /* !likely */
 
 
/* Define MALLOC_DEBUGGING to cause malloc to emit debugging info to stderr
when the variable __malloc_debug is set to true. */
#ifdef MALLOC_DEBUGGING
 
extern void __malloc_debug_init (void);
 
/* The number of spaces in a malloc debug indent level. */
#define MALLOC_DEBUG_INDENT_SIZE 3
 
extern int __malloc_debug, __malloc_check;
 
# define MALLOC_DEBUG(indent, fmt, args...) \
(__malloc_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0)
# define MALLOC_DEBUG_INDENT(indent) \
(__malloc_debug ? __malloc_debug_indent (indent) : 0)
 
extern int __malloc_debug_cur_indent;
 
/* Print FMT and args indented at the current debug print level, followed
by a newline, and change the level by INDENT. */
extern void __malloc_debug_printf (int indent, const char *fmt, ...);
 
/* Change the current debug print level by INDENT, and return the value. */
#define __malloc_debug_indent(indent) (__malloc_debug_cur_indent += indent)
 
/* Set the current debug print level to LEVEL. */
#define __malloc_debug_set_indent(level) (__malloc_debug_cur_indent = level)
 
#else /* !MALLOC_DEBUGGING */
# define MALLOC_DEBUG(fmt, args...) (void)0
# define MALLOC_DEBUG_INDENT(indent) (void)0
#endif /* MALLOC_DEBUGGING */
 
 
/* Return SZ rounded down to POWER_OF_2_SIZE (which must be power of 2). */
#define MALLOC_ROUND_DOWN(sz, power_of_2_size) \
((sz) & ~(power_of_2_size - 1))
/* Return SZ rounded to POWER_OF_2_SIZE (which must be power of 2). */
#define MALLOC_ROUND_UP(sz, power_of_2_size) \
MALLOC_ROUND_DOWN ((sz) + (power_of_2_size - 1), (power_of_2_size))
 
/* Return SZ rounded down to a multiple MALLOC_PAGE_SIZE. */
#define MALLOC_ROUND_DOWN_TO_PAGE_SIZE(sz) \
MALLOC_ROUND_DOWN (sz, MALLOC_PAGE_SIZE)
/* Return SZ rounded up to a multiple MALLOC_PAGE_SIZE. */
#define MALLOC_ROUND_UP_TO_PAGE_SIZE(sz) \
MALLOC_ROUND_UP (sz, MALLOC_PAGE_SIZE)
 
 
/* The malloc heap. */
extern struct heap __malloc_heap;
/calloc.c
0,0 → 1,41
/* vi: set sw=4 ts=4: */
/* calloc for uClibc
*
* Copyright (C) 2002 by Erik Andersen <andersen@uclibc.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 Library General Public License
* for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
#include <stdlib.h>
#include <string.h>
#include <errno.h>
 
void * calloc(size_t nmemb, size_t lsize)
{
void *result;
size_t size=lsize * nmemb;
 
/* guard vs integer overflow, but allow nmemb
* to fall through and call malloc(0) */
if (nmemb && lsize != (size / nmemb)) {
__set_errno(ENOMEM);
return NULL;
}
if ((result=malloc(size)) != NULL) {
memset(result, 0, size);
}
return result;
}
 
/malloc_debug.c
0,0 → 1,86
/*
* libc/stdlib/malloc/malloc_debug.c -- malloc debugging support
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License. See the file COPYING.LIB in the main
* directory of this archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
 
#include "malloc.h"
#include "heap.h"
 
int __malloc_debug = 0, __malloc_check = 0;
 
#ifdef MALLOC_MMB_DEBUGGING
int __malloc_mmb_debug = 0;
#endif
 
/* Debugging output is indented this may levels. */
int __malloc_debug_cur_indent = 0;
 
 
/* Print FMT and args indented at the current debug print level, followed
by a newline, and change the level by INDENT. */
void
__malloc_debug_printf (int indent, const char *fmt, ...)
{
unsigned spaces = __malloc_debug_cur_indent * MALLOC_DEBUG_INDENT_SIZE;
va_list val;
 
while (spaces > 0)
{
putc (' ', stderr);
spaces--;
}
 
va_start (val, fmt);
vfprintf (stderr, fmt, val);
va_end (val);
 
putc ('\n', stderr);
 
__malloc_debug_indent (indent);
}
 
void
__malloc_debug_init (void)
{
char *ev = getenv ("MALLOC_DEBUG");
if (ev)
{
int val = atoi (ev);
 
if (val & 1)
__malloc_check = 1;
 
if (val & 2)
__malloc_debug = 1;
 
#ifdef MALLOC_MMB_DEBUGGING
if (val & 4)
__malloc_mmb_debug = 1;
#endif
 
#ifdef HEAP_DEBUGGING
if (val & 8)
__heap_debug = 1;
#endif
 
if (val)
__malloc_debug_printf
(0, "malloc_debug: initialized to %d (check = %d, dump = %d, dump_mmb = %d, dump_heap = %d)",
val,
!!(val & 1), !!(val & 2),
!!(val & 4), !!(val & 8));
}
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.