WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / fifo.c
blob72c1c181fb3f42158eec2283ac33ce3022f27324
1 /* fifo.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #include "hb.h"
11 #include "openclwrapper.h"
13 #ifndef SYS_DARWIN
14 #include <malloc.h>
15 #endif
17 #define FIFO_TIMEOUT 200
18 //#define HB_FIFO_DEBUG 1
19 //#define HB_BUFFER_DEBUG 1
21 /* Fifo */
22 struct hb_fifo_s
24 hb_lock_t * lock;
25 hb_cond_t * cond_full;
26 int wait_full;
27 hb_cond_t * cond_empty;
28 int wait_empty;
29 hb_cond_t * cond_alert_full;
30 uint32_t capacity;
31 uint32_t thresh;
32 uint32_t size;
33 uint32_t buffer_size;
34 hb_buffer_t * first;
35 hb_buffer_t * last;
37 #if defined(HB_FIFO_DEBUG)
38 // Fifo list for debugging
39 hb_fifo_t * next;
40 #endif
43 #if defined(HB_FIFO_DEBUG)
44 static hb_fifo_t fifo_list =
46 .next = NULL
48 #endif
50 /* we round the requested buffer size up to the next power of 2 so there can
51 * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot
52 * of slow & error-prone run-time checking we allow for all 32. */
53 #define MAX_BUFFER_POOLS 32
54 #define BUFFER_POOL_FIRST 10
55 #define BUFFER_POOL_LAST 25
56 /* the buffer pool only exists to avoid the two malloc and two free calls that
57 * it would otherwise take to allocate & free a buffer. but we don't want to
58 * tie up a lot of memory in the pool because this allocator isn't as general
59 * as malloc so memory tied up here puts more pressure on the malloc pool.
60 * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting
61 * too much memory. */
62 #define BUFFER_POOL_MAX_ELEMENTS 32
64 struct hb_buffer_pools_s
66 int64_t allocated;
67 hb_lock_t *lock;
68 hb_fifo_t *pool[MAX_BUFFER_POOLS];
69 #if defined(HB_BUFFER_DEBUG)
70 hb_list_t *alloc_list;
71 #endif
72 } buffers;
75 void hb_buffer_pool_init( void )
77 buffers.lock = hb_lock_init();
78 buffers.allocated = 0;
80 #if defined(HB_BUFFER_DEBUG)
81 buffers.alloc_list = hb_list_init();
82 #endif
84 /* we allocate pools for sizes 2^10 through 2^25. requests larger than
85 * 2^25 will get passed through to malloc. */
86 int i;
88 // Create larger queue for 2^10 bucket since all allocations smaller than
89 // 2^10 come from here.
90 buffers.pool[BUFFER_POOL_FIRST] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS*10, 1);
91 buffers.pool[BUFFER_POOL_FIRST]->buffer_size = 1 << 10;
93 /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
94 for ( i = 1; i < BUFFER_POOL_FIRST; ++i )
96 buffers.pool[i] = buffers.pool[BUFFER_POOL_FIRST];
98 for ( i = BUFFER_POOL_FIRST + 1; i <= BUFFER_POOL_LAST; ++i )
100 buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS, 1);
101 buffers.pool[i]->buffer_size = 1 << i;
105 #if defined(HB_FIFO_DEBUG)
107 static void dump_fifo(hb_fifo_t * f)
109 hb_buffer_t * b = f->first;
111 if (b)
113 while (b)
115 fprintf(stderr, "%p:%d:%d\n", b, b->size, b->alloc);
116 b = b->next;
118 fprintf(stderr, "\n");
122 static void fifo_list_add( hb_fifo_t * f )
124 hb_fifo_t *next = fifo_list.next;
126 fifo_list.next = f;
127 f->next = next;
130 static void fifo_list_rem( hb_fifo_t * f )
132 hb_fifo_t *next, *prev;
134 prev = &fifo_list;
135 next = fifo_list.next;
137 while ( next && next != f )
139 prev = next;
140 next = next->next;
142 if ( next == f )
144 prev->next = f->next;
148 // These routines are useful for finding and debugging problems
149 // with the fifos and buffer pools
150 static void buffer_pool_validate( hb_fifo_t * f )
152 hb_buffer_t *b;
154 hb_lock( f->lock );
155 b = f->first;
156 while (b)
158 if (b->alloc != f->buffer_size)
160 fprintf(stderr, "Invalid buffer pool size! buf %p size %d pool size %d\n", b, b->alloc, f->buffer_size);
161 dump_fifo( f );
162 *(char*)0 = 1;
164 b = b->next;
167 hb_unlock( f->lock );
170 static void buffer_pools_validate( void )
172 int ii;
173 for ( ii = BUFFER_POOL_FIRST; ii <= BUFFER_POOL_LAST; ++ii )
175 buffer_pool_validate( buffers.pool[ii] );
179 void fifo_list_validate( void )
181 hb_fifo_t *next = fifo_list.next;
182 hb_fifo_t *m;
183 hb_buffer_t *b, *c;
184 int count;
186 buffer_pools_validate();
187 while ( next )
189 count = 0;
190 hb_lock( next->lock );
191 b = next->first;
193 // Count the number of entries in this fifo
194 while (b)
196 c = b->next;
197 // check that the current buffer is not duplicated in this fifo
198 while (c)
200 if (c == b)
202 fprintf(stderr, "Duplicate buffer in fifo!\n");
203 dump_fifo(next);
204 *(char*)0 = 1;
206 c = c->next;
209 // check that the current buffer is not duplicated in another fifo
210 m = next->next;
211 while (m)
213 hb_lock( m->lock );
214 c = m->first;
215 while (c)
217 if (c == b)
219 fprintf(stderr, "Duplicate buffer in another fifo!\n");
220 dump_fifo(next);
221 *(char*)0 = 1;
223 c = c->next;
225 hb_unlock( m->lock );
226 m = m->next;
229 count++;
230 b = b->next;
233 if ( count != next->size )
235 fprintf(stderr, "Invalid fifo size! count %d size %d\n", count, next->size);
236 dump_fifo(next);
237 *(char*)0 = 1;
239 hb_unlock( next->lock );
241 next = next->next;
244 #endif
246 void hb_buffer_pool_free( void )
248 int i;
249 int count;
250 int64_t freed = 0;
251 hb_buffer_t *b;
253 hb_lock(buffers.lock);
255 #if defined(HB_BUFFER_DEBUG)
256 hb_deep_log(2, "leaked %d buffers", hb_list_count(buffers.alloc_list));
257 for (i = 0; i < hb_list_count(buffers.alloc_list); i++)
259 hb_buffer_t *b = hb_list_item(buffers.alloc_list, i);
260 hb_deep_log(2, "leaked buffer %p type %d size %d alloc %d",
261 b, b->s.type, b->size, b->alloc);
263 #endif
265 for( i = BUFFER_POOL_FIRST; i <= BUFFER_POOL_LAST; ++i)
267 count = 0;
268 while( ( b = hb_fifo_get(buffers.pool[i]) ) )
270 if( b->data )
272 freed += b->alloc;
274 if (b->cl.buffer != NULL)
276 /* OpenCL */
277 if (hb_cl_free_mapped_buffer(b->cl.buffer, b->data) == 0)
279 hb_log("hb_buffer_pool_free: bad free: %p -> buffer %p map %p",
280 b, b->cl.buffer, b->data);
283 else
285 free(b->data);
288 free( b );
289 count++;
291 if ( count )
293 hb_deep_log( 2, "Freed %d buffers of size %d", count,
294 buffers.pool[i]->buffer_size);
298 hb_deep_log( 2, "Allocated %"PRId64" bytes of buffers on this pass and Freed %"PRId64" bytes, "
299 "%"PRId64" bytes leaked", buffers.allocated, freed, buffers.allocated - freed);
300 buffers.allocated = 0;
301 hb_unlock(buffers.lock);
304 static hb_fifo_t *size_to_pool( int size )
306 int i;
307 for ( i = BUFFER_POOL_FIRST; i <= BUFFER_POOL_LAST; ++i )
309 if ( size <= (1 << i) )
311 return buffers.pool[i];
314 return NULL;
317 hb_buffer_t * hb_buffer_init_internal( int size , int needsMapped )
319 hb_buffer_t * b;
320 // Certain libraries (hrm ffmpeg) expect buffers passed to them to
321 // end on certain alignments (ffmpeg is 8). So allocate some extra bytes.
322 // Note that we can't simply align the end of our buffer because
323 // sometimes we feed data to these libraries starting from arbitrary
324 // points within the buffer.
325 int alloc = size + 16;
326 hb_fifo_t *buffer_pool = size_to_pool( alloc );
328 if( buffer_pool )
330 b = hb_fifo_get( buffer_pool );
332 /* OpenCL */
333 if (b != NULL && needsMapped && b->cl.buffer == NULL)
335 // We need a mapped OpenCL buffer and that is not
336 // what we got out of the pool.
337 // Ditch it; it will get replaced with what we need.
338 if (b->data != NULL)
340 free(b->data);
342 free(b);
343 b = NULL;
346 if( b )
349 * Zero the contents of the buffer, would be nice if we
350 * didn't have to do this.
352 uint8_t *data = b->data;
354 /* OpenCL */
355 cl_mem buffer = b->cl.buffer;
356 cl_event last_event = b->cl.last_event;
357 int loc = b->cl.buffer_location;
359 memset( b, 0, sizeof(hb_buffer_t) );
360 b->alloc = buffer_pool->buffer_size;
361 b->size = size;
362 b->data = data;
363 b->s.start = AV_NOPTS_VALUE;
364 b->s.stop = AV_NOPTS_VALUE;
365 b->s.renderOffset = AV_NOPTS_VALUE;
367 /* OpenCL */
368 b->cl.buffer = buffer;
369 b->cl.last_event = last_event;
370 b->cl.buffer_location = loc;
372 #if defined(HB_BUFFER_DEBUG)
373 hb_lock(buffers.lock);
374 hb_list_add(buffers.alloc_list, b);
375 hb_unlock(buffers.lock);
376 #endif
377 return( b );
382 * No existing buffers, create a new one
384 if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
386 hb_log( "out of memory" );
387 return NULL;
390 b->size = size;
391 b->alloc = buffer_pool ? buffer_pool->buffer_size : alloc;
393 if (size)
395 /* OpenCL */
396 b->cl.last_event = NULL;
397 b->cl.buffer_location = HOST;
399 /* OpenCL */
400 if (needsMapped)
402 int status = hb_cl_create_mapped_buffer(&b->cl.buffer, &b->data, b->alloc);
403 if (!status)
405 hb_error("Failed to map CL buffer");
406 free(b);
407 return NULL;
410 else
412 b->cl.buffer = NULL;
414 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
415 b->data = malloc( b->alloc );
416 #elif defined( SYS_CYGWIN )
417 /* FIXME */
418 b->data = malloc( b->alloc + 17 );
419 #else
420 b->data = memalign( 16, b->alloc );
421 #endif
424 if( !b->data )
426 hb_log( "out of memory" );
427 free( b );
428 return NULL;
430 hb_lock(buffers.lock);
431 buffers.allocated += b->alloc;
432 hb_unlock(buffers.lock);
434 b->s.start = AV_NOPTS_VALUE;
435 b->s.stop = AV_NOPTS_VALUE;
436 b->s.renderOffset = AV_NOPTS_VALUE;
437 #if defined(HB_BUFFER_DEBUG)
438 hb_lock(buffers.lock);
439 hb_list_add(buffers.alloc_list, b);
440 hb_unlock(buffers.lock);
441 #endif
442 return b;
445 hb_buffer_t * hb_buffer_init( int size )
447 return hb_buffer_init_internal(size, 0);
450 hb_buffer_t * hb_buffer_eof_init(void)
452 hb_buffer_t * buf = hb_buffer_init(0);
453 buf->s.flags = HB_BUF_FLAG_EOF;
454 return buf;
457 void hb_buffer_realloc( hb_buffer_t * b, int size )
459 if ( size > b->alloc || b->data == NULL )
461 uint32_t orig = b->data != NULL ? b->alloc : 0;
462 size = size_to_pool( size )->buffer_size;
463 b->data = realloc( b->data, size );
464 b->alloc = size;
466 hb_lock(buffers.lock);
467 buffers.allocated += size - orig;
468 hb_unlock(buffers.lock);
472 void hb_buffer_reduce( hb_buffer_t * b, int size )
475 if ( size < b->alloc / 8 || b->data == NULL )
477 hb_buffer_t * tmp = hb_buffer_init( size );
479 hb_buffer_swap_copy( b, tmp );
480 memcpy( b->data, tmp->data, size );
481 tmp->next = NULL;
482 hb_buffer_close( &tmp );
486 hb_buffer_t * hb_buffer_dup( const hb_buffer_t * src )
489 hb_buffer_t * buf;
491 if ( src == NULL )
492 return NULL;
494 buf = hb_buffer_init( src->size );
495 if ( buf )
497 memcpy( buf->data, src->data, src->size );
498 buf->s = src->s;
499 buf->f = src->f;
500 if ( buf->s.type == FRAME_BUF )
501 hb_buffer_init_planes( buf );
504 #ifdef USE_QSV
505 memcpy(&buf->qsv_details, &src->qsv_details, sizeof(src->qsv_details));
506 #endif
508 return buf;
511 int hb_buffer_copy(hb_buffer_t * dst, const hb_buffer_t * src)
513 if (src == NULL || dst == NULL)
514 return -1;
516 if ( dst->size < src->size )
517 return -1;
519 memcpy( dst->data, src->data, src->size );
520 dst->s = src->s;
521 dst->f = src->f;
522 if (dst->s.type == FRAME_BUF)
523 hb_buffer_init_planes(dst);
525 return 0;
528 static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane )
530 uint8_t * plane = b->data;
531 int p;
533 for( p = 0; p < 4; p++ )
535 if ( has_plane[p] )
537 b->plane[p].data = plane;
538 b->plane[p].stride = hb_image_stride( b->f.fmt, b->f.width, p );
539 b->plane[p].height_stride = hb_image_height_stride( b->f.fmt, b->f.height, p );
540 b->plane[p].width = hb_image_width( b->f.fmt, b->f.width, p );
541 b->plane[p].height = hb_image_height( b->f.fmt, b->f.height, p );
542 b->plane[p].size = b->plane[p].stride * b->plane[p].height_stride;
543 plane += b->plane[p].size;
548 void hb_buffer_init_planes( hb_buffer_t * b )
550 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(b->f.fmt);
551 int p;
553 if (desc == NULL)
555 return;
558 uint8_t has_plane[4] = {0,};
560 for( p = 0; p < 4; p++ )
562 has_plane[desc->comp[p].plane] = 1;
564 hb_buffer_init_planes_internal( b, has_plane );
567 // this routine gets a buffer for an uncompressed picture
568 // with pixel format pix_fmt and dimensions width x height.
569 hb_buffer_t * hb_frame_buffer_init( int pix_fmt, int width, int height )
571 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
572 hb_buffer_t * buf;
573 int p;
574 uint8_t has_plane[4] = {0,};
576 if (desc == NULL)
578 return NULL;
580 for( p = 0; p < 4; p++ )
582 has_plane[desc->comp[p].plane] = 1;
585 int size = 0;
586 for( p = 0; p < 4; p++ )
588 if ( has_plane[p] )
590 size += hb_image_stride( pix_fmt, width, p ) *
591 hb_image_height_stride( pix_fmt, height, p );
595 /* OpenCL */
596 buf = hb_buffer_init_internal(size , hb_use_buffers());
598 if( buf == NULL )
599 return NULL;
601 buf->s.type = FRAME_BUF;
602 buf->f.width = width;
603 buf->f.height = height;
604 buf->f.fmt = pix_fmt;
606 hb_buffer_init_planes_internal( buf, has_plane );
607 return buf;
610 // this routine reallocs a buffer for an uncompressed YUV420 video frame
611 // with dimensions width x height.
612 void hb_video_buffer_realloc( hb_buffer_t * buf, int width, int height )
614 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(buf->f.fmt);
615 int p;
616 uint8_t has_plane[4] = {0,};
618 if (desc == NULL)
620 return;
622 for( p = 0; p < 4; p++ )
624 has_plane[desc->comp[p].plane] = 1;
627 int size = 0;
628 for( p = 0; p < 4; p++ )
630 if ( has_plane[p] )
632 size += hb_image_stride( buf->f.fmt, width, p ) *
633 hb_image_height_stride( buf->f.fmt, height, p );
637 hb_buffer_realloc(buf, size );
639 buf->f.width = width;
640 buf->f.height = height;
641 buf->size = size;
643 hb_buffer_init_planes_internal( buf, has_plane );
646 // this routine 'moves' data from src to dst by interchanging 'data',
647 // 'size' & 'alloc' between them and copying the rest of the fields
648 // from src to dst.
649 void hb_buffer_swap_copy( hb_buffer_t *src, hb_buffer_t *dst )
651 uint8_t *data = dst->data;
652 int size = dst->size;
653 int alloc = dst->alloc;
655 /* OpenCL */
656 cl_mem buffer = dst->cl.buffer;
657 cl_event last_event = dst->cl.last_event;
658 int loc = dst->cl.buffer_location;
660 *dst = *src;
662 src->data = data;
663 src->size = size;
664 src->alloc = alloc;
666 /* OpenCL */
667 src->cl.buffer = buffer;
668 src->cl.last_event = last_event;
669 src->cl.buffer_location = loc;
672 // Frees the specified buffer list.
673 void hb_buffer_close( hb_buffer_t ** _b )
675 hb_buffer_t * b = *_b;
677 while( b )
679 hb_buffer_t * next = b->next;
680 hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
682 b->next = NULL;
684 #if defined(HB_BUFFER_DEBUG)
685 hb_lock(buffers.lock);
686 hb_list_rem(buffers.alloc_list, b);
687 hb_unlock(buffers.lock);
688 #endif
689 // Close any attached subtitle buffers
690 hb_buffer_close( &b->sub );
692 if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
694 hb_fifo_push_head( buffer_pool, b );
695 b = next;
696 continue;
698 // either the pool is full or this size doesn't use a pool
699 // free the buf
700 if( b->data )
702 if (b->cl.buffer != NULL)
704 /* OpenCL */
705 if (hb_cl_free_mapped_buffer(b->cl.buffer, b->data) == 0)
707 hb_log("hb_buffer_pool_free: bad free %p -> buffer %p map %p",
708 b, b->cl.buffer, b->data);
711 else
713 free(b->data);
715 hb_lock(buffers.lock);
716 buffers.allocated -= b->alloc;
717 hb_unlock(buffers.lock);
719 free( b );
720 b = next;
723 *_b = NULL;
726 void hb_buffer_move_subs( hb_buffer_t * dst, hb_buffer_t * src )
728 // Note that dst takes ownership of the subtitles
729 dst->sub = src->sub;
730 src->sub = NULL;
732 #ifdef USE_QSV
733 memcpy(&dst->qsv_details, &src->qsv_details, sizeof(src->qsv_details));
734 #endif
738 hb_image_t * hb_image_init(int pix_fmt, int width, int height)
740 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
741 int p;
742 uint8_t has_plane[4] = {0,};
744 if (desc == NULL)
746 return NULL;
748 for (p = 0; p < 4; p++)
750 has_plane[desc->comp[p].plane] = 1;
753 int size = 0;
754 for (p = 0; p < 4; p++)
756 if (has_plane[p])
758 size += hb_image_stride( pix_fmt, width, p ) *
759 hb_image_height_stride( pix_fmt, height, p );
763 hb_image_t *image = calloc(1, sizeof(hb_image_t));
764 if (image == NULL)
766 return NULL;
768 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
769 image->data = malloc(size);
770 #elif defined( SYS_CYGWIN )
771 /* FIXME */
772 image->data = malloc(size + 17);
773 #else
774 image->data = memalign(16, size);
775 #endif
776 if (image->data == NULL)
778 free(image);
779 return NULL;
781 image->format = pix_fmt;
782 image->width = width;
783 image->height = height;
784 memset(image->data, 0, size);
786 uint8_t * plane = image->data;
787 for (p = 0; p < 4; p++)
789 if (has_plane[p])
791 image->plane[p].data = plane;
792 image->plane[p].stride = hb_image_stride(pix_fmt, width, p );
793 image->plane[p].height_stride =
794 hb_image_height_stride(pix_fmt, height, p );
795 image->plane[p].width = hb_image_width(pix_fmt, width, p );
796 image->plane[p].height = hb_image_height(pix_fmt, height, p );
797 image->plane[p].size =
798 image->plane[p].stride * image->plane[p].height_stride;
799 plane += image->plane[p].size;
802 return image;
805 hb_image_t * hb_buffer_to_image(hb_buffer_t *buf)
807 hb_image_t *image = calloc(1, sizeof(hb_image_t));
809 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
810 image->data = malloc( buf->size );
811 #elif defined( SYS_CYGWIN )
812 /* FIXME */
813 image->data = malloc( buf->size + 17 );
814 #else
815 image->data = memalign( 16, buf->size );
816 #endif
817 if (image->data == NULL)
819 free(image);
820 return NULL;
823 image->format = buf->f.fmt;
824 image->width = buf->f.width;
825 image->height = buf->f.height;
826 memcpy(image->data, buf->data, buf->size);
828 int p;
829 uint8_t *data = image->data;
830 for (p = 0; p < 4; p++)
832 image->plane[p].data = data;
833 image->plane[p].width = buf->plane[p].width;
834 image->plane[p].height = buf->plane[p].height;
835 image->plane[p].stride = buf->plane[p].stride;
836 image->plane[p].height_stride = buf->plane[p].height_stride;
837 image->plane[p].size = buf->plane[p].size;
838 data += image->plane[p].size;
840 return image;
843 void hb_image_close(hb_image_t **_image)
845 if (_image == NULL)
846 return;
848 hb_image_t * image = *_image;
849 if (image != NULL)
851 free(image->data);
852 free(image);
853 *_image = NULL;
857 hb_fifo_t * hb_fifo_init( int capacity, int thresh )
859 hb_fifo_t * f;
860 f = calloc( sizeof( hb_fifo_t ), 1 );
861 f->lock = hb_lock_init();
862 f->cond_full = hb_cond_init();
863 f->cond_empty = hb_cond_init();
864 f->capacity = capacity;
865 f->thresh = thresh;
866 f->buffer_size = 0;
868 #if defined(HB_FIFO_DEBUG)
869 // Add the fifo to the global fifo list
870 fifo_list_add( f );
871 #endif
872 return f;
875 void hb_fifo_register_full_cond( hb_fifo_t * f, hb_cond_t * c )
877 f->cond_alert_full = c;
880 int hb_fifo_size_bytes( hb_fifo_t * f )
882 int ret = 0;
883 hb_buffer_t * link;
885 hb_lock( f->lock );
886 link = f->first;
887 while ( link )
889 ret += link->size;
890 link = link->next;
892 hb_unlock( f->lock );
894 return ret;
897 int hb_fifo_size( hb_fifo_t * f )
899 int ret;
901 hb_lock( f->lock );
902 ret = f->size;
903 hb_unlock( f->lock );
905 return ret;
908 int hb_fifo_is_full( hb_fifo_t * f )
910 int ret;
912 hb_lock( f->lock );
913 ret = ( f->size >= f->capacity );
914 hb_unlock( f->lock );
916 return ret;
919 float hb_fifo_percent_full( hb_fifo_t * f )
921 float ret;
923 hb_lock( f->lock );
924 ret = f->size / f->capacity;
925 hb_unlock( f->lock );
927 return ret;
930 // Pulls the first packet out of this FIFO, blocking until such a packet is available.
931 // Returns NULL if this FIFO has been closed or flushed.
932 hb_buffer_t * hb_fifo_get_wait( hb_fifo_t * f )
934 hb_buffer_t * b;
936 hb_lock( f->lock );
937 if( f->size < 1 )
939 f->wait_empty = 1;
940 hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
941 if( f->size < 1 )
943 hb_unlock( f->lock );
944 return NULL;
947 b = f->first;
948 f->first = b->next;
949 b->next = NULL;
950 f->size -= 1;
951 if( f->wait_full && f->size == f->capacity - f->thresh )
953 f->wait_full = 0;
954 hb_cond_signal( f->cond_full );
956 hb_unlock( f->lock );
958 return b;
961 // Pulls a packet out of this FIFO, or returns NULL if no packet is available.
962 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
964 hb_buffer_t * b;
966 hb_lock( f->lock );
967 if( f->size < 1 )
969 hb_unlock( f->lock );
970 return NULL;
972 b = f->first;
973 f->first = b->next;
974 b->next = NULL;
975 f->size -= 1;
976 if( f->wait_full && f->size == f->capacity - f->thresh )
978 f->wait_full = 0;
979 hb_cond_signal( f->cond_full );
981 hb_unlock( f->lock );
983 return b;
986 hb_buffer_t * hb_fifo_see_wait( hb_fifo_t * f )
988 hb_buffer_t * b;
990 hb_lock( f->lock );
991 if( f->size < 1 )
993 f->wait_empty = 1;
994 hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT );
995 if( f->size < 1 )
997 hb_unlock( f->lock );
998 return NULL;
1001 b = f->first;
1002 hb_unlock( f->lock );
1004 return b;
1007 // Returns the first packet in the specified FIFO.
1008 // If the FIFO is empty, returns NULL.
1009 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
1011 hb_buffer_t * b;
1013 hb_lock( f->lock );
1014 if( f->size < 1 )
1016 hb_unlock( f->lock );
1017 return NULL;
1019 b = f->first;
1020 hb_unlock( f->lock );
1022 return b;
1025 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
1027 hb_buffer_t * b;
1029 hb_lock( f->lock );
1030 if( f->size < 2 )
1032 hb_unlock( f->lock );
1033 return NULL;
1035 b = f->first->next;
1036 hb_unlock( f->lock );
1038 return b;
1041 // Waits until the specified FIFO is no longer full or until FIFO_TIMEOUT milliseconds have elapsed.
1042 // Returns whether the FIFO is non-full upon return.
1043 int hb_fifo_full_wait( hb_fifo_t * f )
1045 int result;
1047 hb_lock( f->lock );
1048 if( f->size >= f->capacity )
1050 f->wait_full = 1;
1051 hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
1053 result = ( f->size < f->capacity );
1054 hb_unlock( f->lock );
1055 return result;
1058 // Pushes the specified buffer onto the specified FIFO,
1059 // blocking until the FIFO has space available.
1060 void hb_fifo_push_wait( hb_fifo_t * f, hb_buffer_t * b )
1062 if( !b )
1064 return;
1067 hb_lock( f->lock );
1068 if( f->size >= f->capacity )
1070 f->wait_full = 1;
1071 if (f->cond_alert_full != NULL)
1072 hb_cond_broadcast( f->cond_alert_full );
1073 hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT );
1075 if( f->size > 0 )
1077 f->last->next = b;
1079 else
1081 f->first = b;
1083 f->last = b;
1084 f->size += 1;
1085 while( f->last->next )
1087 f->size += 1;
1088 f->last = f->last->next;
1090 if( f->wait_empty && f->size >= 1 )
1092 f->wait_empty = 0;
1093 hb_cond_signal( f->cond_empty );
1095 hb_unlock( f->lock );
1098 // Appends the specified packet list to the end of the specified FIFO.
1099 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
1101 if( !b )
1103 return;
1106 hb_lock( f->lock );
1107 if (f->size >= f->capacity &&
1108 f->cond_alert_full != NULL)
1110 hb_cond_broadcast( f->cond_alert_full );
1112 if( f->size > 0 )
1114 f->last->next = b;
1116 else
1118 f->first = b;
1120 f->last = b;
1121 f->size += 1;
1122 while( f->last->next )
1124 f->size += 1;
1125 f->last = f->last->next;
1127 if( f->wait_empty && f->size >= 1 )
1129 f->wait_empty = 0;
1130 hb_cond_signal( f->cond_empty );
1132 hb_unlock( f->lock );
1135 // Prepends the specified packet list to the start of the specified FIFO.
1136 void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b )
1138 hb_buffer_t * tmp;
1139 uint32_t size = 0;
1141 if( !b )
1143 return;
1146 hb_lock( f->lock );
1147 if (f->size >= f->capacity &&
1148 f->cond_alert_full != NULL)
1150 hb_cond_broadcast( f->cond_alert_full );
1154 * If there are a chain of buffers prepend the lot
1156 tmp = b;
1157 while( tmp->next )
1159 tmp = tmp->next;
1160 size += 1;
1163 if( f->size > 0 )
1165 tmp->next = f->first;
1167 else
1169 f->last = tmp;
1172 f->first = b;
1173 f->size += ( size + 1 );
1175 hb_unlock( f->lock );
1178 // Pushes a list of packets onto the specified FIFO as a single element.
1179 void hb_fifo_push_list_element( hb_fifo_t *fifo, hb_buffer_t *buffer_list )
1181 hb_buffer_t *container = hb_buffer_init( 0 );
1182 // XXX: Using an arbitrary hb_buffer_t pointer (other than 'next')
1183 // to carry the list inside a single "container" buffer
1184 container->sub = buffer_list;
1186 hb_fifo_push( fifo, container );
1189 // Removes a list of packets from the specified FIFO that were stored as a single element.
1190 hb_buffer_t *hb_fifo_get_list_element( hb_fifo_t *fifo )
1192 hb_buffer_t *container = hb_fifo_get( fifo );
1193 // XXX: Using an arbitrary hb_buffer_t pointer (other than 'next')
1194 // to carry the list inside a single "container" buffer
1195 hb_buffer_t *buffer_list = container->sub;
1196 hb_buffer_close( &container );
1198 return buffer_list;
1201 void hb_fifo_close( hb_fifo_t ** _f )
1203 hb_fifo_t * f = *_f;
1204 hb_buffer_t * b;
1206 if ( f == NULL )
1207 return;
1209 hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
1210 while( ( b = hb_fifo_get( f ) ) )
1212 hb_buffer_close( &b );
1215 hb_lock_close( &f->lock );
1216 hb_cond_close( &f->cond_empty );
1217 hb_cond_close( &f->cond_full );
1219 #if defined(HB_FIFO_DEBUG)
1220 // Remove the fifo from the global fifo list
1221 fifo_list_rem( f );
1222 #endif
1224 free( f );
1226 *_f = NULL;
1229 void hb_fifo_flush( hb_fifo_t * f )
1231 hb_buffer_t * b;
1233 while( ( b = hb_fifo_get( f ) ) )
1235 hb_buffer_close( &b );
1237 hb_lock( f->lock );
1238 hb_cond_signal( f->cond_empty );
1239 hb_cond_signal( f->cond_full );
1240 hb_unlock( f->lock );