Memory pooling part 2 and other optimisations
[melted] / 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 <string.h>
26 #include <pthread.h>
27
28 /** Singleton repositories
29 */
30
31 static mlt_properties pools = NULL;
32
33 /** Private pooling structure.
34 */
35
36 typedef struct mlt_pool_s
37 {
38 pthread_mutex_t lock;
39 mlt_deque stack;
40 int size;
41 int count;
42 }
43 *mlt_pool;
44
45 typedef struct mlt_release_s
46 {
47 mlt_pool pool;
48 }
49 *mlt_release;
50
51 /** Create a pool.
52 */
53
54 static mlt_pool pool_init( int size )
55 {
56 // Create the pool
57 mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
58
59 // Initialise it
60 if ( this != NULL )
61 {
62 // Initialise the mutex
63 pthread_mutex_init( &this->lock, NULL );
64
65 // Create the stack
66 this->stack = mlt_deque_init( );
67
68 // Assign the size
69 this->size = size;
70 }
71
72 // Return it
73 return this;
74 }
75
76 /** Get an item from the pool.
77 */
78
79 static void *pool_fetch( mlt_pool this )
80 {
81 // We will generate a release object
82 void *ptr = NULL;
83
84 // Sanity check
85 if ( this != NULL )
86 {
87 // Lock the pool
88 pthread_mutex_lock( &this->lock );
89
90 // Check if the stack is empty
91 if ( mlt_deque_count( this->stack ) != 0 )
92 {
93 // Pop the top of the stack
94 ptr = mlt_deque_pop_back( this->stack );
95 }
96 else
97 {
98 // We need to generate a release item
99 mlt_release release = malloc( sizeof( struct mlt_release_s ) + this->size );
100
101 // Initialise it
102 if ( release != NULL )
103 {
104 // Assign the pool
105 release->pool = this;
106
107 // Determine the ptr
108 ptr = ( void * )release + sizeof( struct mlt_release_s );
109 }
110 }
111
112 // Unlock the pool
113 pthread_mutex_unlock( &this->lock );
114 }
115
116 // Return the generated release object
117 return ptr;
118 }
119
120 /** Return an item to the pool.
121 */
122
123 static void pool_return( void *ptr )
124 {
125 // Sanity checks
126 if ( ptr != NULL )
127 {
128 // Get the release pointer
129 mlt_release that = ( void * )ptr - sizeof( struct mlt_release_s );
130
131 // Get the pool
132 mlt_pool this = that->pool;
133
134 if ( this != NULL )
135 {
136 // Lock the pool
137 pthread_mutex_lock( &this->lock );
138
139 // Push the that back back on to the stack
140 mlt_deque_push_back( this->stack, ptr );
141
142 // Unlock the pool
143 pthread_mutex_unlock( &this->lock );
144
145 // Ensure that we don't clean up
146 ptr = NULL;
147 }
148 }
149
150 // Tidy up - this will only occur if the returned item is incorrect
151 if ( ptr != NULL )
152 {
153 // Free the release itself
154 free( ptr - sizeof( struct mlt_release_s ) );
155 }
156 }
157
158 /** Destroy a pool.
159 */
160
161 static void pool_close( mlt_pool this )
162 {
163 if ( this != NULL )
164 {
165 // We need to free up all items in the pool
166 void *release = NULL;
167
168 // Iterate through the stack until depleted
169 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
170 {
171 // We'll free this item now
172 free( release - sizeof( struct mlt_release_s ) );
173 }
174
175 // We can now close the stack
176 mlt_deque_close( this->stack );
177
178 // Destroy the mutex
179 pthread_mutex_destroy( &this->lock );
180
181 // Close the pool
182 free( this );
183 }
184 }
185
186 /** Initialise the pool.
187 */
188
189 void mlt_pool_init( )
190 {
191 // Loop variable used to create the pools
192 int i = 0;
193
194 // Create the pools
195 pools = mlt_properties_new( );
196
197 // Create the pools
198 for ( i = 8; i < 31; i ++ )
199 {
200 // Each properties item needs a name
201 char name[ 32 ];
202
203 // Construct a pool
204 mlt_pool pool = pool_init( 1 << i );
205
206 // Generate a name
207 sprintf( name, "%d", i );
208
209 // Register with properties
210 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
211 }
212 }
213
214 /** Allocate size bytes from the pool.
215 */
216
217 void *mlt_pool_alloc( int size )
218 {
219 // This will be used to obtain the pool to use
220 mlt_pool pool = NULL;
221
222 // Determines the index of the pool to use
223 int index = 0;
224
225 // Minimum size pooled is 256 bytes
226 size = size >> 8;
227 while ( ( 1 << index ) < size )
228 index ++;
229
230 // Now get the pool at the index
231 pool = mlt_properties_get_data_at( pools, index + 1, NULL );
232
233 // Now get the real item
234 return pool_fetch( pool );
235 }
236
237 /** Allocate size bytes from the pool.
238 */
239
240 void *mlt_pool_allocate( int size, void **release )
241 {
242 // This is the real release structure we'll return
243 void *real = NULL;
244
245 // This will be used to obtain the pool to use
246 mlt_pool pool = NULL;
247
248 // Determines the index of the pool to use
249 int index = 0;
250
251 // Minimum size pooled is 256 bytes
252 size = size >> 8;
253 while ( ( 1 << index ) < size )
254 index ++;
255
256 // Now get the pool at the index
257 pool = mlt_properties_get_data_at( pools, index + 1, NULL );
258
259 // Now get the real item
260 real = pool_fetch( pool );
261
262 // Assign to release
263 *release = real;
264
265 // Otherwise return a NULL to indicate failure
266 return real;
267 }
268
269 /** Release the allocated memory.
270 */
271
272 void mlt_pool_release( void *release )
273 {
274 // Return to the pool
275 pool_return( release );
276 }
277
278 /** Close the pool.
279 */
280
281 void mlt_pool_close( )
282 {
283 // Close the properties
284 mlt_properties_close( pools );
285 }
286