OSDN Git Service

plug some memory leaks.
[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.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 #define FIFO_TIMEOUT 200
14
15 /* Fifo */
16 struct hb_fifo_s
17 {
18     hb_lock_t    * lock;
19     hb_cond_t    * cond_full;
20     int            wait_full;
21     hb_cond_t    * cond_empty;
22     int            wait_empty;
23     uint32_t       capacity;
24     uint32_t       thresh;
25     uint32_t       size;
26     uint32_t       buffer_size;
27     hb_buffer_t  * first;
28     hb_buffer_t  * last;
29 };
30
31 /* we round the requested buffer size up to the next power of 2 so there can
32  * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot
33  * of slow & error-prone run-time checking we allow for all 32. */
34 #define MAX_BUFFER_POOLS  32
35 /* the buffer pool only exists to avoid the two malloc and two free calls that
36  * it would otherwise take to allocate & free a buffer. but we don't want to
37  * tie up a lot of memory in the pool because this allocator isn't as general
38  * as malloc so memory tied up here puts more pressure on the malloc pool.
39  * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting
40  * too much memory. */
41 #define BUFFER_POOL_MAX_ELEMENTS 32
42
43 struct hb_buffer_pools_s
44 {
45     int64_t allocated;
46     hb_lock_t *lock;
47     hb_fifo_t *pool[MAX_BUFFER_POOLS];
48 } buffers;
49
50
51 void hb_buffer_pool_init( void )
52 {
53     buffers.lock = hb_lock_init();
54     buffers.allocated = 0;
55
56     /* we allocate pools for sizes 2^10 through 2^25. requests larger than
57      * 2^25 will get passed through to malloc. */
58     int i;
59     for ( i = 10; i < 26; ++i )
60     {
61         buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS, 1);
62         buffers.pool[i]->buffer_size = 1 << i;
63     }
64     /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
65     for ( i = 1; i < 10; ++i )
66     {
67         buffers.pool[i] = buffers.pool[10];
68     }
69 }
70
71 void hb_buffer_pool_free( void )
72 {
73     int i;
74     int count;
75     int64_t freed = 0;
76     hb_buffer_t *b;
77
78     hb_lock(buffers.lock);
79
80     for( i = 10; i < 26; ++i)
81     {
82         count = 0;
83         while( ( b = hb_fifo_get(buffers.pool[i]) ) )
84         {
85             freed += b->alloc;
86             if( b->data )
87             {
88                 free( b->data );
89             }
90             free( b );
91             count++;
92         }
93         if ( count )
94         {
95             hb_deep_log( 2, "Freed %d buffers of size %d", count,
96                     buffers.pool[i]->buffer_size);
97         }
98     }
99
100     hb_deep_log( 2, "Allocated %"PRId64" bytes of buffers on this pass and Freed %"PRId64" bytes, "
101            "%"PRId64" bytes leaked", buffers.allocated, freed, buffers.allocated - freed);
102     buffers.allocated = 0;
103     hb_unlock(buffers.lock);
104 }
105
106 static hb_fifo_t *size_to_pool( int size )
107 {
108     int i;
109     for ( i = 0; i < 30; ++i )
110     {
111         if ( size <= (1 << i) )
112         {
113             return buffers.pool[i];
114         }
115     }
116     return NULL;
117 }
118
119 hb_buffer_t * hb_buffer_init( int size )
120 {
121     hb_buffer_t * b;
122     hb_fifo_t *buffer_pool = size_to_pool( size );
123
124     if( buffer_pool )
125     {
126         b = hb_fifo_get( buffer_pool );
127
128         if( b )
129         {
130             /*
131              * Zero the contents of the buffer, would be nice if we
132              * didn't have to do this.
133              */
134             uint8_t *data = b->data;
135             memset( b, 0, sizeof(hb_buffer_t) );
136             b->alloc = buffer_pool->buffer_size;
137             b->size = size;
138             b->data = data;
139             return( b );
140         }
141     }
142
143     /*
144      * No existing buffers, create a new one
145      */
146     if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
147     {
148         hb_log( "out of memory" );
149         return NULL;
150     }
151
152     b->size  = size;
153     b->alloc  = buffer_pool? buffer_pool->buffer_size : size;
154
155     if (size)
156     {
157 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
158         b->data  = malloc( b->alloc );
159 #elif defined( SYS_CYGWIN )
160         /* FIXME */
161         b->data  = malloc( b->alloc + 17 );
162 #else
163         b->data  = memalign( 16, b->alloc );
164 #endif
165         if( !b->data )
166         {
167             hb_log( "out of memory" );
168             free( b );
169             return NULL;
170         }
171         hb_lock(buffers.lock);
172         buffers.allocated += b->alloc;
173         hb_unlock(buffers.lock);
174     }
175     return b;
176 }
177
178 void hb_buffer_realloc( hb_buffer_t * b, int size )
179 {
180     if ( size > b->alloc )
181     {
182         uint32_t orig = b->alloc;
183         size = size_to_pool( size )->buffer_size;
184         b->data  = realloc( b->data, size );
185         b->alloc = size;
186
187         hb_lock(buffers.lock);
188         buffers.allocated += size - orig;
189         hb_unlock(buffers.lock);
190     }
191 }
192
193 void hb_buffer_close( hb_buffer_t ** _b )
194 {
195     hb_buffer_t * b = *_b;
196
197     while( b )
198     {
199         hb_buffer_t * next = b->next;
200         hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
201
202         b->next = NULL;
203
204         if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
205         {
206             hb_fifo_push_head( buffer_pool, b );
207             b = next;
208             continue;
209         }
210         // either the pool is full or this size doesn't use a pool
211         // free the buf 
212         if( b->data )
213         {
214             free( b->data );
215             hb_lock(buffers.lock);
216             buffers.allocated -= b->alloc;
217             hb_unlock(buffers.lock);
218         }
219         free( b );
220         b = next;
221     }
222     *_b = NULL;
223 }
224
225 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
226 {
227     dst->start     = src->start;
228     dst->stop      = src->stop;
229     dst->new_chap  = src->new_chap;
230     dst->frametype = src->frametype;
231     dst->flags     = src->flags;
232 }
233
234 hb_fifo_t * hb_fifo_init( int capacity, int thresh )
235 {
236     hb_fifo_t * f;
237     f             = calloc( sizeof( hb_fifo_t ), 1 );
238     f->lock       = hb_lock_init();
239     f->cond_full  = hb_cond_init();
240     f->cond_empty = hb_cond_init();
241     f->capacity   = capacity;
242     f->thresh     = thresh;
243     f->buffer_size = 0;
244     return f;
245 }
246
247 int hb_fifo_size_bytes( hb_fifo_t * f )
248 {
249     int ret = 0;
250     hb_buffer_t * link;
251
252     hb_lock( f->lock );
253     link = f->first;
254     while ( link )
255     {
256         ret += link->size;
257         link = link->next;
258     }
259     hb_unlock( f->lock );
260
261     return ret;
262 }
263
264 int hb_fifo_size( hb_fifo_t * f )
265 {
266     int ret;
267
268     hb_lock( f->lock );
269     ret = f->size;
270     hb_unlock( f->lock );
271
272     return ret;
273 }
274
275 int hb_fifo_is_full( hb_fifo_t * f )
276 {
277     int ret;
278
279     hb_lock( f->lock );
280     ret = ( f->size >= f->capacity );
281     hb_unlock( f->lock );
282
283     return ret;
284 }
285
286 float hb_fifo_percent_full( hb_fifo_t * f )
287 {
288     float ret;
289
290     hb_lock( f->lock );
291     ret = f->size / f->capacity;
292     hb_unlock( f->lock );
293
294     return ret;
295 }
296
297 hb_buffer_t * hb_fifo_get_wait( hb_fifo_t * f )
298 {
299     hb_buffer_t * b;
300
301     hb_lock( f->lock );
302     if( f->size < 1 )
303     {
304         f->wait_empty = 1;
305         hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
306         if( f->size < 1 )
307         {
308             hb_unlock( f->lock );
309             return NULL;
310         }
311     }
312     b         = f->first;
313     f->first  = b->next;
314     b->next   = NULL;
315     f->size  -= 1;
316     if( f->wait_full && f->size == f->capacity - f->thresh )
317     {
318         f->wait_full = 0;
319         hb_cond_signal( f->cond_full );
320     }
321     hb_unlock( f->lock );
322
323     return b;
324 }
325
326 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
327 {
328     hb_buffer_t * b;
329
330     hb_lock( f->lock );
331     if( f->size < 1 )
332     {
333         hb_unlock( f->lock );
334         return NULL;
335     }
336     b         = f->first;
337     f->first  = b->next;
338     b->next   = NULL;
339     f->size  -= 1;
340     if( f->wait_full && f->size == f->capacity - f->thresh )
341     {
342         f->wait_full = 0;
343         hb_cond_signal( f->cond_full );
344     }
345     hb_unlock( f->lock );
346
347     return b;
348 }
349
350 hb_buffer_t * hb_fifo_see_wait( hb_fifo_t * f )
351 {
352     hb_buffer_t * b;
353
354     hb_lock( f->lock );
355     if( f->size < 1 )
356     {
357         f->wait_empty = 1;
358         hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
359         if( f->size < 1 )
360         {
361             hb_unlock( f->lock );
362             return NULL;
363         }
364     }
365     b = f->first;
366     hb_unlock( f->lock );
367
368     return b;
369 }
370
371 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
372 {
373     hb_buffer_t * b;
374
375     hb_lock( f->lock );
376     if( f->size < 1 )
377     {
378         hb_unlock( f->lock );
379         return NULL;
380     }
381     b = f->first;
382     hb_unlock( f->lock );
383
384     return b;
385 }
386
387 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
388 {
389     hb_buffer_t * b;
390
391     hb_lock( f->lock );
392     if( f->size < 2 )
393     {
394         hb_unlock( f->lock );
395         return NULL;
396     }
397     b = f->first->next;
398     hb_unlock( f->lock );
399
400     return b;
401 }
402
403 int hb_fifo_full_wait( hb_fifo_t * f )
404 {
405     int result;
406
407     hb_lock( f->lock );
408     if( f->size >= f->capacity )
409     {
410         f->wait_full = 1;
411         hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
412     }
413     result = ( f->size < f->capacity );
414     hb_unlock( f->lock );
415     return result;
416 }
417
418 void hb_fifo_push_wait( hb_fifo_t * f, hb_buffer_t * b )
419 {
420     if( !b )
421     {
422         return;
423     }
424
425     hb_lock( f->lock );
426     if( f->size >= f->capacity )
427     {
428         f->wait_full = 1;
429         hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
430     }
431     if( f->size > 0 )
432     {
433         f->last->next = b;
434     }
435     else
436     {
437         f->first = b;
438     }
439     f->last  = b;
440     f->size += 1;
441     while( f->last->next )
442     {
443         f->size += 1;
444         f->last  = f->last->next;
445     }
446     if( f->wait_empty && f->size >= f->thresh )
447     {
448         f->wait_empty = 0;
449         hb_cond_signal( f->cond_empty );
450     }
451     hb_unlock( f->lock );
452 }
453
454 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
455 {
456     if( !b )
457     {
458         return;
459     }
460
461     hb_lock( f->lock );
462     if( f->size > 0 )
463     {
464         f->last->next = b;
465     }
466     else
467     {
468         f->first = b;
469     }
470     f->last  = b;
471     f->size += 1;
472     while( f->last->next )
473     {
474         f->size += 1;
475         f->last  = f->last->next;
476     }
477     if( f->wait_empty && f->size >= f->thresh )
478     {
479         f->wait_empty = 0;
480         hb_cond_signal( f->cond_empty );
481     }
482     hb_unlock( f->lock );
483 }
484
485 void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b )
486 {
487     hb_buffer_t * tmp;
488     uint32_t      size = 0;
489
490     if( !b )
491     {
492         return;
493     }
494
495     hb_lock( f->lock );
496
497     /*
498      * If there are a chain of buffers prepend the lot
499      */
500     tmp = b;
501     while( tmp->next )
502     {
503         tmp = tmp->next;
504         size += 1;
505     }
506
507     if( f->size > 0 )
508     {
509         tmp->next = f->first;
510     } 
511     else
512     {
513         f->last = tmp;
514     }
515
516     f->first = b;
517     f->size += ( size + 1 );
518
519     hb_unlock( f->lock );
520 }
521
522 void hb_fifo_close( hb_fifo_t ** _f )
523 {
524     hb_fifo_t   * f = *_f;
525     hb_buffer_t * b;
526
527     hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
528     while( ( b = hb_fifo_get( f ) ) )
529     {
530         hb_buffer_close( &b );
531     }
532
533     hb_lock_close( &f->lock );
534     hb_cond_close( &f->cond_empty );
535     hb_cond_close( &f->cond_full );
536     free( f );
537
538     *_f = NULL;
539 }
540
541 void hb_fifo_flush( hb_fifo_t * f )
542 {
543     hb_buffer_t * b;
544
545     while( ( b = hb_fifo_get( f ) ) )
546     {
547         hb_buffer_close( &b );
548     }
549     hb_lock( f->lock );
550     hb_cond_signal( f->cond_empty );
551     hb_cond_signal( f->cond_full );
552     hb_unlock( f->lock );
553
554 }
555