X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fframework%2Fmlt_pool.c;h=b708f878272c087e5553420fef3b7d49e4d8e6a9;hb=cbb2f4d4ef7924c05d335768b2e0bfe2da259020;hp=ab51392345fabec8228f3c8a033e3e41fb47e350;hpb=94dce1aea965163f8dcd2f97271f2652abb0e62d;p=melted diff --git a/src/framework/mlt_pool.c b/src/framework/mlt_pool.c index ab51392..b708f87 100644 --- a/src/framework/mlt_pool.c +++ b/src/framework/mlt_pool.c @@ -1,21 +1,24 @@ -/* - * mlt_pool.c -- memory pooling functionality - * Copyright (C) 2003-2004 Ushodaya Enterprises Limited - * Author: Charles Yates +/** + * \file mlt_pool.c + * \brief memory pooling functionality + * \see mlt_pool_s * - * This program 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 of the License, or - * (at your option) any later version. + * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * \author Charles Yates * - * This program is distributed in the hope that it will be useful, + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_properties.h" @@ -25,34 +28,43 @@ #include #include -/** Singleton repositories -*/ +// Not nice - memalign is defined here apparently? +#ifdef linux +#include +#endif + +/** global singleton for tracking pools */ static mlt_properties pools = NULL; -/** Private pooling structure. -*/ +/** \brief Pool (memory) class + */ typedef struct mlt_pool_s { - pthread_mutex_t lock; - mlt_deque stack; - int size; + pthread_mutex_t lock; ///< lock to prevent race conditions + mlt_deque stack; ///< a stack of addresses to memory blocks + int size; ///< the size of the memory block as a power of 2 + int count; ///< the number of blocks in the pool } *mlt_pool; -/** Private release structure -*/ +/** \brief private to mlt_pool_s, for tracking items to release + */ typedef struct mlt_release_s { - void *ptr; mlt_pool pool; + int references; } *mlt_release; /** Create a pool. -*/ + * + * \private \memberof mlt_pool_s + * \param size the size of the memory blocks to hold as some power of two + * \return a new pool object + */ static mlt_pool pool_init( int size ) { @@ -77,12 +89,16 @@ static mlt_pool pool_init( int size ) } /** Get an item from the pool. -*/ + * + * \private \memberof mlt_pool_s + * \param this a pool + * \return an opaque pointer + */ -static mlt_release pool_fetch( mlt_pool this ) +static void *pool_fetch( mlt_pool this ) { // We will generate a release object - mlt_release release = NULL; + void *ptr = NULL; // Sanity check if ( this != NULL ) @@ -94,21 +110,34 @@ static mlt_release pool_fetch( mlt_pool this ) if ( mlt_deque_count( this->stack ) != 0 ) { // Pop the top of the stack - release = mlt_deque_pop_back( this->stack ); + ptr = mlt_deque_pop_back( this->stack ); + + // Assign the reference + ( ( mlt_release )ptr )->references = 1; } else { // We need to generate a release item - release = calloc( 1, sizeof( struct mlt_release_s ) ); +#ifdef linux + mlt_release release = memalign( 16, this->size ); +#else + mlt_release release = malloc( this->size ); +#endif // Initialise it if ( release != NULL ) { - // Allocate the real memory - release->ptr = malloc( this->size ); + // Increment the number of items allocated to this pool + this->count ++; // Assign the pool release->pool = this; + + // Assign the reference + release->references = 1; + + // Determine the ptr + ptr = ( void * )release + sizeof( struct mlt_release_s ); } } @@ -117,60 +146,68 @@ static mlt_release pool_fetch( mlt_pool this ) } // Return the generated release object - return release; + return ptr; } /** Return an item to the pool. -*/ + * + * \private \memberof mlt_pool_s + * \param ptr an opaque pointer + */ -static void pool_return( mlt_pool this, mlt_release that ) +static void pool_return( void *ptr ) { // Sanity checks - if ( this != NULL && that != NULL ) + if ( ptr != NULL ) { - // Ensure that the pools match - if ( this == that->pool ) + // Get the release pointer + mlt_release that = ptr - sizeof( struct mlt_release_s ); + + // Get the pool + mlt_pool this = that->pool; + + if ( this != NULL ) { // Lock the pool pthread_mutex_lock( &this->lock ); // Push the that back back on to the stack - mlt_deque_push_back( this->stack, that ); + mlt_deque_push_back( this->stack, ptr ); // Unlock the pool pthread_mutex_unlock( &this->lock ); // Ensure that we don't clean up - that = NULL; + ptr = NULL; } } // Tidy up - this will only occur if the returned item is incorrect - if ( that != NULL ) + if ( ptr != NULL ) { - // Free the memory - free( that->ptr ); - // Free the release itself - free( that ); + free( ptr - sizeof( struct mlt_release_s ) ); } } /** Destroy a pool. -*/ + * + * \private \memberof mlt_pool_s + * \param this a pool + */ static void pool_close( mlt_pool this ) { if ( this != NULL ) { // We need to free up all items in the pool - mlt_release release = NULL; + void *release = NULL; // Iterate through the stack until depleted while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL ) { - // We'll return this item to NULL - pool_return( NULL, release ); + // We'll free this item now + free( release - sizeof( struct mlt_release_s ) ); } // We can now close the stack @@ -184,8 +221,10 @@ static void pool_close( mlt_pool this ) } } -/** Initialise the pool. -*/ +/** Initialise the global pool. + * + * \public \memberof mlt_pool_s + */ void mlt_pool_init( ) { @@ -196,7 +235,7 @@ void mlt_pool_init( ) pools = mlt_properties_new( ); // Create the pools - for ( i = 8; i < 32; i ++ ) + for ( i = 8; i < 31; i ++ ) { // Each properties item needs a name char name[ 32 ]; @@ -213,65 +252,139 @@ void mlt_pool_init( ) } /** Allocate size bytes from the pool. -*/ + * + * \public \memberof mlt_pool_s + * \param size the number of bytes + */ -void *mlt_pool_allocate( int size, void **release ) +void *mlt_pool_alloc( int size ) { - // This is the real release structure we'll return - mlt_release real = NULL; - // This will be used to obtain the pool to use mlt_pool pool = NULL; // Determines the index of the pool to use - int index = 1; + int index = 8; // Minimum size pooled is 256 bytes - size = size >> 8; + size = size + sizeof( mlt_release ); while ( ( 1 << index ) < size ) index ++; // Now get the pool at the index - pool = mlt_properties_get_data_at( pools, index + 1, NULL ); + pool = mlt_properties_get_data_at( pools, index - 8, NULL ); // Now get the real item - real = pool_fetch( pool ); + return pool_fetch( pool ); +} - // Deal with return - if ( real != NULL ) +/** Allocate size bytes from the pool. + * + * \public \memberof mlt_pool_s + * \param ptr an opaque pointer - can be in the pool or a new block to allocate + * \param size the number of bytes + */ + +void *mlt_pool_realloc( void *ptr, int size ) +{ + // Result to return + void *result = NULL; + + // Check if we actually have an address + if ( ptr != NULL ) { - // Assign to release - *release = real; + // Get the release pointer + mlt_release that = ptr - sizeof( struct mlt_release_s ); - // Return the pointer - return real->ptr; + // If the current pool this ptr belongs to is big enough + if ( size > that->pool->size - sizeof( struct mlt_release_s ) ) + { + // Allocate + result = mlt_pool_alloc( size ); + + // Copy + memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) ); + + // Release + mlt_pool_release( ptr ); + } + else + { + // Nothing to do + result = ptr; + } + } + else + { + // Simply allocate + result = mlt_pool_alloc( size ); } - // Otherwise return a NULL to indicate failure - return NULL; + return result; } -/** Release the allocated memory. -*/ +/** Purge unused items in the pool. + * + * A form of garbage collection. + * \public \memberof mlt_pool_s + */ -void mlt_pool_release( void *release ) +void mlt_pool_purge( ) { - // Sanity check - if ( release != NULL ) + int i = 0; + + // For each pool + for ( i = 0; i < mlt_properties_count( pools ); i ++ ) { - // Get the real release structure - mlt_release real = release; + // Get the pool + mlt_pool this = mlt_properties_get_data_at( pools, i, NULL ); + + // Pointer to unused memory + void *release = NULL; + + // Lock the pool + pthread_mutex_lock( &this->lock ); + + // We'll free all unused items now + while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL ) + free( release - sizeof( struct mlt_release_s ) ); - // Return to the pool - pool_return( real->pool, real ); + // Unlock the pool + pthread_mutex_unlock( &this->lock ); } } +/** Release the allocated memory. + * + * \public \memberof mlt_pool_s + * \param release an opaque pointer of a block in the pool + */ + +void mlt_pool_release( void *release ) +{ + // Return to the pool + pool_return( release ); +} + /** Close the pool. -*/ + * + * \public \memberof mlt_pool_s + */ void mlt_pool_close( ) { +#ifdef _MLT_POOL_CHECKS_ + // Stats dump on close + int i = 0; + for ( i = 0; i < mlt_properties_count( pools ); i ++ ) + { + mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL ); + if ( pool->count ) + mlt_log( NULL, MLT_LOG_DEBUG, "%s: size %d allocated %d returned %d %c\n", __FUNCTION__, + pool->size, pool->count, mlt_deque_count( pool->stack ), + pool->count != mlt_deque_count( pool->stack ) ? '*' : ' ' ); + } +#endif + // Close the properties mlt_properties_close( pools ); }