3 * \brief memory pooling functionality
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mlt_properties.h"
25 #include "mlt_deque.h"
31 // Not nice - memalign is defined here apparently?
36 /** global singleton for tracking pools */
38 static mlt_properties pools = NULL;
40 /** \brief Pool (memory) class
43 typedef struct mlt_pool_s
45 pthread_mutex_t lock; ///< lock to prevent race conditions
46 mlt_deque stack; ///< a stack of addresses to memory blocks
47 int size; ///< the size of the memory block as a power of 2
48 int count; ///< the number of blocks in the pool
52 /** \brief private to mlt_pool_s, for tracking items to release
54 * Aligned to 16 byte in case we toss buffers to external assembly
55 * optimized libraries (sse/altivec).
58 typedef struct __attribute__ ((aligned (16))) mlt_release_s
67 * \private \memberof mlt_pool_s
68 * \param size the size of the memory blocks to hold as some power of two
69 * \return a new pool object
72 static mlt_pool pool_init( int size )
75 mlt_pool self = calloc( 1, sizeof( struct mlt_pool_s ) );
80 // Initialise the mutex
81 pthread_mutex_init( &self->lock, NULL );
84 self->stack = mlt_deque_init( );
94 /** Get an item from the pool.
96 * \private \memberof mlt_pool_s
98 * \return an opaque pointer
101 static void *pool_fetch( mlt_pool self )
103 // We will generate a release object
110 pthread_mutex_lock( &self->lock );
112 // Check if the stack is empty
113 if ( mlt_deque_count( self->stack ) != 0 )
115 // Pop the top of the stack
116 ptr = mlt_deque_pop_back( self->stack );
118 // Assign the reference
119 ( ( mlt_release )ptr )->references = 1;
123 // We need to generate a release item
125 mlt_release release = memalign( 16, self->size );
127 mlt_release release = malloc( self->size );
131 if ( release != NULL )
133 // Increment the number of items allocated to this pool
137 release->pool = self;
139 // Assign the reference
140 release->references = 1;
143 ptr = ( char * )release + sizeof( struct mlt_release_s );
148 pthread_mutex_unlock( &self->lock );
151 // Return the generated release object
155 /** Return an item to the pool.
157 * \private \memberof mlt_pool_s
158 * \param ptr an opaque pointer
161 static void pool_return( void *ptr )
166 // Get the release pointer
167 mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s ));
170 mlt_pool self = that->pool;
175 pthread_mutex_lock( &self->lock );
177 // Push the that back back on to the stack
178 mlt_deque_push_back( self->stack, ptr );
181 pthread_mutex_unlock( &self->lock );
183 // Ensure that we don't clean up
188 // Tidy up - this will only occur if the returned item is incorrect
191 // Free the release itself
192 free( ( char * )ptr - sizeof( struct mlt_release_s ) );
198 * \private \memberof mlt_pool_s
202 static void pool_close( mlt_pool self )
206 // We need to free up all items in the pool
207 void *release = NULL;
209 // Iterate through the stack until depleted
210 while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL )
212 // We'll free this item now
213 free( ( char * )release - sizeof( struct mlt_release_s ) );
216 // We can now close the stack
217 mlt_deque_close( self->stack );
220 pthread_mutex_destroy( &self->lock );
227 /** Initialise the global pool.
229 * \public \memberof mlt_pool_s
232 void mlt_pool_init( )
234 // Loop variable used to create the pools
238 pools = mlt_properties_new( );
241 for ( i = 8; i < 31; i ++ )
243 // Each properties item needs a name
247 mlt_pool pool = pool_init( 1 << i );
250 sprintf( name, "%d", i );
252 // Register with properties
253 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
257 /** Allocate size bytes from the pool.
259 * \public \memberof mlt_pool_s
260 * \param size the number of bytes
263 void *mlt_pool_alloc( int size )
265 // This will be used to obtain the pool to use
266 mlt_pool pool = NULL;
268 // Determines the index of the pool to use
271 // Minimum size pooled is 256 bytes
272 size += sizeof( struct mlt_release_s );
273 while ( ( 1 << index ) < size )
276 // Now get the pool at the index
277 pool = mlt_properties_get_data_at( pools, index - 8, NULL );
279 // Now get the real item
280 return pool_fetch( pool );
283 /** Allocate size bytes from the pool.
285 * \public \memberof mlt_pool_s
286 * \param ptr an opaque pointer - can be in the pool or a new block to allocate
287 * \param size the number of bytes
290 void *mlt_pool_realloc( void *ptr, int size )
295 // Check if we actually have an address
298 // Get the release pointer
299 mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s ));
301 // If the current pool this ptr belongs to is big enough
302 if ( size > that->pool->size - sizeof( struct mlt_release_s ) )
305 result = mlt_pool_alloc( size );
308 memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) );
311 mlt_pool_release( ptr );
322 result = mlt_pool_alloc( size );
328 /** Purge unused items in the pool.
330 * A form of garbage collection.
331 * \public \memberof mlt_pool_s
334 void mlt_pool_purge( )
339 for ( i = 0; i < mlt_properties_count( pools ); i ++ )
342 mlt_pool self = mlt_properties_get_data_at( pools, i, NULL );
344 // Pointer to unused memory
345 void *release = NULL;
348 pthread_mutex_lock( &self->lock );
350 // We'll free all unused items now
351 while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL )
352 free( ( char * )release - sizeof( struct mlt_release_s ) );
355 pthread_mutex_unlock( &self->lock );
359 /** Release the allocated memory.
361 * \public \memberof mlt_pool_s
362 * \param release an opaque pointer of a block in the pool
365 void mlt_pool_release( void *release )
367 // Return to the pool
368 pool_return( release );
373 * \public \memberof mlt_pool_s
376 void mlt_pool_close( )
378 #ifdef _MLT_POOL_CHECKS_
379 // Stats dump on close
381 for ( i = 0; i < mlt_properties_count( pools ); i ++ )
383 mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL );
385 mlt_log( NULL, MLT_LOG_DEBUG, "%s: size %d allocated %d returned %d %c\n", __FUNCTION__,
386 pool->size, pool->count, mlt_deque_count( pool->stack ),
387 pool->count != mlt_deque_count( pool->stack ) ? '*' : ' ' );
391 // Close the properties
392 mlt_properties_close( pools );