summaryrefslogtreecommitdiff
path: root/ecos/packages/services/memalloc/common/current/include/mvarimpl.inl
diff options
context:
space:
mode:
Diffstat (limited to 'ecos/packages/services/memalloc/common/current/include/mvarimpl.inl')
-rw-r--r--ecos/packages/services/memalloc/common/current/include/mvarimpl.inl454
1 files changed, 454 insertions, 0 deletions
diff --git a/ecos/packages/services/memalloc/common/current/include/mvarimpl.inl b/ecos/packages/services/memalloc/common/current/include/mvarimpl.inl
new file mode 100644
index 0000000000..df38635a42
--- /dev/null
+++ b/ecos/packages/services/memalloc/common/current/include/mvarimpl.inl
@@ -0,0 +1,454 @@
+#ifndef CYGONCE_MEMALLOC_MVARIMPL_INL
+#define CYGONCE_MEMALLOC_MVARIMPL_INL
+
+//==========================================================================
+//
+// mvarimpl.inl
+//
+// Memory pool with variable block class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos 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 General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): hmt
+// Contributors: jlarmour
+// Date: 2000-06-12
+// Purpose: Define Mvarimpl class interface
+// Description: Inline class for constructing a variable block allocator
+// Usage: #include <cyg/memalloc/mvarimpl.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/memalloc.h>
+#include <cyg/memalloc/mvarimpl.hxx>
+
+#include <cyg/infra/cyg_ass.h> // assertion support
+#include <cyg/infra/cyg_trac.h> // tracing support
+
+// Simple allocator
+
+// The free list is stored on a doubly linked list, each member of
+// which is stored in the body of the free memory. The head of the
+// list has the same structure but its size field is zero. This
+// resides in the memory pool structure. Always having at least one
+// item on the list simplifies the alloc and free code.
+
+//
+inline cyg_int32
+Cyg_Mempool_Variable_Implementation::roundup( cyg_int32 size )
+{
+
+ size += sizeof(struct memdq);
+ size = (size + alignment - 1) & -alignment;
+ return size;
+}
+
+inline struct Cyg_Mempool_Variable_Implementation::memdq *
+Cyg_Mempool_Variable_Implementation::addr2memdq( cyg_uint8 *addr )
+{
+ struct memdq *dq;
+ dq = (struct memdq *)(roundup((cyg_int32)addr) - sizeof(struct memdq));
+ return dq;
+}
+
+inline struct Cyg_Mempool_Variable_Implementation::memdq *
+Cyg_Mempool_Variable_Implementation::alloc2memdq( cyg_uint8 *addr )
+{
+ return (struct memdq *)(addr - sizeof(struct memdq));
+}
+
+inline cyg_uint8 *
+Cyg_Mempool_Variable_Implementation::memdq2alloc( struct memdq *dq )
+{
+ return ((cyg_uint8 *)dq + sizeof(struct memdq));
+}
+
+// -------------------------------------------------------------------------
+
+inline void
+Cyg_Mempool_Variable_Implementation::insert_free_block( struct memdq *dq )
+{
+ struct memdq *hdq=&head;
+
+ freemem += dq->size;
+#ifdef CYGSEM_MEMALLOC_ALLOCATOR_VARIABLE_COALESCE
+// For simple coalescing have the free list be sorted by memory base address
+ struct memdq *idq;
+
+ for (idq = hdq->next; idq != hdq; idq = idq->next) {
+ if (idq > dq)
+ break;
+ }
+ // we want to insert immediately before idq
+ dq->next = idq;
+ dq->prev = idq->prev;
+ idq->prev = dq;
+ dq->prev->next = dq;
+
+ // Now do coalescing, but leave the head of the list alone.
+ if (dq->next != hdq && (char *)dq + dq->size == (char *)dq->next) {
+ dq->size += dq->next->size;
+ dq->next = dq->next->next;
+ dq->next->prev = dq;
+ }
+ if (dq->prev != hdq && (char *)dq->prev + dq->prev->size == (char *)dq) {
+ dq->prev->size += dq->size;
+ dq->prev->next = dq->next;
+ dq->next->prev = dq->prev;
+ dq = dq->prev;
+ }
+#else
+ dq->prev = hdq;
+ dq->next = hdq->next;
+ hdq->next = dq;
+ dq->next->prev=dq;
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+inline
+Cyg_Mempool_Variable_Implementation::Cyg_Mempool_Variable_Implementation(
+ cyg_uint8 *base,
+ cyg_int32 size,
+ CYG_ADDRWORD align )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( align > 0, "Bad alignment" );
+ CYG_ASSERT(0!=align ,"align is zero");
+ CYG_ASSERT(0==(align & align-1),"align not a power of 2");
+
+ if ((unsigned)size < sizeof(struct memdq)) {
+ bottom = NULL;
+ return;
+ }
+
+ obase=base;
+ osize=size;
+
+ alignment = align;
+ while (alignment < (cyg_int32)sizeof(struct memdq))
+ alignment += alignment;
+ CYG_ASSERT(0==(alignment & alignment-1),"alignment not a power of 2");
+
+ // the memdq for each allocation is always positioned immediately before
+ // an aligned address, so that the allocation (i.e. what eventually gets
+ // returned from alloc()) is at the correctly aligned address
+ // Therefore bottom is set to the lowest available address given the size of
+ // struct memdq and the alignment.
+ bottom = (cyg_uint8 *)addr2memdq(base);
+
+ // because we split free blocks by allocating memory from the end, not
+ // the beginning, then to preserve alignment, the *top* must also be
+ // aligned such that (top-bottom) is a multiple of the alignment
+ top = (cyg_uint8 *)((cyg_int32)(base+size+sizeof(struct memdq)) & -alignment) -
+ sizeof(struct memdq);
+
+ CYG_ASSERT( top > bottom , "heap too small" );
+ CYG_ASSERT( top <= (base+size), "top too large" );
+ CYG_ASSERT( ((cyg_int32)(top+sizeof(struct memdq)) & alignment-1)==0,
+ "top badly aligned" );
+
+ struct memdq *hdq = &head, *dq = (struct memdq *)bottom;
+
+ CYG_ASSERT( ((cyg_int32)memdq2alloc(dq) & alignment-1)==0,
+ "bottom badly aligned" );
+
+ hdq->prev = hdq->next = dq;
+ hdq->size = 0;
+ dq->prev = dq->next = hdq;
+
+ freemem = dq->size = top - bottom;
+}
+
+// -------------------------------------------------------------------------
+
+inline
+Cyg_Mempool_Variable_Implementation::~Cyg_Mempool_Variable_Implementation()
+{
+}
+
+// -------------------------------------------------------------------------
+// allocation is simple
+// First we look down the free list for a large enough block
+// If we find a block the right size, we unlink the block from
+// the free list and return a pointer to it.
+// If we find a larger block, we chop a piece off the end
+// and return that
+// Otherwise we will eventually get back to the head of the list
+// and return NULL
+inline cyg_uint8 *
+Cyg_Mempool_Variable_Implementation::try_alloc( cyg_int32 size )
+{
+ struct memdq *dq = &head;
+ cyg_uint8 *alloced;
+
+ CYG_REPORT_FUNCTION();
+
+ // Allow uninitialised (zero sized) heaps because they could exist as a
+ // quirk of the MLT setup where a dynamically sized heap is at the top of
+ // memory.
+ if (NULL == bottom)
+ return NULL;
+
+ size = roundup(size);
+
+ do {
+ CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
+ dq = dq->next;
+ if(0 == dq->size) {
+ CYG_ASSERT(dq == &head, "bad free block");
+ return NULL;
+ }
+ } while(dq->size < size);
+
+ if( size == dq->size ) {
+ // exact fit -- unlink from free list
+ dq->prev->next = dq->next;
+ dq->next->prev = dq->prev;
+ alloced = (cyg_uint8 *)dq;
+ } else {
+
+ CYG_ASSERT( dq->size > size, "block found is too small");
+
+ // allocate portion of memory from end of block
+
+ dq->size -=size;
+
+ // The portion left over has to be large enough to store a
+ // struct memdq. This is guaranteed because the alignment is
+ // larger than the size of this structure.
+
+ CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=dq->size ,
+ "not enough space for list item" );
+
+ alloced = (cyg_uint8 *)dq + dq->size;
+ }
+
+ CYG_ASSERT( bottom<=alloced && alloced<=top, "alloced outside pool" );
+
+ // Set size on allocated block
+
+ dq = (struct memdq *)alloced;
+ dq->size = size;
+ dq->next = dq->prev = (struct memdq *)0xd530d53; // magic number
+
+ freemem -=size;
+
+ cyg_uint8 *ptr = memdq2alloc( dq );
+ CYG_ASSERT( ((CYG_ADDRESS)ptr & (alignment-1)) == 0,
+ "returned memory not aligned" );
+ CYG_MEMALLOC_FAIL_TEST(ptr==NULL, size);
+
+ return ptr;
+}
+
+// -------------------------------------------------------------------------
+// resize existing allocation, if oldsize is non-NULL, previous
+// allocation size is placed into it. If previous size not available,
+// it is set to 0. NB previous allocation size may have been rounded up.
+// Occasionally the allocation can be adjusted *backwards* as well as,
+// or instead of forwards, therefore the address of the resized
+// allocation is returned, or NULL if no resizing was possible.
+// Note that this differs from ::realloc() in that no attempt is
+// made to call malloc() if resizing is not possible - that is left
+// to higher layers. The data is copied from old to new though.
+// The effects of alloc_ptr==NULL or newsize==0 are undefined
+
+inline cyg_uint8 *
+Cyg_Mempool_Variable_Implementation::resize_alloc( cyg_uint8 *alloc_ptr,
+ cyg_int32 newsize,
+ cyg_int32 *oldsize )
+{
+ cyg_uint8 *ret = NULL;
+
+ CYG_REPORT_FUNCTION();
+
+ CYG_CHECK_DATA_PTRC( alloc_ptr );
+ if ( NULL != oldsize )
+ CYG_CHECK_DATA_PTRC( oldsize );
+
+ CYG_ASSERT( (bottom <= alloc_ptr) && (alloc_ptr <= top),
+ "alloc_ptr outside pool" );
+
+ struct memdq *dq=alloc2memdq( alloc_ptr );
+
+ // check magic number in block for validity
+ CYG_ASSERT( (dq->next == dq->prev) &&
+ (dq->next == (struct memdq *)0xd530d53), "bad alloc_ptr" );
+
+ newsize = roundup(newsize);
+
+ if ( NULL != oldsize )
+ *oldsize = dq->size;
+
+ if ( newsize > dq->size ) {
+ // see if we can increase the allocation size
+ if ( (cyg_uint8 *)dq + newsize <= top ) { // obviously can't exceed pool
+ struct memdq *nextdq = (struct memdq *)((cyg_uint8 *)dq + dq->size);
+
+ if ( (nextdq->next != nextdq->prev) &&
+ (nextdq->size >= (newsize - dq->size)) ) {
+ // it's free and it's big enough
+ // we therefore temporarily join this block and *all* of
+ // the next block, so that the code below can then split it
+ nextdq->next->prev = nextdq->prev;
+ nextdq->prev->next = nextdq->next;
+ dq->size += nextdq->size;
+ freemem -= nextdq->size;
+ }
+ } // if
+ } // if
+
+ // this is also used if the allocation size was increased and we need
+ // to split it
+ if ( newsize < dq->size ) {
+ // We can shrink the allocation by splitting into smaller allocation and
+ // new free block
+ struct memdq *newdq = (struct memdq *)((cyg_uint8 *)dq + newsize);
+
+ newdq->size = dq->size - newsize;
+ dq->size = newsize;
+
+ CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=newdq->size ,
+ "not enough space for list item" );
+
+ // now return the new space back to the freelist
+ insert_free_block( newdq );
+
+ ret = alloc_ptr;
+
+ } // if
+ else if ( newsize == dq->size ) {
+ ret = alloc_ptr;
+ }
+
+ CYG_MEMALLOC_FAIL_TEST(ret==NULL, newsize);
+
+ return ret;
+
+} // resize_alloc()
+
+
+// -------------------------------------------------------------------------
+// When no coalescing is done, free is simply a matter of using the
+// freed memory as an element of the free list linking it in at the
+// start. When coalescing, the free list is sorted
+
+inline cyg_bool
+Cyg_Mempool_Variable_Implementation::free( cyg_uint8 *p, cyg_int32 size )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_CHECK_DATA_PTRC( p );
+
+ if (!((bottom <= p) && (p <= top)))
+ return false;
+
+ struct memdq *dq=alloc2memdq( p );
+
+ // check magic number in block for validity
+ if ( (dq->next != dq->prev) ||
+ (dq->next != (struct memdq *)0xd530d53) )
+ return false;
+
+ if ( 0==size ) {
+ size = dq->size;
+ } else {
+ size = roundup(size);
+ }
+
+ if( dq->size != size )
+ return false;
+
+ CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=size ,
+ "not enough space for list item" );
+
+ insert_free_block( dq );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+inline void
+Cyg_Mempool_Variable_Implementation::get_status(
+ cyg_mempool_status_flag_t flags,
+ Cyg_Mempool_Status &status )
+{
+ CYG_REPORT_FUNCTION();
+
+// as quick or quicker to just set it, rather than test flag first
+ status.arenabase = obase;
+ if ( 0 != (flags & CYG_MEMPOOL_STAT_ARENASIZE) )
+ status.arenasize = top - bottom;
+ if ( 0 != (flags & CYG_MEMPOOL_STAT_TOTALALLOCATED) )
+ status.totalallocated = (top-bottom) - freemem;
+// as quick or quicker to just set it, rather than test flag first
+ status.totalfree = freemem;
+ if ( 0 != (flags & CYG_MEMPOOL_STAT_MAXFREE) ) {
+ struct memdq *dq = &head;
+ cyg_int32 mf = 0;
+
+ do {
+ CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
+ dq = dq->next;
+ if(0 == dq->size) {
+ CYG_ASSERT(dq == &head, "bad free block");
+ break;
+ }
+ if(dq->size > mf)
+ mf = dq->size;
+ } while(1);
+ status.maxfree = mf - sizeof(struct memdq);
+ }
+// as quick or quicker to just set it, rather than test flag first
+ status.origbase = obase;
+// as quick or quicker to just set it, rather than test flag first
+ status.origsize = osize;
+
+ CYG_REPORT_RETURN();
+
+} // get_status()
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_MEMALLOC_MVARIMPL_INL
+// EOF mvarimpl.inl