-/*
- * mlt_pool.c -- memory pooling functionality
- * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
- * Author: Charles Yates <charles.yates@pandora.be>
+/**
+ * \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 <charles.yates@pandora.be>
*
- * 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"
#include <malloc.h>
#endif
-/** Singleton repositories
-*/
+/** 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;
- int count;
+ 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;
-typedef struct mlt_release_s
+/** \brief private to mlt_pool_s, for tracking items to release
+ *
+ * Aligned to 16 byte in case we toss buffers to external assembly
+ * optimized libraries (sse/altivec).
+ */
+
+typedef struct __attribute__ ((aligned (16))) mlt_release_s
{
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 )
{
// Create the pool
- mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
+ mlt_pool self = calloc( 1, sizeof( struct mlt_pool_s ) );
// Initialise it
- if ( this != NULL )
+ if ( self != NULL )
{
// Initialise the mutex
- pthread_mutex_init( &this->lock, NULL );
+ pthread_mutex_init( &self->lock, NULL );
// Create the stack
- this->stack = mlt_deque_init( );
+ self->stack = mlt_deque_init( );
// Assign the size
- this->size = size;
+ self->size = size;
}
// Return it
- return this;
+ return self;
}
/** Get an item from the pool.
-*/
+ *
+ * \private \memberof mlt_pool_s
+ * \param self a pool
+ * \return an opaque pointer
+ */
-static void *pool_fetch( mlt_pool this )
+static void *pool_fetch( mlt_pool self )
{
// We will generate a release object
void *ptr = NULL;
// Sanity check
- if ( this != NULL )
+ if ( self != NULL )
{
// Lock the pool
- pthread_mutex_lock( &this->lock );
+ pthread_mutex_lock( &self->lock );
// Check if the stack is empty
- if ( mlt_deque_count( this->stack ) != 0 )
+ if ( mlt_deque_count( self->stack ) != 0 )
{
// Pop the top of the stack
- ptr = mlt_deque_pop_back( this->stack );
+ ptr = mlt_deque_pop_back( self->stack );
// Assign the reference
( ( mlt_release )ptr )->references = 1;
{
// We need to generate a release item
#ifdef linux
- mlt_release release = memalign( 16, this->size );
+ mlt_release release = memalign( 16, self->size );
#else
- mlt_release release = malloc( this->size );
+ mlt_release release = malloc( self->size );
#endif
// Initialise it
if ( release != NULL )
{
// Increment the number of items allocated to this pool
- this->count ++;
+ self->count ++;
// Assign the pool
- release->pool = this;
+ release->pool = self;
// Assign the reference
release->references = 1;
// Determine the ptr
- ptr = ( void * )release + sizeof( struct mlt_release_s );
+ ptr = ( char * )release + sizeof( struct mlt_release_s );
}
}
// Unlock the pool
- pthread_mutex_unlock( &this->lock );
+ pthread_mutex_unlock( &self->lock );
}
// Return the generated release object
}
/** Return an item to the pool.
-*/
+ *
+ * \private \memberof mlt_pool_s
+ * \param ptr an opaque pointer
+ */
static void pool_return( void *ptr )
{
if ( ptr != NULL )
{
// Get the release pointer
- mlt_release that = ptr - sizeof( struct mlt_release_s );
+ mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s ));
// Get the pool
- mlt_pool this = that->pool;
+ mlt_pool self = that->pool;
- if ( this != NULL )
+ if ( self != NULL )
{
// Lock the pool
- pthread_mutex_lock( &this->lock );
+ pthread_mutex_lock( &self->lock );
// Push the that back back on to the stack
- mlt_deque_push_back( this->stack, ptr );
+ mlt_deque_push_back( self->stack, ptr );
// Unlock the pool
- pthread_mutex_unlock( &this->lock );
+ pthread_mutex_unlock( &self->lock );
// Ensure that we don't clean up
ptr = NULL;
if ( ptr != NULL )
{
// Free the release itself
- free( ptr - sizeof( struct mlt_release_s ) );
+ free( ( char * )ptr - sizeof( struct mlt_release_s ) );
}
}
/** Destroy a pool.
-*/
+ *
+ * \private \memberof mlt_pool_s
+ * \param self a pool
+ */
-static void pool_close( mlt_pool this )
+static void pool_close( mlt_pool self )
{
- if ( this != NULL )
+ if ( self != NULL )
{
// We need to free up all items in the pool
void *release = NULL;
// Iterate through the stack until depleted
- while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
+ while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL )
{
// We'll free this item now
- free( release - sizeof( struct mlt_release_s ) );
+ free( ( char * )release - sizeof( struct mlt_release_s ) );
}
// We can now close the stack
- mlt_deque_close( this->stack );
+ mlt_deque_close( self->stack );
// Destroy the mutex
- pthread_mutex_destroy( &this->lock );
+ pthread_mutex_destroy( &self->lock );
// Close the pool
- free( this );
+ free( self );
}
}
-/** Initialise the pool.
-*/
+/** Initialise the global pool.
+ *
+ * \public \memberof mlt_pool_s
+ */
void mlt_pool_init( )
{
}
/** Allocate size bytes from the pool.
-*/
+ *
+ * \public \memberof mlt_pool_s
+ * \param size the number of bytes
+ */
void *mlt_pool_alloc( int size )
{
int index = 8;
// Minimum size pooled is 256 bytes
- size = size + sizeof( mlt_release );
+ size += sizeof( struct mlt_release_s );
while ( ( 1 << index ) < size )
index ++;
}
/** 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 )
{
if ( ptr != NULL )
{
// Get the release pointer
- mlt_release that = ptr - sizeof( struct mlt_release_s );
+ mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s ));
// If the current pool this ptr belongs to is big enough
if ( size > that->pool->size - sizeof( struct mlt_release_s ) )
}
/** Purge unused items in the pool.
-*/
+ *
+ * A form of garbage collection.
+ * \public \memberof mlt_pool_s
+ */
void mlt_pool_purge( )
{
for ( i = 0; i < mlt_properties_count( pools ); i ++ )
{
// Get the pool
- mlt_pool this = mlt_properties_get_data_at( pools, i, NULL );
+ mlt_pool self = mlt_properties_get_data_at( pools, i, NULL );
// Pointer to unused memory
void *release = NULL;
// Lock the pool
- pthread_mutex_lock( &this->lock );
+ pthread_mutex_lock( &self->lock );
// We'll free all unused items now
- while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
- free( release - sizeof( struct mlt_release_s ) );
+ while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL )
+ free( ( char * )release - sizeof( struct mlt_release_s ) );
// Unlock the pool
- pthread_mutex_unlock( &this->lock );
+ pthread_mutex_unlock( &self->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 )
{
}
/** Close the pool.
-*/
+ *
+ * \public \memberof mlt_pool_s
+ */
void mlt_pool_close( )
{
#ifdef _MLT_POOL_CHECKS_
// Stats dump on close
int i = 0;
- fprintf( stderr, "Usage:\n\n" );
for ( i = 0; i < mlt_properties_count( pools ); i ++ )
{
mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL );
if ( pool->count )
- fprintf( stderr, "%d: allocated %d returned %d %c\n", pool->size, pool->count, mlt_deque_count( pool->stack ),
- pool->count != mlt_deque_count( pool->stack ) ? '*' : ' ' );
+ 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