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