#include <string.h>
#include <pthread.h>
+// Not nice - memalign is defined here apparently?
+#ifdef linux
+#include <malloc.h>
+#endif
+
/** Singleton repositories
*/
pthread_mutex_t lock;
mlt_deque stack;
int size;
+ int count;
}
*mlt_pool;
-/** Private release structure
-*/
-
typedef struct mlt_release_s
{
- void *ptr;
mlt_pool pool;
+ int references;
}
*mlt_release;
/** Get an item from the pool.
*/
-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 )
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 );
}
}
}
// Return the generated release object
- return release;
+ return ptr;
}
/** Return an item to the pool.
*/
-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 ) );
}
}
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
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 ];
/** Allocate size bytes from the pool.
*/
-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.
+*/
+
+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 );
+
+ // 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 ) );
- // Return the pointer
- return real->ptr;
+ // 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.
*/
-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;
- // Return to the pool
- pool_return( real->pool, real );
+ // 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 ) );
+
+ // Unlock the pool
+ pthread_mutex_unlock( &this->lock );
}
}
+/** Release the allocated memory.
+*/
+
+void mlt_pool_release( void *release )
+{
+ // Return to the pool
+ pool_return( release );
+}
+
/** Close the pool.
*/
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 ) ? '*' : ' ' );
+ }
+#endif
+
// Close the properties
mlt_properties_close( pools );
}