342 lines
8.8 KiB
C
342 lines
8.8 KiB
C
/* Copyright 2014 Samsung Electronics Co., Ltd.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/** \addtogroup mem Memory allocation
|
|
* @{
|
|
*
|
|
* \addtogroup poolman Memory pool manager
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Memory pool manager implementation
|
|
*/
|
|
|
|
#define JERRY_MEM_POOL_INTERNAL
|
|
|
|
#include "globals.h"
|
|
#include "jerry-libc.h"
|
|
#include "mem-allocator.h"
|
|
#include "mem-heap.h"
|
|
#include "mem-pool.h"
|
|
#include "mem-poolman.h"
|
|
|
|
/**
|
|
* Lists of pools for possible chunk sizes
|
|
*/
|
|
mem_PoolState_t *mem_Pools[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
|
|
|
/**
|
|
* Number of free chunks of possible chunk sizes
|
|
*/
|
|
size_t mem_FreeChunksNumber[ MEM_POOL_CHUNK_TYPE__COUNT ];
|
|
|
|
/**
|
|
* Pool, containing pool headers
|
|
*/
|
|
mem_PoolState_t mem_PoolForPoolHeaders;
|
|
|
|
/**
|
|
* Space for pool, containing pool headers
|
|
*/
|
|
uint8_t *mem_SpaceForPoolForPoolHeaders;
|
|
|
|
#ifdef MEM_STATS
|
|
/**
|
|
* Pools' memory usage statistics
|
|
*/
|
|
mem_PoolsStats_t mem_PoolsStats;
|
|
|
|
static void mem_PoolsStatInit( void);
|
|
static void mem_PoolsStatAllocPool( mem_PoolChunkType_t);
|
|
static void mem_PoolsStatFreePool( mem_PoolChunkType_t);
|
|
static void mem_PoolsStatAllocChunk( mem_PoolChunkType_t);
|
|
static void mem_PoolsStatFreeChunk( mem_PoolChunkType_t);
|
|
#else /* !MEM_STATS */
|
|
# define mem_PoolsStatInit()
|
|
# define mem_PoolsStatAllocPool(v)
|
|
# define mem_PoolsStatFreePool(v)
|
|
# define mem_PoolsStatAllocChunk(v)
|
|
# define mem_PoolsStatFreeChunk(v)
|
|
#endif /* !MEM_STATS */
|
|
|
|
/**
|
|
* Get chunk size from chunk type.
|
|
*
|
|
* @return size (in bytes) of chunk of specified type
|
|
*/
|
|
size_t
|
|
mem_GetChunkSize( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
uint32_t chunkTypeId = (uint32_t) chunkType;
|
|
|
|
JERRY_ASSERT( chunkTypeId < MEM_POOL_CHUNK_TYPE__COUNT );
|
|
|
|
return ( 1u << ( chunkTypeId + 2 ) );
|
|
} /* mem_GetChunkSize */
|
|
|
|
/**
|
|
* Initialize pool manager
|
|
*/
|
|
void
|
|
mem_PoolsInit(void)
|
|
{
|
|
for ( uint32_t i = 0; i < MEM_POOL_CHUNK_TYPE__COUNT; i++ )
|
|
{
|
|
mem_Pools[ i ] = NULL;
|
|
mem_FreeChunksNumber[ i ] = 0;
|
|
}
|
|
|
|
/**
|
|
* Space, at least for four pool headers and a bitmap entry.
|
|
*
|
|
* TODO: Research.
|
|
*/
|
|
size_t poolSpaceSize = mem_HeapRecommendAllocationSize( 4 * sizeof (mem_PoolState_t) + sizeof (mword_t) );
|
|
|
|
mem_SpaceForPoolForPoolHeaders = mem_HeapAllocBlock(poolSpaceSize,
|
|
MEM_HEAP_ALLOC_LONG_TERM);
|
|
|
|
/*
|
|
* Get chunk type, checking that there is a type corresponding to specified size.
|
|
*/
|
|
const mem_PoolChunkType_t chunkType = mem_SizeToPoolChunkType( sizeof(mem_PoolState_t));
|
|
|
|
mem_PoolInit(&mem_PoolForPoolHeaders,
|
|
mem_GetChunkSize( chunkType),
|
|
mem_SpaceForPoolForPoolHeaders,
|
|
poolSpaceSize);
|
|
|
|
mem_PoolsStatInit();
|
|
} /* mem_PoolsInit */
|
|
|
|
/**
|
|
* Allocate a chunk of specified size
|
|
*
|
|
* @return pointer to allocated chunk, if allocation was successful,
|
|
* or NULL - if not enough memory.
|
|
*/
|
|
uint8_t*
|
|
mem_PoolsAlloc( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
size_t chunkSize = mem_GetChunkSize( chunkType);
|
|
|
|
/**
|
|
* If there are no free chunks, allocate new pool.
|
|
*/
|
|
if ( mem_FreeChunksNumber[ chunkType ] == 0 )
|
|
{
|
|
mem_PoolState_t *poolState = (mem_PoolState_t*) mem_PoolAllocChunk( &mem_PoolForPoolHeaders);
|
|
|
|
if ( poolState == NULL )
|
|
{
|
|
/**
|
|
* Not enough space for new pool' header.
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Space, at least for eight chunks and a bitmap entry.
|
|
*
|
|
* TODO: Research.
|
|
*/
|
|
size_t poolSpaceSize = mem_HeapRecommendAllocationSize( 8 * chunkSize + sizeof (mword_t) );
|
|
|
|
uint8_t *poolSpace = mem_HeapAllocBlock( poolSpaceSize,
|
|
MEM_HEAP_ALLOC_LONG_TERM);
|
|
|
|
if ( poolSpace == NULL )
|
|
{
|
|
/**
|
|
* Not enough memory.
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
mem_PoolInit( poolState,
|
|
chunkSize,
|
|
poolSpace,
|
|
poolSpaceSize);
|
|
|
|
poolState->m_pNextPool = mem_Pools[ chunkType ];
|
|
mem_Pools[ chunkType ] = poolState;
|
|
|
|
mem_FreeChunksNumber[ chunkType ] += poolState->m_FreeChunksNumber;
|
|
|
|
mem_PoolsStatAllocPool( chunkType);
|
|
}
|
|
|
|
/**
|
|
* Now there is definitely at least one pool of specified type with at least one free chunk.
|
|
*
|
|
* Search for the pool.
|
|
*/
|
|
mem_PoolState_t *poolState = mem_Pools[ chunkType ];
|
|
|
|
while ( poolState->m_FreeChunksNumber == 0 )
|
|
{
|
|
poolState = poolState->m_pNextPool;
|
|
|
|
JERRY_ASSERT( poolState != NULL );
|
|
}
|
|
|
|
/**
|
|
* And allocate chunk within it.
|
|
*/
|
|
mem_FreeChunksNumber[ chunkType ]--;
|
|
|
|
mem_PoolsStatAllocChunk( chunkType);
|
|
|
|
return mem_PoolAllocChunk( poolState);
|
|
} /* mem_PoolsAlloc */
|
|
|
|
/**
|
|
* Free the chunk
|
|
*/
|
|
void
|
|
mem_PoolsFree( mem_PoolChunkType_t chunkType, /**< the chunk type */
|
|
uint8_t *pChunk) /**< pointer to the chunk */
|
|
{
|
|
mem_PoolState_t *poolState = mem_Pools[ chunkType ], *prevPoolState = NULL;
|
|
|
|
/**
|
|
* Search for the pool containing specified chunk.
|
|
*/
|
|
while ( !( pChunk >= poolState->m_pChunks
|
|
&& pChunk <= poolState->m_pPoolStart + poolState->m_PoolSize ) )
|
|
{
|
|
prevPoolState = poolState;
|
|
poolState = poolState->m_pNextPool;
|
|
|
|
JERRY_ASSERT( poolState != NULL );
|
|
}
|
|
|
|
/**
|
|
* Free the chunk
|
|
*/
|
|
mem_PoolFreeChunk( poolState, pChunk);
|
|
mem_FreeChunksNumber[ chunkType ]++;
|
|
|
|
mem_PoolsStatFreeChunk( chunkType);
|
|
|
|
/**
|
|
* If all chunks of the pool are free, free the pool itself.
|
|
*/
|
|
if ( poolState->m_FreeChunksNumber == poolState->m_ChunksNumber )
|
|
{
|
|
if ( prevPoolState != NULL )
|
|
{
|
|
prevPoolState->m_pNextPool = poolState->m_pNextPool;
|
|
} else
|
|
{
|
|
mem_Pools[ chunkType ] = poolState->m_pNextPool;
|
|
}
|
|
|
|
mem_FreeChunksNumber[ chunkType ] -= poolState->m_ChunksNumber;
|
|
|
|
mem_HeapFreeBlock( poolState->m_pPoolStart);
|
|
|
|
mem_PoolFreeChunk( &mem_PoolForPoolHeaders, (uint8_t*) poolState);
|
|
|
|
mem_PoolsStatFreePool( chunkType);
|
|
}
|
|
} /* mem_PoolsFree */
|
|
|
|
#ifdef MEM_STATS
|
|
/**
|
|
* Get pools memory usage statistics
|
|
*/
|
|
void
|
|
mem_PoolsGetStats( mem_PoolsStats_t *out_pools_stats_p) /**< out: pools' stats */
|
|
{
|
|
JERRY_ASSERT( out_pools_stats_p != NULL );
|
|
|
|
*out_pools_stats_p = mem_PoolsStats;
|
|
} /* mem_PoolsGetStats */
|
|
|
|
/**
|
|
* Initalize pools' memory usage statistics account structure
|
|
*/
|
|
static void
|
|
mem_PoolsStatInit( void)
|
|
{
|
|
__memset( &mem_PoolsStats, 0, sizeof (mem_PoolsStats));
|
|
} /* mem_PoolsStatInit */
|
|
|
|
/**
|
|
* Account allocation of a pool
|
|
*/
|
|
static void
|
|
mem_PoolsStatAllocPool( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
mem_PoolsStats.pools_count[ chunkType ]++;
|
|
mem_PoolsStats.free_chunks[ chunkType ] = mem_FreeChunksNumber[ chunkType ];
|
|
|
|
if ( mem_PoolsStats.pools_count[ chunkType ] > mem_PoolsStats.peak_pools_count[ chunkType ] )
|
|
{
|
|
mem_PoolsStats.peak_pools_count[ chunkType ] = mem_PoolsStats.pools_count[ chunkType ];
|
|
}
|
|
} /* mem_PoolsStatAllocPool */
|
|
|
|
/**
|
|
* Account freeing of a pool
|
|
*/
|
|
static void
|
|
mem_PoolsStatFreePool( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
JERRY_ASSERT( mem_PoolsStats.pools_count[ chunkType ] > 0 );
|
|
|
|
mem_PoolsStats.pools_count[ chunkType ]--;
|
|
mem_PoolsStats.free_chunks[ chunkType ] = mem_FreeChunksNumber[ chunkType ];
|
|
} /* mem_PoolsStatFreePool */
|
|
|
|
/**
|
|
* Account allocation of chunk in a pool
|
|
*/
|
|
static void
|
|
mem_PoolsStatAllocChunk( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
JERRY_ASSERT( mem_PoolsStats.free_chunks[ chunkType ] > 0 );
|
|
|
|
mem_PoolsStats.allocated_chunks[ chunkType ]++;
|
|
mem_PoolsStats.free_chunks[ chunkType ]--;
|
|
|
|
if ( mem_PoolsStats.allocated_chunks[ chunkType ] > mem_PoolsStats.peak_allocated_chunks[ chunkType ] )
|
|
{
|
|
mem_PoolsStats.peak_allocated_chunks[ chunkType ] = mem_PoolsStats.allocated_chunks[ chunkType ];
|
|
}
|
|
} /* mem_PoolsStatAllocChunk */
|
|
|
|
/**
|
|
* Account freeing of chunk in a pool
|
|
*/
|
|
static void
|
|
mem_PoolsStatFreeChunk( mem_PoolChunkType_t chunkType) /**< chunk type */
|
|
{
|
|
JERRY_ASSERT( mem_PoolsStats.allocated_chunks[ chunkType ] > 0 );
|
|
|
|
mem_PoolsStats.allocated_chunks[ chunkType ]--;
|
|
mem_PoolsStats.free_chunks[ chunkType ]++;
|
|
} /* mem_PoolsStatFreeChunk */
|
|
#endif /* MEM_STATS */
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
/**
|
|
* @}
|
|
*/
|