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
55 typedef struct mlt_release_s
64 * \private \memberof mlt_pool_s
65 * \param size the size of the memory blocks to hold as some power of two
66 * \return a new pool object
69 static mlt_pool
pool_init( int size
)
72 mlt_pool
this = calloc( 1, sizeof( struct mlt_pool_s
) );
77 // Initialise the mutex
78 pthread_mutex_init( &this->lock
, NULL
);
81 this->stack
= mlt_deque_init( );
91 /** Get an item from the pool.
93 * \private \memberof mlt_pool_s
95 * \return an opaque pointer
98 static void *pool_fetch( mlt_pool
this )
100 // We will generate a release object
107 pthread_mutex_lock( &this->lock
);
109 // Check if the stack is empty
110 if ( mlt_deque_count( this->stack
) != 0 )
112 // Pop the top of the stack
113 ptr
= mlt_deque_pop_back( this->stack
);
115 // Assign the reference
116 ( ( mlt_release
)ptr
)->references
= 1;
120 // We need to generate a release item
122 mlt_release release
= memalign( 16, this->size
);
124 mlt_release release
= malloc( this->size
);
128 if ( release
!= NULL
)
130 // Increment the number of items allocated to this pool
134 release
->pool
= this;
136 // Assign the reference
137 release
->references
= 1;
140 ptr
= ( void * )release
+ sizeof( struct mlt_release_s
);
145 pthread_mutex_unlock( &this->lock
);
148 // Return the generated release object
152 /** Return an item to the pool.
154 * \private \memberof mlt_pool_s
155 * \param ptr an opaque pointer
158 static void pool_return( void *ptr
)
163 // Get the release pointer
164 mlt_release that
= ptr
- sizeof( struct mlt_release_s
);
167 mlt_pool
this = that
->pool
;
172 pthread_mutex_lock( &this->lock
);
174 // Push the that back back on to the stack
175 mlt_deque_push_back( this->stack
, ptr
);
178 pthread_mutex_unlock( &this->lock
);
180 // Ensure that we don't clean up
185 // Tidy up - this will only occur if the returned item is incorrect
188 // Free the release itself
189 free( ptr
- sizeof( struct mlt_release_s
) );
195 * \private \memberof mlt_pool_s
199 static void pool_close( mlt_pool
this )
203 // We need to free up all items in the pool
204 void *release
= NULL
;
206 // Iterate through the stack until depleted
207 while ( ( release
= mlt_deque_pop_back( this->stack
) ) != NULL
)
209 // We'll free this item now
210 free( release
- sizeof( struct mlt_release_s
) );
213 // We can now close the stack
214 mlt_deque_close( this->stack
);
217 pthread_mutex_destroy( &this->lock
);
224 /** Initialise the global pool.
226 * \public \memberof mlt_pool_s
229 void mlt_pool_init( )
231 // Loop variable used to create the pools
235 pools
= mlt_properties_new( );
238 for ( i
= 8; i
< 31; i
++ )
240 // Each properties item needs a name
244 mlt_pool pool
= pool_init( 1 << i
);
247 sprintf( name
, "%d", i
);
249 // Register with properties
250 mlt_properties_set_data( pools
, name
, pool
, 0, ( mlt_destructor
)pool_close
, NULL
);
254 /** Allocate size bytes from the pool.
256 * \public \memberof mlt_pool_s
257 * \param size the number of bytes
260 void *mlt_pool_alloc( int size
)
262 // This will be used to obtain the pool to use
263 mlt_pool pool
= NULL
;
265 // Determines the index of the pool to use
268 // Minimum size pooled is 256 bytes
269 size
= size
+ sizeof( mlt_release
);
270 while ( ( 1 << index
) < size
)
273 // Now get the pool at the index
274 pool
= mlt_properties_get_data_at( pools
, index
- 8, NULL
);
276 // Now get the real item
277 return pool_fetch( pool
);
280 /** Allocate size bytes from the pool.
282 * \public \memberof mlt_pool_s
283 * \param ptr an opaque pointer - can be in the pool or a new block to allocate
284 * \param size the number of bytes
287 void *mlt_pool_realloc( void *ptr
, int size
)
292 // Check if we actually have an address
295 // Get the release pointer
296 mlt_release that
= ptr
- sizeof( struct mlt_release_s
);
298 // If the current pool this ptr belongs to is big enough
299 if ( size
> that
->pool
->size
- sizeof( struct mlt_release_s
) )
302 result
= mlt_pool_alloc( size
);
305 memcpy( result
, ptr
, that
->pool
->size
- sizeof( struct mlt_release_s
) );
308 mlt_pool_release( ptr
);
319 result
= mlt_pool_alloc( size
);
325 /** Purge unused items in the pool.
327 * A form of garbage collection.
328 * \public \memberof mlt_pool_s
331 void mlt_pool_purge( )
336 for ( i
= 0; i
< mlt_properties_count( pools
); i
++ )
339 mlt_pool
this = mlt_properties_get_data_at( pools
, i
, NULL
);
341 // Pointer to unused memory
342 void *release
= NULL
;
345 pthread_mutex_lock( &this->lock
);
347 // We'll free all unused items now
348 while ( ( release
= mlt_deque_pop_back( this->stack
) ) != NULL
)
349 free( release
- sizeof( struct mlt_release_s
) );
352 pthread_mutex_unlock( &this->lock
);
356 /** Release the allocated memory.
358 * \public \memberof mlt_pool_s
359 * \param release an opaque pointer of a block in the pool
362 void mlt_pool_release( void *release
)
364 // Return to the pool
365 pool_return( release
);
370 * \public \memberof mlt_pool_s
373 void mlt_pool_close( )
375 #ifdef _MLT_POOL_CHECKS_
376 // Stats dump on close
378 for ( i
= 0; i
< mlt_properties_count( pools
); i
++ )
380 mlt_pool pool
= mlt_properties_get_data_at( pools
, i
, NULL
);
382 mlt_log( NULL
, MLT_LOG_DEBUG
, "%s: size %d allocated %d returned %d %c\n", __FUNCTION__
,
383 pool
->size
, pool
->count
, mlt_deque_count( pool
->stack
),
384 pool
->count
!= mlt_deque_count( pool
->stack
) ?
'*' : ' ' );
388 // Close the properties
389 mlt_properties_close( pools
);