OSDN Git Service

Two changes, one ensure zero size buffers are zero size, second change the buffer...
[handbrake-jp/handbrake-jp-git.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.m0k.org/>.
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     int            capacity;
18     int            size;
19     int            buffer_size;
20     hb_buffer_t  * first;
21     hb_buffer_t  * last;
22 };
23
24 #define MAX_BUFFER_POOLS  15
25 #define BUFFER_POOL_MAX_ELEMENTS 2048
26
27 struct hb_buffer_pools_s
28 {
29     int entries;
30     int allocated;
31     hb_fifo_t *pool[MAX_BUFFER_POOLS];
32     hb_lock_t *lock;
33 };
34
35 struct hb_buffer_pools_s buffers;
36
37 void hb_buffer_pool_init( void )
38 {
39     hb_fifo_t *buffer_pool;
40     int size = 512;
41     int max_size = 32768;;
42
43     buffers.entries = 0;
44     buffers.lock = hb_lock_init();
45     buffers.allocated = 0;
46     
47     while(size <= max_size) {
48         buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
49         buffer_pool->buffer_size = size;
50         size *= 2;
51     }
52 }
53
54 void hb_buffer_pool_free( void )
55 {
56     int i;
57     int count;
58     int freed = 0;
59     hb_buffer_t *b;
60
61     hb_lock(buffers.lock);
62
63     for( i = 0; i < buffers.entries; i++) 
64     {
65         count = 0;
66         while( ( b = hb_fifo_get(buffers.pool[i]) ) )
67         {
68             freed += b->alloc;
69             if( b->data )
70             {
71                 free( b->data );
72                 b->data = NULL;
73             }
74             free( b );
75             count++;
76         }
77         hb_log("Freed %d buffers of size %d", count, buffers.pool[i]->buffer_size);
78     }
79
80     hb_log("Allocated %d bytes of buffers on this pass and Freed %d bytes, %d bytes leaked",
81            buffers.allocated, freed, buffers.allocated - freed);
82     buffers.allocated = 0;
83     hb_unlock(buffers.lock);
84 }
85
86
87 hb_buffer_t * hb_buffer_init( int size )
88
89     hb_buffer_t * b;
90     int i;
91     hb_fifo_t *buffer_pool = NULL;
92     uint8_t *data;
93     int b_alloc;
94     int resize = 0;
95
96     if( size > 0 )
97     {
98         /*
99          * The buffer pools are allocated in increasing size
100          */
101         for( i = 0; i < buffers.entries; i++ )
102         {
103             if( buffers.pool[i]->buffer_size >= size )
104             {
105                 /*
106                  * This pool is big enough, but are there any buffers in it?
107                  */
108                 if( hb_fifo_size( buffers.pool[i] ) ) 
109                 {
110                     /*
111                      * We've found a matching buffer pool, with buffers.
112                      */
113                     buffer_pool = buffers.pool[i];
114                     resize =  buffers.pool[i]->buffer_size;
115                 } else {
116                     /*
117                      * Buffer pool is empty, 
118                      */
119                     if( resize ) {
120                         /*
121                          * This is the second time through, so break
122                          * out of here to avoid using too large a
123                          * buffer for a small job.
124                          */
125                         break;
126                     }
127                     resize =  buffers.pool[i]->buffer_size;
128                 }
129             }
130         }
131     }
132     /*
133      * Don't reuse the 0 size buffers, not much gain.
134      */
135     if( size != 0 && buffer_pool )
136     {
137         b = hb_fifo_get( buffer_pool );    
138
139         if( b )
140         {
141             /*
142              * Zero the contents of the buffer, would be nice if we
143              * didn't have to do this.
144              *
145             hb_log("Reused buffer size %d for size %d from pool %d depth %d", 
146                    b->alloc, size, smallest_pool->buffer_size, 
147                    hb_fifo_size(smallest_pool));
148             */
149             data = b->data;
150             b_alloc = b->alloc;
151             memset( b, 0, sizeof(hb_buffer_t) );
152             b->alloc = b_alloc;
153             b->size = size;
154             b->data = data;
155             return( b );
156         } 
157     }
158
159     /*
160      * No existing buffers, create a new one
161      */
162     if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
163     {
164         hb_log( "out of memory" );
165         return NULL;
166     }
167
168     b->size  = size;
169
170     if( resize )
171     {
172         size = resize;
173     } 
174     b->alloc  = size;  
175
176     /*
177     hb_log("Allocating new buffer of size %d for size %d", 
178            b->alloc, 
179            b->size);
180     */
181
182     if (!size)
183         return b;
184 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
185     b->data  = malloc( b->alloc );
186 #elif defined( SYS_CYGWIN )
187     /* FIXME */
188     b->data  = malloc( b->alloc + 17 );
189 #else
190     b->data  = memalign( 16, b->alloc );
191 #endif
192
193     if( !b->data )
194     {
195         hb_log( "out of memory" );
196         free( b );
197         return NULL;
198     }
199
200     buffers.allocated += b->alloc;
201
202     return b;
203 }
204
205 void hb_buffer_realloc( hb_buffer_t * b, int size )
206 {
207     /* No more alignment, but we don't care */
208     if( size < 2048 ) {
209         size = 2048;
210     }
211     b->data  = realloc( b->data, size );
212     buffers.allocated -= b->alloc;
213     b->alloc = size;
214     buffers.allocated += b->alloc;
215 }
216
217 void hb_buffer_close( hb_buffer_t ** _b )
218 {
219     hb_buffer_t * b = *_b;
220     hb_fifo_t *buffer_pool = NULL;
221     int i;
222
223     /*
224      * Put the buffer into our free list in the matching buffer pool, if there is one.
225      */
226     if( b->alloc != 0 )
227     {
228         for( i = 0; i < buffers.entries; i++ )
229         {
230             if( b->alloc == buffers.pool[i]->buffer_size )
231             { 
232                 buffer_pool = buffers.pool[i];
233                 break;
234             }
235         }
236     }
237
238     if( buffer_pool ) 
239     {
240         if( !hb_fifo_is_full( buffer_pool ) ) 
241         {
242             if(b->data)
243             {
244                 /*
245                 hb_log("Putting a buffer of size %d on pool %d, depth %d",
246                        b->alloc, 
247                        buffer_pool->buffer_size, 
248                        hb_fifo_size(buffer_pool));
249                 */
250                 hb_fifo_push( buffer_pool, b );
251             } else {
252                 free(b);
253             }
254         } else {
255             /*
256              * Got a load of these size ones already, free this buffer.
257              *
258             hb_log("Buffer pool for size %d full, freeing buffer", b->alloc);
259             */
260             if( b->data )
261             {
262                 free( b->data );
263             }
264             buffers.allocated -= b->alloc;
265             free( b );
266         }
267     } else {
268         /*
269          * Need a new buffer pool for this size.
270          */
271         hb_lock(buffers.lock);
272         if ( b->alloc != 0 && buffers.entries < MAX_BUFFER_POOLS)
273         {
274             buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
275             buffer_pool->buffer_size = b->alloc;
276             hb_fifo_push( buffer_pool, b );
277             /*
278             hb_log("*** Allocated a new buffer pool for size %d [%d]", b->alloc,
279                    buffers.entries );
280             */
281         } else {
282             if( b->alloc != 0 )
283             {
284                 for( i = buffers.entries-1; i >= 0; i-- )
285                 {
286                     if( hb_fifo_size(buffers.pool[i]) == 0 )
287                     {
288                         /*
289                          * Reuse this pool as it is empty.
290                          */
291                         buffers.pool[i]->buffer_size = b->alloc;
292                         hb_fifo_push( buffers.pool[i], b );
293                         b = NULL;
294                         break;
295                     }
296                 }
297             }
298
299             if( b )
300             {
301                 if( b->data )
302                 {
303                     free( b->data );
304                     b->data = NULL;
305                     buffers.allocated -= b->alloc;
306                 }
307                 free( b );
308             }
309         }
310         hb_unlock(buffers.lock);
311     }
312
313     *_b = NULL;
314
315 }
316
317 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
318 {
319     dst->start     = src->start;
320     dst->stop      = src->stop;
321     dst->new_chap  = src->new_chap;
322     dst->frametype = src->frametype;
323     dst->flags     = src->flags;
324 }
325
326 hb_fifo_t * hb_fifo_init( int capacity )
327 {
328     hb_fifo_t * f;
329     f           = calloc( sizeof( hb_fifo_t ), 1 );
330     f->lock     = hb_lock_init();
331     f->capacity = capacity;
332     f->buffer_size = 0;
333     return f;
334 }
335
336 int hb_fifo_size( hb_fifo_t * f )
337 {
338     int ret;
339
340     hb_lock( f->lock );
341     ret = f->size;
342     hb_unlock( f->lock );
343
344     return ret;
345 }
346
347 int hb_fifo_is_full( hb_fifo_t * f )
348 {
349     int ret;
350
351     hb_lock( f->lock );
352     ret = ( f->size >= f->capacity );
353     hb_unlock( f->lock );
354
355     return ret;
356 }
357
358 float hb_fifo_percent_full( hb_fifo_t * f )
359 {
360     float ret;
361
362     hb_lock( f->lock );
363     ret = f->size / f->capacity;
364     hb_unlock( f->lock );
365
366     return ret;
367 }
368
369 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
370 {
371     hb_buffer_t * b;
372
373     hb_lock( f->lock );
374     if( f->size < 1 )
375     {
376         hb_unlock( f->lock );
377         return NULL;
378     }
379     b         = f->first;
380     f->first  = b->next;
381     b->next   = NULL;
382     f->size  -= 1;
383     hb_unlock( f->lock );
384     
385     return b;
386 }
387
388 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
389 {
390     hb_buffer_t * b;
391
392     hb_lock( f->lock );
393     if( f->size < 1 )
394     {
395         hb_unlock( f->lock );
396         return NULL;
397     }
398     b = f->first;
399     hb_unlock( f->lock );
400
401     return b;
402 }
403
404 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
405 {
406     hb_buffer_t * b;
407
408     hb_lock( f->lock );
409     if( f->size < 2 )
410     {
411         hb_unlock( f->lock );
412         return NULL;
413     }
414     b = f->first->next;
415     hb_unlock( f->lock );
416
417     return b;
418 }
419
420 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
421 {
422     if( !b )
423     {
424         return;
425     }
426
427     hb_lock( f->lock );
428     if( f->size > 0 )
429     {
430         f->last->next = b;
431     }
432     else
433     {
434         f->first = b;
435     }
436     f->last  = b;
437     f->size += 1;
438     while( f->last->next )
439     {
440         f->size += 1;
441         f->last  = f->last->next;
442     }
443     hb_unlock( f->lock );
444 }
445
446 void hb_fifo_close( hb_fifo_t ** _f )
447 {
448     hb_fifo_t   * f = *_f;
449     hb_buffer_t * b;
450     
451     hb_log( "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
452     while( ( b = hb_fifo_get( f ) ) )
453     {
454         hb_buffer_close( &b );
455     }
456
457     hb_lock_close( &f->lock );
458     free( f );
459
460     *_f = NULL;
461 }