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