]> git.sesse.net Git - mlt/blob - src/framework/mlt_pool.c
e4d47dd40392ee31d28d8f20d1b9c7ec278be4ce
[mlt] / src / framework / mlt_pool.c
1 /**
2  * \file mlt_pool.c
3  * \brief memory pooling functionality
4  *
5  * Copyright (C) 2003-2008 Ushodaya Enterprises Limited
6  * \author Charles Yates <charles.yates@pandora.be>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "mlt_properties.h"
24 #include "mlt_deque.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <pthread.h>
29
30 // Not nice - memalign is defined here apparently?
31 #ifdef linux
32 #include <malloc.h>
33 #endif
34
35 /** Singleton repositories
36 */
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;
46         mlt_deque stack;
47         int size;
48         int count;
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
65 static mlt_pool pool_init( int size )
66 {
67         // Create the pool
68         mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
69
70         // Initialise it
71         if ( this != NULL )
72         {
73                 // Initialise the mutex
74                 pthread_mutex_init( &this->lock, NULL );
75
76                 // Create the stack
77                 this->stack = mlt_deque_init( );
78
79                 // Assign the size
80                 this->size = size;
81         }
82
83         // Return it
84         return this;
85 }
86
87 /** Get an item from the pool.
88 */
89
90 static void *pool_fetch( mlt_pool this )
91 {
92         // We will generate a release object
93         void *ptr = NULL;
94
95         // Sanity check
96         if ( this != NULL )
97         {
98                 // Lock the pool
99                 pthread_mutex_lock( &this->lock );
100
101                 // Check if the stack is empty
102                 if ( mlt_deque_count( this->stack ) != 0 )
103                 {
104                         // Pop the top of the stack
105                         ptr = mlt_deque_pop_back( this->stack );
106
107                         // Assign the reference
108                         ( ( mlt_release )ptr )->references = 1;
109                 }
110                 else
111                 {
112                         // We need to generate a release item
113 #ifdef linux
114                         mlt_release release = memalign( 16, this->size );
115 #else
116                         mlt_release release = malloc( this->size );
117 #endif
118
119                         // Initialise it
120                         if ( release != NULL )
121                         {
122                                 // Increment the number of items allocated to this pool
123                                 this->count ++;
124
125                                 // Assign the pool
126                                 release->pool = this;
127
128                                 // Assign the reference
129                                 release->references = 1;
130
131                                 // Determine the ptr
132                                 ptr = ( void * )release + sizeof( struct mlt_release_s );
133                         }
134                 }
135
136                 // Unlock the pool
137                 pthread_mutex_unlock( &this->lock );
138         }
139
140         // Return the generated release object
141         return ptr;
142 }
143
144 /** Return an item to the pool.
145 */
146
147 static void pool_return( void *ptr )
148 {
149         // Sanity checks
150         if ( ptr != NULL )
151         {
152                 // Get the release pointer
153                 mlt_release that = ptr - sizeof( struct mlt_release_s );
154
155                 // Get the pool
156                 mlt_pool this = that->pool;
157
158                 if ( this != NULL )
159                 {
160                         // Lock the pool
161                         pthread_mutex_lock( &this->lock );
162
163                         // Push the that back back on to the stack
164                         mlt_deque_push_back( this->stack, ptr );
165
166                         // Unlock the pool
167                         pthread_mutex_unlock( &this->lock );
168
169                         // Ensure that we don't clean up
170                         ptr = NULL;
171                 }
172         }
173
174         // Tidy up - this will only occur if the returned item is incorrect
175         if ( ptr != NULL )
176         {
177                 // Free the release itself
178                 free( ptr - sizeof( struct mlt_release_s ) );
179         }
180 }
181
182 /** Destroy a pool.
183 */
184
185 static void pool_close( mlt_pool this )
186 {
187         if ( this != NULL )
188         {
189                 // We need to free up all items in the pool
190                 void *release = NULL;
191
192                 // Iterate through the stack until depleted
193                 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
194                 {
195                         // We'll free this item now
196                         free( release - sizeof( struct mlt_release_s ) );
197                 }
198
199                 // We can now close the stack
200                 mlt_deque_close( this->stack );
201
202                 // Destroy the mutex
203                 pthread_mutex_destroy( &this->lock );
204
205                 // Close the pool
206                 free( this );
207         }
208 }
209
210 /** Initialise the pool.
211 */
212
213 void mlt_pool_init( )
214 {
215         // Loop variable used to create the pools
216         int i = 0;
217
218         // Create the pools
219         pools = mlt_properties_new( );
220
221         // Create the pools
222         for ( i = 8; i < 31; i ++ )
223         {
224                 // Each properties item needs a name
225                 char name[ 32 ];
226
227                 // Construct a pool
228                 mlt_pool pool = pool_init( 1 << i );
229
230                 // Generate a name
231                 sprintf( name, "%d", i );
232
233                 // Register with properties
234                 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
235         }
236 }
237
238 /** Allocate size bytes from the pool.
239 */
240
241 void *mlt_pool_alloc( int size )
242 {
243         // This will be used to obtain the pool to use
244         mlt_pool pool = NULL;
245
246         // Determines the index of the pool to use
247         int index = 8;
248
249         // Minimum size pooled is 256 bytes
250         size = size + sizeof( mlt_release );
251         while ( ( 1 << index ) < size )
252                 index ++;
253
254         // Now get the pool at the index
255         pool = mlt_properties_get_data_at( pools, index - 8, NULL );
256
257         // Now get the real item
258         return pool_fetch( pool );
259 }
260
261 /** Allocate size bytes from the pool.
262 */
263
264 void *mlt_pool_realloc( void *ptr, int size )
265 {
266         // Result to return
267         void *result = NULL;
268
269         // Check if we actually have an address
270         if ( ptr != NULL )
271         {
272                 // Get the release pointer
273                 mlt_release that = ptr - sizeof( struct mlt_release_s );
274
275                 // If the current pool this ptr belongs to is big enough
276                 if ( size > that->pool->size - sizeof( struct mlt_release_s ) )
277                 {
278                         // Allocate
279                         result = mlt_pool_alloc( size );
280
281                         // Copy
282                         memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) );
283
284                         // Release
285                         mlt_pool_release( ptr );
286                 }
287                 else
288                 {
289                         // Nothing to do
290                         result = ptr;
291                 }
292         }
293         else
294         {
295                 // Simply allocate
296                 result = mlt_pool_alloc( size );
297         }
298
299         return result;
300 }
301
302 /** Purge unused items in the pool.
303 */
304
305 void mlt_pool_purge( )
306 {
307         int i = 0;
308
309         // For each pool
310         for ( i = 0; i < mlt_properties_count( pools ); i ++ )
311         {
312                 // Get the pool
313                 mlt_pool this = mlt_properties_get_data_at( pools, i, NULL );
314
315                 // Pointer to unused memory
316                 void *release = NULL;
317
318                 // Lock the pool
319                 pthread_mutex_lock( &this->lock );
320
321                 // We'll free all unused items now
322                 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
323                         free( release - sizeof( struct mlt_release_s ) );
324
325                 // Unlock the pool
326                 pthread_mutex_unlock( &this->lock );
327         }
328 }
329
330 /** Release the allocated memory.
331 */
332
333 void mlt_pool_release( void *release )
334 {
335         // Return to the pool
336         pool_return( release );
337 }
338
339 /** Close the pool.
340 */
341
342 void mlt_pool_close( )
343 {
344 #ifdef _MLT_POOL_CHECKS_
345         // Stats dump on close
346         int i = 0;
347         for ( i = 0; i < mlt_properties_count( pools ); i ++ )
348         {
349                 mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL );
350                 if ( pool->count )
351                         mlt_log( NULL, MLT_LOG_DEBUG, "%s: size %d allocated %d returned %d %c\n", __FUNCTION__,
352                                 pool->size, pool->count, mlt_deque_count( pool->stack ),
353                                 pool->count !=  mlt_deque_count( pool->stack ) ? '*' : ' ' );
354         }
355 #endif
356
357         // Close the properties
358         mlt_properties_close( pools );
359 }
360