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