Mercurial > ecos
diff packages/kernel/current/include/mvarimpl.inl @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/kernel/current/include/mvarimpl.inl @@ -0,0 +1,283 @@ +#ifndef CYGONCE_KERNEL_MVARIMPL_INL +#define CYGONCE_KERNEL_MVARIMPL_INL + +//========================================================================== +// +// mvarimpl.inl +// +// Memory pool with variable block class declarations +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt +// Date: 1998-03-23 +// Purpose: Define Mvarimpl class interface +// Description: Inline class for constructing a variable block allocator +// Usage: #include <cyg/kernel/mvarimpl.hxx> +// #include <cyg/kernel/mvarimpl.inl> +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +// Simple non-coalescing 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; +} + +Cyg_Mempool_Variable_Implementation::Cyg_Mempool_Variable_Implementation( + cyg_uint8 *base, + cyg_int32 size, + CYG_ADDRWORD align ) +{ + CYG_ASSERT( align > 0, "Bad alignment" ); + CYG_ASSERT( size > 0, "Bad size" ); + CYG_ASSERT(0!=align ,"align is zero"); + CYG_ASSERT(0==(align & align-1),"align not a power of 2"); + + obase=base; + osize=size; + oalign=align; + + alignment = align; + while(alignment < (cyg_int32)sizeof(struct memdq)) + alignment += alignment; + CYG_ASSERT(0==(alignment & alignment-1),"alignment not a power of 2"); + + bottom = (cyg_uint8 *)roundup((cyg_int32)base); + top = (cyg_uint8 *)((cyg_int32)(base+size) & -alignment); + + CYG_ASSERT( top > bottom , "heap too small" ); + CYG_ASSERT( ((cyg_int32)bottom & alignment-1)==0, "bottom badly aligned" ); + CYG_ASSERT( ((cyg_int32)top & alignment-1)==0, "top badly aligned" ); + + struct memdq *hdq = &head, *dq = (struct memdq *)bottom; + + hdq->prev = hdq->next = dq; + hdq->size = 0; + dq->prev = dq->next = hdq; + + freemem = dq->size = top-bottom; +} + +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::alloc( cyg_int32 size ) +{ + struct memdq *dq = &head; + cyg_uint8 *alloced; + + 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; + return alloced + sizeof(struct memdq); +} + +// As 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. + +inline cyg_bool +Cyg_Mempool_Variable_Implementation::free( cyg_uint8 *p, cyg_int32 size ) +{ + if(!(bottom<=p&&p<=top)) + return false; + + struct memdq *hdq=&head,*dq=(struct memdq *)(p-sizeof(struct memdq)); + + // check magic number in block to be freed + 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" ); + +#ifdef CYGSEM_KERNEL_MEMORY_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; + } + dq->size = size; + if (idq != hdq) { + dq->prev = idq; + dq->next = idq->next; + idq->next = dq; + dq->next->prev = dq; + } else { + dq->next = idq; + dq->prev = idq->prev; + idq->prev = dq; + dq->prev->next = dq; + } + // Now do coalescing + if ((char *)dq + dq->size == (char *)dq->next) { + dq->size += dq->next->size; + dq->next = dq->next->next; + dq->next->prev = dq; + } + if ((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; + dq->size = size; + hdq->next = dq; + dq->next->prev=dq; +#endif + + freemem +=size; + return true; +} + + +inline void +Cyg_Mempool_Variable_Implementation::get_arena( + cyg_uint8 * &base, + cyg_int32 &size, + CYG_ADDRWORD &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); + + base = obase; + size = osize; + maxfree = mf; +} + + +inline cyg_int32 +Cyg_Mempool_Variable_Implementation::get_allocation_size( cyg_uint8 *ptr ) +{ + CYG_CHECK_DATA_PTR(ptr, "Requested allocation size of bad data pointer!"); + + if(!(bottom<=ptr && ptr<=top)) + return -1; + + struct memdq *dq=(struct memdq *)(ptr-sizeof(struct memdq)); + + // check magic number in block to be freed + if(dq->next != dq->prev || dq->next != (struct memdq *)0xd530d53) + return -1; + + return dq->size; + +} // get_allocation_size() + +// ------------------------------------------------------------------------- +#endif // ifndef CYGONCE_KERNEL_MVARIMPL_INL +// EOF mvarimpl.inl
