2 * mlt_pool.c -- memory pooling functionality
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "mlt_properties.h"
22 #include "mlt_deque.h"
28 // Not nice - memalign is defined here apparently?
33 /** Singleton repositories
36 static mlt_properties pools = NULL;
38 /** Private pooling structure.
41 typedef struct mlt_pool_s
50 typedef struct mlt_release_s
60 static mlt_pool pool_init( int size )
63 mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
68 // Initialise the mutex
69 pthread_mutex_init( &this->lock, NULL );
72 this->stack = mlt_deque_init( );
82 /** Get an item from the pool.
85 static void *pool_fetch( mlt_pool this )
87 // We will generate a release object
94 pthread_mutex_lock( &this->lock );
96 // Check if the stack is empty
97 if ( mlt_deque_count( this->stack ) != 0 )
99 // Pop the top of the stack
100 ptr = mlt_deque_pop_back( this->stack );
102 // Assign the reference
103 ( ( mlt_release )ptr )->references = 1;
107 // We need to generate a release item
109 mlt_release release = memalign( 16, this->size );
111 mlt_release release = malloc( this->size );
115 if ( release != NULL )
117 // Increment the number of items allocated to this pool
121 release->pool = this;
123 // Assign the reference
124 release->references = 1;
127 ptr = ( void * )release + sizeof( struct mlt_release_s );
132 pthread_mutex_unlock( &this->lock );
135 // Return the generated release object
139 /** Return an item to the pool.
142 static void pool_return( void *ptr )
147 // Get the release pointer
148 mlt_release that = ptr - sizeof( struct mlt_release_s );
151 mlt_pool this = that->pool;
156 pthread_mutex_lock( &this->lock );
158 // Push the that back back on to the stack
159 mlt_deque_push_back( this->stack, ptr );
162 pthread_mutex_unlock( &this->lock );
164 // Ensure that we don't clean up
169 // Tidy up - this will only occur if the returned item is incorrect
172 // Free the release itself
173 free( ptr - sizeof( struct mlt_release_s ) );
180 static void pool_close( mlt_pool this )
184 // We need to free up all items in the pool
185 void *release = NULL;
187 // Iterate through the stack until depleted
188 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
190 // We'll free this item now
191 free( release - sizeof( struct mlt_release_s ) );
194 // We can now close the stack
195 mlt_deque_close( this->stack );
198 pthread_mutex_destroy( &this->lock );
205 /** Initialise the pool.
208 void mlt_pool_init( )
210 // Loop variable used to create the pools
214 pools = mlt_properties_new( );
217 for ( i = 8; i < 31; i ++ )
219 // Each properties item needs a name
223 mlt_pool pool = pool_init( 1 << i );
226 sprintf( name, "%d", i );
228 // Register with properties
229 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
233 /** Allocate size bytes from the pool.
236 void *mlt_pool_alloc( int size )
238 // This will be used to obtain the pool to use
239 mlt_pool pool = NULL;
241 // Determines the index of the pool to use
244 // Minimum size pooled is 256 bytes
245 size = size + sizeof( mlt_release );
246 while ( ( 1 << index ) < size )
249 // Now get the pool at the index
250 pool = mlt_properties_get_data_at( pools, index - 8, NULL );
252 // Now get the real item
253 return pool_fetch( pool );
256 /** Allocate size bytes from the pool.
259 void *mlt_pool_realloc( void *ptr, int size )
264 // Check if we actually have an address
267 // Get the release pointer
268 mlt_release that = ptr - sizeof( struct mlt_release_s );
270 // If the current pool this ptr belongs to is big enough
271 if ( size > that->pool->size - sizeof( struct mlt_release_s ) )
274 result = mlt_pool_alloc( size );
277 memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) );
280 mlt_pool_release( ptr );
291 result = mlt_pool_alloc( size );
297 /** Purge unused items in the pool.
300 void mlt_pool_purge( )
305 for ( i = 0; i < mlt_properties_count( pools ); i ++ )
308 mlt_pool this = mlt_properties_get_data_at( pools, i, NULL );
310 // Pointer to unused memory
311 void *release = NULL;
314 pthread_mutex_lock( &this->lock );
316 // We'll free all unused items now
317 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
318 free( release - sizeof( struct mlt_release_s ) );
321 pthread_mutex_unlock( &this->lock );
325 /** Release the allocated memory.
328 void mlt_pool_release( void *release )
330 // Return to the pool
331 pool_return( release );
337 void mlt_pool_close( )
339 #ifdef _MLT_POOL_CHECKS_
340 // Stats dump on close
342 fprintf( stderr, "Usage:\n\n" );
343 for ( i = 0; i < mlt_properties_count( pools ); i ++ )
345 mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL );
347 fprintf( stderr, "%d: allocated %d returned %d %c\n", pool->size, pool->count, mlt_deque_count( pool->stack ),
348 pool->count != mlt_deque_count( pool->stack ) ? '*' : ' ' );
352 // Close the properties
353 mlt_properties_close( pools );