OSDN Git Service

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