mlt_log.[hc], mlt_transition.c, mlt_tractor.c, mlt_repository.c, mlt_properties.c,
[melted] / src / framework / mlt_pool.c
index ab51392..e4d47dd 100644 (file)
@@ -1,21 +1,23 @@
-/*
- * 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
  *
- * 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-2008 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 <string.h>
 #include <pthread.h>
 
+// Not nice - memalign is defined here apparently?
+#ifdef linux
+#include <malloc.h>
+#endif
+
 /** Singleton repositories
 */
 
 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;
 }
 *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;
 
@@ -79,10 +87,10 @@ static mlt_pool pool_init( int size )
 /** 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 )
@@ -94,21 +102,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,42 +138,44 @@ static mlt_release pool_fetch( mlt_pool this )
        }
 
        // 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 ) );
        }
 }
 
@@ -164,13 +187,13 @@ 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
@@ -196,7 +219,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 ];
@@ -215,63 +238,122 @@ void mlt_pool_init( )
 /** 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 );
+}
+
+/** Allocate size bytes from the pool.
+*/
 
-       // Deal with return
-       if ( real != NULL )
+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.
 */
 
-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.
+*/
+
+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;
+       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 );
 }