1 /* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $
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. */
13 #define FIFO_TIMEOUT 200
19 hb_cond_t * cond_full;
21 hb_cond_t * cond_empty;
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
41 #define BUFFER_POOL_MAX_ELEMENTS 32
43 struct hb_buffer_pools_s
47 hb_fifo_t *pool[MAX_BUFFER_POOLS];
51 void hb_buffer_pool_init( void )
53 buffers.lock = hb_lock_init();
54 buffers.allocated = 0;
56 /* we allocate pools for sizes 2^10 through 2^25. requests larger than
57 * 2^25 will get passed through to malloc. */
59 for ( i = 10; i < 26; ++i )
61 buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS, 1);
62 buffers.pool[i]->buffer_size = 1 << i;
64 /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
65 for ( i = 1; i < 10; ++i )
67 buffers.pool[i] = buffers.pool[10];
71 void hb_buffer_pool_free( void )
78 hb_lock(buffers.lock);
80 for( i = 10; i < 26; ++i)
83 while( ( b = hb_fifo_get(buffers.pool[i]) ) )
95 hb_deep_log( 2, "Freed %d buffers of size %d", count,
96 buffers.pool[i]->buffer_size);
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);
106 static hb_fifo_t *size_to_pool( int size )
109 for ( i = 0; i < 30; ++i )
111 if ( size <= (1 << i) )
113 return buffers.pool[i];
119 hb_buffer_t * hb_buffer_init( int size )
122 hb_fifo_t *buffer_pool = size_to_pool( size );
126 b = hb_fifo_get( buffer_pool );
131 * Zero the contents of the buffer, would be nice if we
132 * didn't have to do this.
134 uint8_t *data = b->data;
135 memset( b, 0, sizeof(hb_buffer_t) );
136 b->alloc = buffer_pool->buffer_size;
144 * No existing buffers, create a new one
146 if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
148 hb_log( "out of memory" );
153 b->alloc = buffer_pool? buffer_pool->buffer_size : size;
157 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
158 b->data = malloc( b->alloc );
159 #elif defined( SYS_CYGWIN )
161 b->data = malloc( b->alloc + 17 );
163 b->data = memalign( 16, b->alloc );
167 hb_log( "out of memory" );
171 hb_lock(buffers.lock);
172 buffers.allocated += b->alloc;
173 hb_unlock(buffers.lock);
178 void hb_buffer_realloc( hb_buffer_t * b, int size )
180 if ( size > b->alloc )
182 uint32_t orig = b->alloc;
183 size = size_to_pool( size )->buffer_size;
184 b->data = realloc( b->data, size );
187 hb_lock(buffers.lock);
188 buffers.allocated += size - orig;
189 hb_unlock(buffers.lock);
193 // Frees the specified buffer list.
194 void hb_buffer_close( hb_buffer_t ** _b )
196 hb_buffer_t * b = *_b;
200 hb_buffer_t * next = b->next;
201 hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
205 if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
207 hb_fifo_push_head( buffer_pool, b );
211 // either the pool is full or this size doesn't use a pool
216 hb_lock(buffers.lock);
217 buffers.allocated -= b->alloc;
218 hb_unlock(buffers.lock);
226 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
228 dst->start = src->start;
229 dst->stop = src->stop;
230 dst->new_chap = src->new_chap;
231 dst->frametype = src->frametype;
232 dst->flags = src->flags;
235 hb_fifo_t * hb_fifo_init( int capacity, int thresh )
238 f = calloc( sizeof( hb_fifo_t ), 1 );
239 f->lock = hb_lock_init();
240 f->cond_full = hb_cond_init();
241 f->cond_empty = hb_cond_init();
242 f->capacity = capacity;
248 int hb_fifo_size_bytes( hb_fifo_t * f )
260 hb_unlock( f->lock );
265 int hb_fifo_size( hb_fifo_t * f )
271 hb_unlock( f->lock );
276 int hb_fifo_is_full( hb_fifo_t * f )
281 ret = ( f->size >= f->capacity );
282 hb_unlock( f->lock );
287 float hb_fifo_percent_full( hb_fifo_t * f )
292 ret = f->size / f->capacity;
293 hb_unlock( f->lock );
298 // Pulls the first packet out of this FIFO, blocking until such a packet is available.
299 // Returns NULL if this FIFO has been closed or flushed.
300 hb_buffer_t * hb_fifo_get_wait( hb_fifo_t * f )
308 hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
311 hb_unlock( f->lock );
319 if( f->wait_full && f->size == f->capacity - f->thresh )
322 hb_cond_signal( f->cond_full );
324 hb_unlock( f->lock );
329 // Pulls a packet out of this FIFO, or returns NULL if no packet is available.
330 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
337 hb_unlock( f->lock );
344 if( f->wait_full && f->size == f->capacity - f->thresh )
347 hb_cond_signal( f->cond_full );
349 hb_unlock( f->lock );
354 hb_buffer_t * hb_fifo_see_wait( hb_fifo_t * f )
362 hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
365 hb_unlock( f->lock );
370 hb_unlock( f->lock );
375 // Returns the first packet in the specified FIFO.
376 // If the FIFO is empty, returns NULL.
377 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
384 hb_unlock( f->lock );
388 hb_unlock( f->lock );
393 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
400 hb_unlock( f->lock );
404 hb_unlock( f->lock );
409 // Waits until the specified FIFO is no longer full or until FIFO_TIMEOUT milliseconds have elapsed.
410 // Returns whether the FIFO is non-full upon return.
411 int hb_fifo_full_wait( hb_fifo_t * f )
416 if( f->size >= f->capacity )
419 hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
421 result = ( f->size < f->capacity );
422 hb_unlock( f->lock );
426 // Pushes the specified buffer onto the specified FIFO,
427 // blocking until the FIFO has space available.
428 void hb_fifo_push_wait( hb_fifo_t * f, hb_buffer_t * b )
436 if( f->size >= f->capacity )
439 hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
451 while( f->last->next )
454 f->last = f->last->next;
456 if( f->wait_empty && f->size >= 1 )
459 hb_cond_signal( f->cond_empty );
461 hb_unlock( f->lock );
464 // Appends the specified packet list to the end of the specified FIFO.
465 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
483 while( f->last->next )
486 f->last = f->last->next;
488 if( f->wait_empty && f->size >= 1 )
491 hb_cond_signal( f->cond_empty );
493 hb_unlock( f->lock );
496 // Prepends the specified packet list to the start of the specified FIFO.
497 void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b )
510 * If there are a chain of buffers prepend the lot
521 tmp->next = f->first;
529 f->size += ( size + 1 );
531 hb_unlock( f->lock );
534 // Pushes a list of packets onto the specified FIFO as a single element.
535 void hb_fifo_push_list_element( hb_fifo_t *fifo, hb_buffer_t *buffer_list )
537 hb_buffer_t *container = hb_buffer_init( 0 );
538 // XXX: Using an arbitrary hb_buffer_t pointer (other than 'next')
539 // to carry the list inside a single "container" buffer
540 container->next_subpicture = buffer_list;
542 hb_fifo_push( fifo, container );
545 // Removes a list of packets from the specified FIFO that were stored as a single element.
546 hb_buffer_t *hb_fifo_get_list_element( hb_fifo_t *fifo )
548 hb_buffer_t *container = hb_fifo_get( fifo );
549 // XXX: Using an arbitrary hb_buffer_t pointer (other than 'next')
550 // to carry the list inside a single "container" buffer
551 hb_buffer_t *buffer_list = container->next_subpicture;
552 hb_buffer_close( &container );
557 void hb_fifo_close( hb_fifo_t ** _f )
562 hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
563 while( ( b = hb_fifo_get( f ) ) )
565 hb_buffer_close( &b );
568 hb_lock_close( &f->lock );
569 hb_cond_close( &f->cond_empty );
570 hb_cond_close( &f->cond_full );
576 void hb_fifo_flush( hb_fifo_t * f )
580 while( ( b = hb_fifo_get( f ) ) )
582 hb_buffer_close( &b );
585 hb_cond_signal( f->cond_empty );
586 hb_cond_signal( f->cond_full );
587 hb_unlock( f->lock );