OSDN Git Service

gitattirubes test 2
[handbrake-jp/handbrake-jp.git] / libhb / fifo.c
1 /* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 #ifndef SYS_DARWIN
10 #include <malloc.h>
11 #endif
12
13 /* Fifo */
14 struct hb_fifo_s
15 {
16     hb_lock_t    * lock;
17     uint32_t       capacity;
18     uint32_t       size;
19     uint32_t       buffer_size;
20     hb_buffer_t  * first;
21     hb_buffer_t  * last;
22 };
23
24 /* we round the requested buffer size up to the next power of 2 so there can
25  * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot
26  * of slow & error-prone run-time checking we allow for all 32. */
27 #define MAX_BUFFER_POOLS  32
28 /* the buffer pool only exists to avoid the two malloc and two free calls that
29  * it would otherwise take to allocate & free a buffer. but we don't want to
30  * tie up a lot of memory in the pool because this allocator isn't as general
31  * as malloc so memory tied up here puts more pressure on the malloc pool.
32  * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting
33  * too much memory. */
34 #define BUFFER_POOL_MAX_ELEMENTS 32
35
36 struct hb_buffer_pools_s
37 {
38     int64_t allocated;
39     hb_lock_t *lock;
40     hb_fifo_t *pool[MAX_BUFFER_POOLS];
41 } buffers;
42
43
44 void hb_buffer_pool_init( void )
45 {
46     buffers.lock = hb_lock_init();
47     buffers.allocated = 0;
48
49     /* we allocate pools for sizes 2^10 through 2^25. requests larger than
50      * 2^25 will get passed through to malloc. */
51     int i;
52     for ( i = 10; i < 26; ++i )
53     {
54         buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
55         buffers.pool[i]->buffer_size = 1 << i;
56     }
57     /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
58     for ( i = 1; i < 10; ++i )
59     {
60         buffers.pool[i] = buffers.pool[10];
61     }
62 }
63
64 void hb_buffer_pool_free( void )
65 {
66     int i;
67     int count;
68     int64_t freed = 0;
69     hb_buffer_t *b;
70
71     hb_lock(buffers.lock);
72
73     for( i = 10; i < 26; ++i)
74     {
75         count = 0;
76         while( ( b = hb_fifo_get(buffers.pool[i]) ) )
77         {
78             freed += b->alloc;
79             if( b->data )
80             {
81                 free( b->data );
82             }
83             free( b );
84             count++;
85         }
86         if ( count )
87         {
88             hb_deep_log( 2, "Freed %d buffers of size %d", count,
89                     buffers.pool[i]->buffer_size);
90         }
91     }
92
93     hb_deep_log( 2, "Allocated %"PRId64" bytes of buffers on this pass and Freed %"PRId64" bytes, "
94            "%"PRId64" bytes leaked", buffers.allocated, freed, buffers.allocated - freed);
95     buffers.allocated = 0;
96     hb_unlock(buffers.lock);
97 }
98
99 static hb_fifo_t *size_to_pool( int size )
100 {
101     int i;
102     for ( i = 0; i < 30; ++i )
103     {
104         if ( size <= (1 << i) )
105         {
106             return buffers.pool[i];
107         }
108     }
109     return NULL;
110 }
111
112 hb_buffer_t * hb_buffer_init( int size )
113 {
114     hb_buffer_t * b;
115     hb_fifo_t *buffer_pool = size_to_pool( size );
116
117     if( buffer_pool )
118     {
119         b = hb_fifo_get( buffer_pool );
120
121         if( b )
122         {
123             /*
124              * Zero the contents of the buffer, would be nice if we
125              * didn't have to do this.
126              */
127             uint8_t *data = b->data;
128             memset( b, 0, sizeof(hb_buffer_t) );
129             b->alloc = buffer_pool->buffer_size;
130             b->size = size;
131             b->data = data;
132             return( b );
133         }
134     }
135
136     /*
137      * No existing buffers, create a new one
138      */
139     if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
140     {
141         hb_log( "out of memory" );
142         return NULL;
143     }
144
145     b->size  = size;
146     b->alloc  = buffer_pool? buffer_pool->buffer_size : size;
147
148     if (size)
149     {
150 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
151         b->data  = malloc( b->alloc );
152 #elif defined( SYS_CYGWIN )
153         /* FIXME */
154         b->data  = malloc( b->alloc + 17 );
155 #else
156         b->data  = memalign( 16, b->alloc );
157 #endif
158         if( !b->data )
159         {
160             hb_log( "out of memory" );
161             free( b );
162             return NULL;
163         }
164         hb_lock(buffers.lock);
165         buffers.allocated += b->alloc;
166         hb_unlock(buffers.lock);
167     }
168     return b;
169 }
170
171 void hb_buffer_realloc( hb_buffer_t * b, int size )
172 {
173     if ( size > b->alloc )
174     {
175         uint32_t orig = b->alloc;
176         size = size_to_pool( size )->buffer_size;
177         b->data  = realloc( b->data, size );
178         b->alloc = size;
179
180         hb_lock(buffers.lock);
181         buffers.allocated += size - orig;
182         hb_unlock(buffers.lock);
183     }
184 }
185
186 void hb_buffer_close( hb_buffer_t ** _b )
187 {
188     hb_buffer_t * b = *_b;
189     hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
190
191     if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
192     {
193         hb_fifo_push_head( buffer_pool, b );
194         *_b = NULL;
195         return;
196     }
197     /* either the pool is full or this size doesn't use a pool - free the buf */
198     if( b->data )
199     {
200         free( b->data );
201         hb_lock(buffers.lock);
202         buffers.allocated -= b->alloc;
203         hb_unlock(buffers.lock);
204     }
205     free( b );
206     *_b = NULL;
207 }
208
209 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
210 {
211     dst->start     = src->start;
212     dst->stop      = src->stop;
213     dst->new_chap  = src->new_chap;
214     dst->frametype = src->frametype;
215     dst->flags     = src->flags;
216 }
217
218 hb_fifo_t * hb_fifo_init( int capacity )
219 {
220     hb_fifo_t * f;
221     f           = calloc( sizeof( hb_fifo_t ), 1 );
222     f->lock     = hb_lock_init();
223     f->capacity = capacity;
224     f->buffer_size = 0;
225     return f;
226 }
227
228 int hb_fifo_size( hb_fifo_t * f )
229 {
230     int ret;
231
232     hb_lock( f->lock );
233     ret = f->size;
234     hb_unlock( f->lock );
235
236     return ret;
237 }
238
239 int hb_fifo_is_full( hb_fifo_t * f )
240 {
241     int ret;
242
243     hb_lock( f->lock );
244     ret = ( f->size >= f->capacity );
245     hb_unlock( f->lock );
246
247     return ret;
248 }
249
250 float hb_fifo_percent_full( hb_fifo_t * f )
251 {
252     float ret;
253
254     hb_lock( f->lock );
255     ret = f->size / f->capacity;
256     hb_unlock( f->lock );
257
258     return ret;
259 }
260
261 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
262 {
263     hb_buffer_t * b;
264
265     hb_lock( f->lock );
266     if( f->size < 1 )
267     {
268         hb_unlock( f->lock );
269         return NULL;
270     }
271     b         = f->first;
272     f->first  = b->next;
273     b->next   = NULL;
274     f->size  -= 1;
275     hb_unlock( f->lock );
276
277     return b;
278 }
279
280 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
281 {
282     hb_buffer_t * b;
283
284     hb_lock( f->lock );
285     if( f->size < 1 )
286     {
287         hb_unlock( f->lock );
288         return NULL;
289     }
290     b = f->first;
291     hb_unlock( f->lock );
292
293     return b;
294 }
295
296 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
297 {
298     hb_buffer_t * b;
299
300     hb_lock( f->lock );
301     if( f->size < 2 )
302     {
303         hb_unlock( f->lock );
304         return NULL;
305     }
306     b = f->first->next;
307     hb_unlock( f->lock );
308
309     return b;
310 }
311
312 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
313 {
314     if( !b )
315     {
316         return;
317     }
318
319     hb_lock( f->lock );
320     if( f->size > 0 )
321     {
322         f->last->next = b;
323     }
324     else
325     {
326         f->first = b;
327     }
328     f->last  = b;
329     f->size += 1;
330     while( f->last->next )
331     {
332         f->size += 1;
333         f->last  = f->last->next;
334     }
335     hb_unlock( f->lock );
336 }
337
338 void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b )
339 {
340     hb_buffer_t * tmp;
341     uint32_t      size = 0;
342
343     if( !b )
344     {
345         return;
346     }
347
348     hb_lock( f->lock );
349
350     /*
351      * If there are a chain of buffers prepend the lot
352      */
353     tmp = b;
354     while( tmp->next )
355     {
356         tmp = tmp->next;
357         size += 1;
358     }
359
360     if( f->size > 0 )
361     {
362         tmp->next = f->first;
363     } 
364     else
365     {
366         f->last = tmp;
367     }
368
369     f->first = b;
370     f->size += ( size + 1 );
371
372     hb_unlock( f->lock );
373 }
374
375 void hb_fifo_close( hb_fifo_t ** _f )
376 {
377     hb_fifo_t   * f = *_f;
378     hb_buffer_t * b;
379
380     hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
381     while( ( b = hb_fifo_get( f ) ) )
382     {
383         hb_buffer_close( &b );
384     }
385
386     hb_lock_close( &f->lock );
387     free( f );
388
389     *_f = NULL;
390 }