mlt_log.[hc], mlt_transition.c, mlt_tractor.c, mlt_repository.c, mlt_properties.c,
[melted] / 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