]> git.sesse.net Git - mlt/blob - src/framework/mlt_pool.c
Add doxygen documentation for mlt_profile, mlt_pool, mlt_repository, and mlt_factory.
[mlt] / src / framework / mlt_pool.c
1 /**
2  * \file mlt_pool.c
3  * \brief memory pooling functionality
4  * \see mlt_pool_s
5  *
6  * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7  * \author Charles Yates <charles.yates@pandora.be>
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "mlt_properties.h"
25 #include "mlt_deque.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <pthread.h>
30
31 // Not nice - memalign is defined here apparently?
32 #ifdef linux
33 #include <malloc.h>
34 #endif
35
36 /** global singleton for tracking pools */
37
38 static mlt_properties pools = NULL;
39
40 /** \brief Pool (memory) class
41  */
42
43 typedef struct mlt_pool_s
44 {
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
49 }
50 *mlt_pool;
51
52 /** \brief private to mlt_pool_s, for tracking items to release
53  */
54
55 typedef struct mlt_release_s
56 {
57         mlt_pool pool;
58         int references;
59 }
60 *mlt_release;
61
62 /** Create a pool.
63  *
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
67  */
68
69 static mlt_pool pool_init( int size )
70 {
71         // Create the pool
72         mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
73
74         // Initialise it
75         if ( this != NULL )
76         {
77                 // Initialise the mutex
78                 pthread_mutex_init( &this->lock, NULL );
79
80                 // Create the stack
81                 this->stack = mlt_deque_init( );
82
83                 // Assign the size
84                 this->size = size;
85         }
86
87         // Return it
88         return this;
89 }
90
91 /** Get an item from the pool.
92  *
93  * \private \memberof mlt_pool_s
94  * \param this a pool
95  * \return an opaque pointer
96  */
97
98 static void *pool_fetch( mlt_pool this )
99 {
100         // We will generate a release object
101         void *ptr = NULL;
102
103         // Sanity check
104         if ( this != NULL )
105         {
106                 // Lock the pool
107                 pthread_mutex_lock( &this->lock );
108
109                 // Check if the stack is empty
110                 if ( mlt_deque_count( this->stack ) != 0 )
111                 {
112                         // Pop the top of the stack
113                         ptr = mlt_deque_pop_back( this->stack );
114
115                         // Assign the reference
116                         ( ( mlt_release )ptr )->references = 1;
117                 }
118                 else
119                 {
120                         // We need to generate a release item
121 #ifdef linux
122                         mlt_release release = memalign( 16, this->size );
123 #else
124                         mlt_release release = malloc( this->size );
125 #endif
126
127                         // Initialise it
128                         if ( release != NULL )
129                         {
130                                 // Increment the number of items allocated to this pool
131                                 this->count ++;
132
133                                 // Assign the pool
134                                 release->pool = this;
135
136                                 // Assign the reference
137                                 release->references = 1;
138
139                                 // Determine the ptr
140                                 ptr = ( void * )release + sizeof( struct mlt_release_s );
141                         }
142                 }
143
144                 // Unlock the pool
145                 pthread_mutex_unlock( &this->lock );
146         }
147
148         // Return the generated release object
149         return ptr;
150 }
151
152 /** Return an item to the pool.
153  *
154  * \private \memberof mlt_pool_s
155  * \param ptr an opaque pointer
156  */
157
158 static void pool_return( void *ptr )
159 {
160         // Sanity checks
161         if ( ptr != NULL )
162         {
163                 // Get the release pointer
164                 mlt_release that = ptr - sizeof( struct mlt_release_s );
165
166                 // Get the pool
167                 mlt_pool this = that->pool;
168
169                 if ( this != NULL )
170                 {
171                         // Lock the pool
172                         pthread_mutex_lock( &this->lock );
173
174                         // Push the that back back on to the stack
175                         mlt_deque_push_back( this->stack, ptr );
176
177                         // Unlock the pool
178                         pthread_mutex_unlock( &this->lock );
179
180                         // Ensure that we don't clean up
181                         ptr = NULL;
182                 }
183         }
184
185         // Tidy up - this will only occur if the returned item is incorrect
186         if ( ptr != NULL )
187         {
188                 // Free the release itself
189                 free( ptr - sizeof( struct mlt_release_s ) );
190         }
191 }
192
193 /** Destroy a pool.
194  *
195  * \private \memberof mlt_pool_s
196  * \param this a pool
197  */
198
199 static void pool_close( mlt_pool this )
200 {
201         if ( this != NULL )
202         {
203                 // We need to free up all items in the pool
204                 void *release = NULL;
205
206                 // Iterate through the stack until depleted
207                 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
208                 {
209                         // We'll free this item now
210                         free( release - sizeof( struct mlt_release_s ) );
211                 }
212
213                 // We can now close the stack
214                 mlt_deque_close( this->stack );
215
216                 // Destroy the mutex
217                 pthread_mutex_destroy( &this->lock );
218
219                 // Close the pool
220                 free( this );
221         }
222 }
223
224 /** Initialise the global pool.
225  *
226  * \public \memberof mlt_pool_s
227  */
228
229 void mlt_pool_init( )
230 {
231         // Loop variable used to create the pools
232         int i = 0;
233
234         // Create the pools
235         pools = mlt_properties_new( );
236
237         // Create the pools
238         for ( i = 8; i < 31; i ++ )
239         {
240                 // Each properties item needs a name
241                 char name[ 32 ];
242
243                 // Construct a pool
244                 mlt_pool pool = pool_init( 1 << i );
245
246                 // Generate a name
247                 sprintf( name, "%d", i );
248
249                 // Register with properties
250                 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
251         }
252 }
253
254 /** Allocate size bytes from the pool.
255  *
256  * \public \memberof mlt_pool_s
257  * \param size the number of bytes
258  */
259
260 void *mlt_pool_alloc( int size )
261 {
262         // This will be used to obtain the pool to use
263         mlt_pool pool = NULL;
264
265         // Determines the index of the pool to use
266         int index = 8;
267
268         // Minimum size pooled is 256 bytes
269         size = size + sizeof( mlt_release );
270         while ( ( 1 << index ) < size )
271                 index ++;
272
273         // Now get the pool at the index
274         pool = mlt_properties_get_data_at( pools, index - 8, NULL );
275
276         // Now get the real item
277         return pool_fetch( pool );
278 }
279
280 /** Allocate size bytes from the pool.
281  *
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
285  */
286
287 void *mlt_pool_realloc( void *ptr, int size )
288 {
289         // Result to return
290         void *result = NULL;
291
292         // Check if we actually have an address
293         if ( ptr != NULL )
294         {
295                 // Get the release pointer
296                 mlt_release that = ptr - sizeof( struct mlt_release_s );
297
298                 // If the current pool this ptr belongs to is big enough
299                 if ( size > that->pool->size - sizeof( struct mlt_release_s ) )
300                 {
301                         // Allocate
302                         result = mlt_pool_alloc( size );
303
304                         // Copy
305                         memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) );
306
307                         // Release
308                         mlt_pool_release( ptr );
309                 }
310                 else
311                 {
312                         // Nothing to do
313                         result = ptr;
314                 }
315         }
316         else
317         {
318                 // Simply allocate
319                 result = mlt_pool_alloc( size );
320         }
321
322         return result;
323 }
324
325 /** Purge unused items in the pool.
326  *
327  * A form of garbage collection.
328  * \public \memberof mlt_pool_s
329  */
330
331 void mlt_pool_purge( )
332 {
333         int i = 0;
334
335         // For each pool
336         for ( i = 0; i < mlt_properties_count( pools ); i ++ )
337         {
338                 // Get the pool
339                 mlt_pool this = mlt_properties_get_data_at( pools, i, NULL );
340
341                 // Pointer to unused memory
342                 void *release = NULL;
343
344                 // Lock the pool
345                 pthread_mutex_lock( &this->lock );
346
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 ) );
350
351                 // Unlock the pool
352                 pthread_mutex_unlock( &this->lock );
353         }
354 }
355
356 /** Release the allocated memory.
357  *
358  * \public \memberof mlt_pool_s
359  * \param release an opaque pointer of a block in the pool
360  */
361
362 void mlt_pool_release( void *release )
363 {
364         // Return to the pool
365         pool_return( release );
366 }
367
368 /** Close the pool.
369  *
370  * \public \memberof mlt_pool_s
371  */
372
373 void mlt_pool_close( )
374 {
375 #ifdef _MLT_POOL_CHECKS_
376         // Stats dump on close
377         int i = 0;
378         for ( i = 0; i < mlt_properties_count( pools ); i ++ )
379         {
380                 mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL );
381                 if ( pool->count )
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 ) ? '*' : ' ' );
385         }
386 #endif
387
388         // Close the properties
389         mlt_properties_close( pools );
390 }
391