/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ---- includes ----------------------------------------------------------- */
#include "b_BasicEm/MemSeg.h"
#include "b_BasicEm/Functions.h"
#include "b_BasicEm/Context.h"
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ constructor / destructor } ----------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
void bbs_MemSeg_init( struct bbs_Context* cpA,
struct bbs_MemSeg* ptrA )
{
ptrA->memPtrE = NULL;
ptrA->sizeE = 0;
ptrA->allocIndexE = 0;
ptrA->sharedE = FALSE;
ptrA->idE = 0;
ptrA->dynMemManagerPtrE = NULL;
}
/* ------------------------------------------------------------------------- */
void bbs_MemSeg_exit( struct bbs_Context* cpA,
struct bbs_MemSeg* ptrA )
{
ptrA->memPtrE = NULL;
ptrA->sizeE = 0;
ptrA->allocIndexE = 0;
ptrA->sharedE = FALSE;
ptrA->idE = 0;
ptrA->dynMemManagerPtrE = NULL;
}
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ operators } -------------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ query functions } -------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
uint32 bbs_MemSeg_availableSize( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
if( ptrA->dynMemManagerPtrE == NULL )
{
return ( ptrA->sizeE == ptrA->allocIndexE ) ? 0 : ptrA->sizeE - ptrA->allocIndexE - 2 * ptrA->sharedE;
}
else
{
return 0xFFFFFFFF;
}
}
/* ------------------------------------------------------------------------- */
uint32 bbs_MemSeg_allocatedSize( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
if( ptrA->dynMemManagerPtrE == NULL )
{
return ptrA->allocIndexE;
}
else
{
return bbs_DynMemManager_allocatedSize( cpA, ptrA->dynMemManagerPtrE );
}
}
/* ------------------------------------------------------------------------- */
uint32 bbs_MemSeg_usedSize( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
if( ptrA->dynMemManagerPtrE == NULL )
{
if( ptrA->sharedE )
{
return ptrA->allocIndexE;
}
else
{
uint32 indexL = 0;
uint32 countL = 0;
while( indexL < ptrA->allocIndexE )
{
uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
indexL += ( sizeL & 0xFFFFFFFE );
if( ( sizeL & 1 ) == 0 )
{
countL += sizeL - 2;
}
}
return countL;
}
}
else
{
return bbs_MemSeg_allocatedSize( cpA, ptrA );
}
}
/* ------------------------------------------------------------------------- */
uint32 bbs_MemSeg_blocks( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
uint32 indexL = 0;
uint32 countL = 0;
if( ptrA->sharedE ) return 0;
while( indexL < ptrA->allocIndexE )
{
uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
indexL += ( sizeL & 0xFFFFFFFE );
countL++;
}
return countL;
}
/* ------------------------------------------------------------------------- */
uint32 bbs_MemSeg_usedBlocks( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
uint32 indexL = 0;
uint32 countL = 0;
if( ptrA->sharedE ) return 0;
while( indexL < ptrA->allocIndexE )
{
uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
indexL += ( sizeL & 0xFFFFFFFE );
countL += ( ( sizeL & 1 ) == 0 );
}
return countL;
}
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ modify functions } ------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ I/O } -------------------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ exec functions } --------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
struct bbs_MemSeg bbs_MemSeg_create( struct bbs_Context* cpA,
void* memPtrA, uint32 sizeA )
{
struct bbs_MemSeg memSegL;
memSegL.memPtrE = ( uint16* )memPtrA;
memSegL.sizeE = sizeA & 0xFFFFFFFE; /* enforce even size to avoid overflow problems */
memSegL.allocIndexE = 0;
memSegL.sharedE = FALSE;
memSegL.idE = 0;
memSegL.dynMemManagerPtrE = NULL;
return memSegL;
}
/* ------------------------------------------------------------------------- */
struct bbs_MemSeg bbs_MemSeg_createShared( struct bbs_Context* cpA,
void* memPtrA, uint32 sizeA )
{
struct bbs_MemSeg memSegL;
memSegL.memPtrE = ( uint16* )memPtrA;
memSegL.sizeE = sizeA;
memSegL.allocIndexE = 0;
memSegL.sharedE = TRUE;
memSegL.idE = 0;
memSegL.dynMemManagerPtrE = NULL;
return memSegL;
}
/* ------------------------------------------------------------------------- */
void* bbs_MemSeg_alloc( struct bbs_Context* cpA,
struct bbs_MemSeg* ptrA,
uint32 sizeA )
{
uint16* memPtrL = NULL;
if( bbs_Context_error( cpA ) ) return NULL;
if( !ptrA->sharedE )
{
if( ptrA->dynMemManagerPtrE == NULL )
{
uint32 effSizeL = sizeA + ( sizeA & 1 ) + 2; /* effective block size */
memPtrL = ptrA->memPtrE + ptrA->allocIndexE;
*( ( uint32* )memPtrL ) = effSizeL;
memPtrL += 2;
if( ptrA->allocIndexE + effSizeL > ptrA->sizeE )
{
bbs_ERR2( bbs_ERR_MEMORY_OVERFLOW,
"uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\n"
"Exclusive Memory overflow. Segment size: %i. Requested size: %i", ptrA->sizeE, sizeA );
return NULL;
}
ptrA->allocIndexE += effSizeL;
}
else
{
memPtrL = bbs_DynMemManager_alloc( cpA, ptrA->dynMemManagerPtrE, ptrA, sizeA );
}
}
else
{
uint32 effSizeL = sizeA + ( sizeA & 1 ); /* effective block size */
if( ptrA->allocIndexE + effSizeL > ptrA->sizeE + ( ptrA->sizeE & 1 ) )
{
if( ptrA->dynMemManagerPtrE == NULL )
{
bbs_ERR2( bbs_ERR_MEMORY_OVERFLOW,
"uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\n"
"Shared Memory overflow. Segment size: %i. Requested size: %i", ptrA->sizeE, sizeA );
return NULL;
}
else
{
uint32 actualBlockSizeL = 0;
ptrA->memPtrE = bbs_DynMemManager_nextBlock( cpA, ptrA->dynMemManagerPtrE, ptrA, ptrA->memPtrE, effSizeL, &actualBlockSizeL );
ptrA->sizeE = actualBlockSizeL;
ptrA->allocIndexE = 0;
}
}
memPtrL = ptrA->memPtrE + ptrA->allocIndexE;
ptrA->allocIndexE += effSizeL;
}
#if defined( HW_TMS320C5x )
#ifdef DEBUG2
{
/* check if segment crosses page boundary */
if( ( ( ( uint32 ) ptrA->memPtrE ) >> 16 ) !=
( ( ( uint32 ) ptrA->memPtrE + ( ptrA->sizeE - 1 ) ) >> 16 ) )
{
bbs_ERROR0( "uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\nSegment crosses page boundary\n" );
return NULL;
}
}
#endif
#endif
return memPtrL;
}
/* ------------------------------------------------------------------------- */
void bbs_MemSeg_free( struct bbs_Context* cpA,
struct bbs_MemSeg* ptrA,
void* memPtrA )
{
bbs_DEF_fNameL( "void bbs_MemSeg_free( struct bbs_MemSeg* ptrA, void* memPtrA )" )
if( bbs_Context_error( cpA ) ) return;
/** only valid exclusive segments can be freed */
if( ptrA == NULL || memPtrA == NULL || ptrA->sharedE ) return;
if( ptrA->dynMemManagerPtrE != NULL )
{
bbs_DynMemManager_free( cpA, ptrA->dynMemManagerPtrE, memPtrA );
}
else
{
uint32 indexL, sizeL;
uint16* memPtrL;
if( ptrA == NULL || memPtrA == NULL ) return;
if( ptrA->sharedE ) return;
#ifdef HW_TMS320C5x
indexL = ( uint32 ) memPtrA - ( uint32 ) ptrA->memPtrE - 2;
#else
indexL = ( uint16* )memPtrA - ptrA->memPtrE - 2;
#endif
memPtrL = ptrA->memPtrE + indexL;
sizeL = *( ( int32* )memPtrL );
/* checks */
if( indexL > ptrA->allocIndexE || ( indexL & 1 ) != 0 )
{
bbs_ERROR4( "%s\n: Invalid memory.\n"
"sizeE = %i\n"
"allocIndexE = %i\n"
"indexL = %i\n",
fNameL,
ptrA->sizeE,
ptrA->allocIndexE,
indexL );
return;
}
if( ( sizeL & 1 ) != 0 )
{
bbs_ERROR1( "%s\n: Memory block was already freed once", fNameL );
return;
}
*( ( uint32* )memPtrL ) += 1; /* odd size value indicates unused memory block */
/* free last unused blocks if any */
if( indexL + sizeL == ptrA->allocIndexE )
{
uint32 newAllocIndexL = 0;
indexL = 0;
while( indexL < ptrA->allocIndexE )
{
uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
indexL += ( sizeL & 0xFFFFFFFE );
if( ( sizeL & 1 ) == 0 )
{
newAllocIndexL = indexL;
}
}
ptrA->allocIndexE = newAllocIndexL;
}
#ifdef DEBUG2
bbs_MemSeg_checkConsistency( cpA, ptrA );
#endif
}
}
/* ------------------------------------------------------------------------- */
void bbs_MemSeg_checkConsistency( struct bbs_Context* cpA,
const struct bbs_MemSeg* ptrA )
{
uint32 indexL = 0;
if( ptrA->sharedE ) return;
while( indexL < ptrA->allocIndexE )
{
uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
indexL += ( sizeL & 0xFFFFFFFE );
}
if( indexL != ptrA->allocIndexE )
{
bbs_ERROR0( "Memory consistency check failed" );
}
}
/* ------------------------------------------------------------------------- */
/* ========================================================================= */