Files
jerryscript/src/liballocator/mem-poolman.c
T

364 lines
9.7 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_pool_state_t *mem_pools[ MEM_POOL_CHUNK_TYPE__COUNT ];
/**
* Number of free chunks of possible chunk sizes
*/
size_t mem_free_chunks_number[ MEM_POOL_CHUNK_TYPE__COUNT ];
/**
* Pool, containing pool headers
*/
mem_pool_state_t mem_pool_for_pool_headers;
/**
* Space for pool, containing pool headers
*/
uint8_t *mem_space_for_pool_for_pool_headers;
#ifdef MEM_STATS
/**
* Pools' memory usage statistics
*/
mem_pools_stats_t mem_pools_stats;
static void mem_pools_stat_init( void);
static void mem_pools_stat_alloc_pool( mem_pool_chunk_type_t);
static void mem_pools_stat_free_pool( mem_pool_chunk_type_t);
static void mem_pools_stat_alloc_chunk( mem_pool_chunk_type_t);
static void mem_pools_stat_free_chunk( mem_pool_chunk_type_t);
#else /* !MEM_STATS */
# define mem_pools_stat_init()
# define mem_pools_stat_alloc_pool(v)
# define mem_pools_stat_free_pool(v)
# define mem_pools_stat_alloc_chunk(v)
# define mem_pools_stat_free_chunk(v)
#endif /* !MEM_STATS */
/**
* Get chunk size from chunk type.
*
* @return size (in bytes) of chunk of specified type
*/
size_t
mem_get_chunk_size( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
uint32_t chunk_type_id = (uint32_t) chunk_type;
JERRY_ASSERT( chunk_type_id < MEM_POOL_CHUNK_TYPE__COUNT );
return ( 1u << ( chunk_type_id + 2 ) );
} /* mem_get_chunk_size */
/**
* Initialize pool manager
*/
void
mem_pools_init(void)
{
for ( uint32_t i = 0; i < MEM_POOL_CHUNK_TYPE__COUNT; i++ )
{
mem_pools[ i ] = NULL;
mem_free_chunks_number[ i ] = 0;
}
/**
* Space, at least for four pool headers and a bitmap entry.
*
* TODO: Research.
*/
size_t pool_space_size = mem_heap_recommend_allocation_size( 4 * sizeof (mem_pool_state_t) );
mem_space_for_pool_for_pool_headers = mem_heap_alloc_block( pool_space_size, MEM_HEAP_ALLOC_LONG_TERM);
/*
* Get chunk type, checking that there is a type corresponding to specified size.
*/
const mem_pool_chunk_type_t chunk_type = mem_size_to_pool_chunk_type( sizeof(mem_pool_state_t));
mem_pool_init(&mem_pool_for_pool_headers,
mem_get_chunk_size( chunk_type),
mem_space_for_pool_for_pool_headers,
pool_space_size);
mem_pools_stat_init();
} /* mem_pools_init */
/**
* Finalize pool manager
*/
void
mem_pools_finalize(void)
{
for ( uint32_t i = 0; i < MEM_POOL_CHUNK_TYPE__COUNT; i++ )
{
JERRY_ASSERT( mem_pools[ i ] == NULL );
JERRY_ASSERT( mem_free_chunks_number[ i ] == 0 );
}
JERRY_ASSERT( mem_pool_for_pool_headers.chunks_number == mem_pool_for_pool_headers.free_chunks_number );
__memset( &mem_pool_for_pool_headers, 0, sizeof(mem_pool_for_pool_headers));
mem_heap_free_block( mem_space_for_pool_for_pool_headers);
mem_space_for_pool_for_pool_headers = NULL;
} /* mem_pools_finalize */
/**
* Allocate a chunk of specified size
*
* @return pointer to allocated chunk, if allocation was successful,
* or NULL - if not enough memory.
*/
uint8_t*
mem_pools_alloc( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
size_t chunk_size = mem_get_chunk_size( chunk_type);
/**
* If there are no free chunks, allocate new pool.
*/
if ( mem_free_chunks_number[ chunk_type ] == 0 )
{
mem_pool_state_t *pool_state = (mem_pool_state_t*) mem_pool_alloc_chunk( &mem_pool_for_pool_headers);
if ( pool_state == NULL )
{
/**
* Not enough space for new pool' header.
*/
return NULL;
}
/**
* Space, at least for eight chunks and a bitmap entry.
*
* TODO: Research.
*/
size_t pool_space_size = mem_heap_recommend_allocation_size( 8 * chunk_size + sizeof (mword_t) );
uint8_t *pool_space = mem_heap_alloc_block( pool_space_size,
MEM_HEAP_ALLOC_LONG_TERM);
if ( pool_space == NULL )
{
/**
* Not enough memory. Freeing pool header that was allocated above.
*/
mem_pool_free_chunk( &mem_pool_for_pool_headers, (uint8_t*) pool_state);
return NULL;
}
mem_pool_init( pool_state,
chunk_size,
pool_space,
pool_space_size);
pool_state->next_pool_p = mem_pools[ chunk_type ];
mem_pools[ chunk_type ] = pool_state;
mem_free_chunks_number[ chunk_type ] += pool_state->free_chunks_number;
mem_pools_stat_alloc_pool( chunk_type);
}
/**
* Now there is definitely at least one pool of specified type with at least one free chunk.
*
* Search for the pool.
*/
mem_pool_state_t *pool_state = mem_pools[ chunk_type ];
while ( pool_state->free_chunks_number == 0 )
{
pool_state = pool_state->next_pool_p;
JERRY_ASSERT( pool_state != NULL );
}
/**
* And allocate chunk within it.
*/
mem_free_chunks_number[ chunk_type ]--;
mem_pools_stat_alloc_chunk( chunk_type);
return mem_pool_alloc_chunk( pool_state);
} /* mem_pools_alloc */
/**
* Free the chunk
*/
void
mem_pools_free(mem_pool_chunk_type_t chunk_type, /**< the chunk type */
uint8_t *chunk_p) /**< pointer to the chunk */
{
mem_pool_state_t *pool_state = mem_pools[ chunk_type ], *prev_pool_state = NULL;
/**
* Search for the pool containing specified chunk.
*/
while ( !( chunk_p >= pool_state->pool_start_p
&& chunk_p <= pool_state->pool_start_p + pool_state->pool_size ) )
{
prev_pool_state = pool_state;
pool_state = pool_state->next_pool_p;
JERRY_ASSERT( pool_state != NULL );
}
/**
* Free the chunk
*/
mem_pool_free_chunk( pool_state, chunk_p);
mem_free_chunks_number[ chunk_type ]++;
mem_pools_stat_free_chunk( chunk_type);
/**
* If all chunks of the pool are free, free the pool itself.
*/
if ( pool_state->free_chunks_number == pool_state->chunks_number )
{
if ( prev_pool_state != NULL )
{
prev_pool_state->next_pool_p = pool_state->next_pool_p;
} else
{
mem_pools[ chunk_type ] = pool_state->next_pool_p;
}
mem_free_chunks_number[ chunk_type ] -= pool_state->chunks_number;
mem_heap_free_block( pool_state->pool_start_p);
mem_pool_free_chunk( &mem_pool_for_pool_headers, (uint8_t*) pool_state);
mem_pools_stat_free_pool( chunk_type);
}
} /* mem_pools_free */
#ifdef MEM_STATS
/**
* Get pools memory usage statistics
*/
void
mem_pools_get_stats( mem_pools_stats_t *out_pools_stats_p) /**< out: pools' stats */
{
JERRY_ASSERT( out_pools_stats_p != NULL );
*out_pools_stats_p = mem_pools_stats;
} /* mem_pools_get_stats */
/**
* Initalize pools' memory usage statistics account structure
*/
static void
mem_pools_stat_init( void)
{
__memset( &mem_pools_stats, 0, sizeof (mem_pools_stats));
} /* mem_pools_stat_init */
/**
* Account allocation of a pool
*/
static void
mem_pools_stat_alloc_pool( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
mem_pools_stats.pools_count[ chunk_type ]++;
mem_pools_stats.free_chunks[ chunk_type ] = mem_free_chunks_number[ chunk_type ];
if ( mem_pools_stats.pools_count[ chunk_type ] > mem_pools_stats.peak_pools_count[ chunk_type ] )
{
mem_pools_stats.peak_pools_count[ chunk_type ] = mem_pools_stats.pools_count[ chunk_type ];
}
} /* mem_pools_stat_alloc_pool */
/**
* Account freeing of a pool
*/
static void
mem_pools_stat_free_pool( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
JERRY_ASSERT( mem_pools_stats.pools_count[ chunk_type ] > 0 );
mem_pools_stats.pools_count[ chunk_type ]--;
mem_pools_stats.free_chunks[ chunk_type ] = mem_free_chunks_number[ chunk_type ];
} /* mem_pools_stat_free_pool */
/**
* Account allocation of chunk in a pool
*/
static void
mem_pools_stat_alloc_chunk( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
JERRY_ASSERT( mem_pools_stats.free_chunks[ chunk_type ] > 0 );
mem_pools_stats.allocated_chunks[ chunk_type ]++;
mem_pools_stats.free_chunks[ chunk_type ]--;
if ( mem_pools_stats.allocated_chunks[ chunk_type ] > mem_pools_stats.peak_allocated_chunks[ chunk_type ] )
{
mem_pools_stats.peak_allocated_chunks[ chunk_type ] = mem_pools_stats.allocated_chunks[ chunk_type ];
}
} /* mem_pools_stat_alloc_chunk */
/**
* Account freeing of chunk in a pool
*/
static void
mem_pools_stat_free_chunk( mem_pool_chunk_type_t chunk_type) /**< chunk type */
{
JERRY_ASSERT( mem_pools_stats.allocated_chunks[ chunk_type ] > 0 );
mem_pools_stats.allocated_chunks[ chunk_type ]--;
mem_pools_stats.free_chunks[ chunk_type ]++;
} /* mem_pools_stat_free_chunk */
#endif /* MEM_STATS */
/**
* @}
*/
/**
* @}
*/