From 2d15c90005bd15960ec54bb722592643337d9f4d Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Thu, 19 Mar 2015 19:05:49 +0200 Subject: [PATCH] block: split block_t and block_fifo_t code --- src/Makefile.am | 1 + src/misc/block.c | 252 ----------------------------------------- src/misc/fifo.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 252 deletions(-) create mode 100644 src/misc/fifo.c diff --git a/src/Makefile.am b/src/Makefile.am index 2c5a9817ae..1f02494330 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -442,6 +442,7 @@ SOURCES_libvlc_common = \ misc/rand.c \ misc/mtime.c \ misc/block.c \ + misc/fifo.c \ misc/fourcc.c \ misc/es_format.c \ misc/picture.c \ diff --git a/src/misc/block.c b/src/misc/block.c index 26a2af6da1..bfc5d1dc8f 100644 --- a/src/misc/block.c +++ b/src/misc/block.c @@ -501,255 +501,3 @@ block_t *block_FilePath (const char *path) close (fd); return block; } - -/** - * @section Thread-safe block queue functions - */ - -/** - * Internal state for block queues - */ -struct block_fifo_t -{ - vlc_mutex_t lock; /* fifo data lock */ - vlc_cond_t wait; /**< Wait for data */ - vlc_cond_t wait_room; /**< Wait for queue depth to shrink */ - - block_t *p_first; - block_t **pp_last; - size_t i_depth; - size_t i_size; - bool b_force_wake; -}; - -/** - * Creates a thread-safe FIFO queue of blocks. - * See also block_FifoPut() and block_FifoGet(). - * @return the FIFO or NULL on memory error - */ -block_fifo_t *block_FifoNew( void ) -{ - block_fifo_t *p_fifo = malloc( sizeof( block_fifo_t ) ); - if( !p_fifo ) - return NULL; - - vlc_mutex_init( &p_fifo->lock ); - vlc_cond_init( &p_fifo->wait ); - vlc_cond_init( &p_fifo->wait_room ); - p_fifo->p_first = NULL; - p_fifo->pp_last = &p_fifo->p_first; - p_fifo->i_depth = p_fifo->i_size = 0; - p_fifo->b_force_wake = false; - - return p_fifo; -} - -/** - * Destroys a FIFO created by block_FifoNew(). - * Any queued blocks are also destroyed. - */ -void block_FifoRelease( block_fifo_t *p_fifo ) -{ - block_ChainRelease( p_fifo->p_first ); - vlc_cond_destroy( &p_fifo->wait_room ); - vlc_cond_destroy( &p_fifo->wait ); - vlc_mutex_destroy( &p_fifo->lock ); - free( p_fifo ); -} - -void block_FifoEmpty( block_fifo_t *p_fifo ) -{ - block_t *block; - - vlc_mutex_lock( &p_fifo->lock ); - block = p_fifo->p_first; - if (block != NULL) - { - p_fifo->i_depth = p_fifo->i_size = 0; - p_fifo->p_first = NULL; - p_fifo->pp_last = &p_fifo->p_first; - } - vlc_cond_broadcast( &p_fifo->wait_room ); - vlc_mutex_unlock( &p_fifo->lock ); - - while (block != NULL) - { - block_t *buf; - - buf = block->p_next; - block_Release (block); - block = buf; - } -} - -/** - * Wait until the FIFO gets below a certain size (if needed). - * - * Note that if more than one thread writes to the FIFO, you cannot assume that - * the FIFO is actually below the requested size upon return (since another - * thread could have refilled it already). This is typically not an issue, as - * this function is meant for (relaxed) congestion control. - * - * This function may be a cancellation point and it is cancel-safe. - * - * @param fifo queue to wait on - * @param max_depth wait until the queue has no more than this many blocks - * (use SIZE_MAX to ignore this constraint) - * @param max_size wait until the queue has no more than this many bytes - * (use SIZE_MAX to ignore this constraint) - * @return nothing. - */ -void block_FifoPace (block_fifo_t *fifo, size_t max_depth, size_t max_size) -{ - vlc_testcancel (); - - vlc_mutex_lock (&fifo->lock); - while ((fifo->i_depth > max_depth) || (fifo->i_size > max_size)) - { - mutex_cleanup_push (&fifo->lock); - vlc_cond_wait (&fifo->wait_room, &fifo->lock); - vlc_cleanup_pop (); - } - vlc_mutex_unlock (&fifo->lock); -} - -/** - * Immediately queue one block at the end of a FIFO. - * @param fifo queue - * @param block head of a block list to queue (may be NULL) - * @return total number of bytes appended to the queue - */ -size_t block_FifoPut( block_fifo_t *p_fifo, block_t *p_block ) -{ - size_t i_size = 0, i_depth = 0; - block_t *p_last; - - if (p_block == NULL) - return 0; - for (p_last = p_block; ; p_last = p_last->p_next) - { - i_size += p_last->i_buffer; - i_depth++; - if (!p_last->p_next) - break; - } - - vlc_mutex_lock (&p_fifo->lock); - *p_fifo->pp_last = p_block; - p_fifo->pp_last = &p_last->p_next; - p_fifo->i_depth += i_depth; - p_fifo->i_size += i_size; - /* We queued at least one block: wake up one read-waiting thread */ - vlc_cond_signal( &p_fifo->wait ); - vlc_mutex_unlock( &p_fifo->lock ); - - return i_size; -} - -void block_FifoWake( block_fifo_t *p_fifo ) -{ - vlc_mutex_lock( &p_fifo->lock ); - if( p_fifo->p_first == NULL ) - p_fifo->b_force_wake = true; - vlc_cond_broadcast( &p_fifo->wait ); - vlc_mutex_unlock( &p_fifo->lock ); -} - -/** - * Dequeue the first block from the FIFO. If necessary, wait until there is - * one block in the queue. This function is (always) cancellation point. - * - * @return a valid block, or NULL if block_FifoWake() was called. - */ -block_t *block_FifoGet( block_fifo_t *p_fifo ) -{ - block_t *b; - - vlc_testcancel( ); - - vlc_mutex_lock( &p_fifo->lock ); - mutex_cleanup_push( &p_fifo->lock ); - - /* Remember vlc_cond_wait() may cause spurious wakeups - * (on both Win32 and POSIX) */ - while( ( p_fifo->p_first == NULL ) && !p_fifo->b_force_wake ) - vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); - - vlc_cleanup_pop(); - b = p_fifo->p_first; - - p_fifo->b_force_wake = false; - if( b == NULL ) - { - /* Forced wakeup */ - vlc_mutex_unlock( &p_fifo->lock ); - return NULL; - } - - p_fifo->p_first = b->p_next; - p_fifo->i_depth--; - p_fifo->i_size -= b->i_buffer; - - if( p_fifo->p_first == NULL ) - { - p_fifo->pp_last = &p_fifo->p_first; - } - - /* We don't know how many threads can queue new packets now. */ - vlc_cond_broadcast( &p_fifo->wait_room ); - vlc_mutex_unlock( &p_fifo->lock ); - - b->p_next = NULL; - return b; -} - -/** - * Peeks the first block in the FIFO. - * If necessary, wait until there is one block. - * This function is (always) a cancellation point. - * - * @warning This function leaves the block in the FIFO. - * You need to protect against concurrent threads who could dequeue the block. - * Preferrably, there should be only one thread reading from the FIFO. - * - * @return a valid block. - */ -block_t *block_FifoShow( block_fifo_t *p_fifo ) -{ - block_t *b; - - vlc_testcancel( ); - - vlc_mutex_lock( &p_fifo->lock ); - mutex_cleanup_push( &p_fifo->lock ); - - while( p_fifo->p_first == NULL ) - vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); - - b = p_fifo->p_first; - - vlc_cleanup_run (); - return b; -} - -/* FIXME: not (really) thread-safe */ -size_t block_FifoSize (block_fifo_t *fifo) -{ - size_t size; - - vlc_mutex_lock (&fifo->lock); - size = fifo->i_size; - vlc_mutex_unlock (&fifo->lock); - return size; -} - -/* FIXME: not (really) thread-safe */ -size_t block_FifoCount (block_fifo_t *fifo) -{ - size_t depth; - - vlc_mutex_lock (&fifo->lock); - depth = fifo->i_depth; - vlc_mutex_unlock (&fifo->lock); - return depth; -} diff --git a/src/misc/fifo.c b/src/misc/fifo.c new file mode 100644 index 0000000000..0c927a1419 --- /dev/null +++ b/src/misc/fifo.c @@ -0,0 +1,284 @@ +/***************************************************************************** + * fifo.c: FIFO management functions + ***************************************************************************** + * Copyright (C) 2003-2004 VLC authors and VideoLAN + * Copyright (C) 2007-2009 Rémi Denis-Courmont + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include + +/** + * @section Thread-safe block queue functions + */ + +/** + * Internal state for block queues + */ +struct block_fifo_t +{ + vlc_mutex_t lock; /* fifo data lock */ + vlc_cond_t wait; /**< Wait for data */ + vlc_cond_t wait_room; /**< Wait for queue depth to shrink */ + + block_t *p_first; + block_t **pp_last; + size_t i_depth; + size_t i_size; + bool b_force_wake; +}; + +/** + * Creates a thread-safe FIFO queue of blocks. + * See also block_FifoPut() and block_FifoGet(). + * @return the FIFO or NULL on memory error + */ +block_fifo_t *block_FifoNew( void ) +{ + block_fifo_t *p_fifo = malloc( sizeof( block_fifo_t ) ); + if( !p_fifo ) + return NULL; + + vlc_mutex_init( &p_fifo->lock ); + vlc_cond_init( &p_fifo->wait ); + vlc_cond_init( &p_fifo->wait_room ); + p_fifo->p_first = NULL; + p_fifo->pp_last = &p_fifo->p_first; + p_fifo->i_depth = p_fifo->i_size = 0; + p_fifo->b_force_wake = false; + + return p_fifo; +} + +/** + * Destroys a FIFO created by block_FifoNew(). + * Any queued blocks are also destroyed. + */ +void block_FifoRelease( block_fifo_t *p_fifo ) +{ + block_ChainRelease( p_fifo->p_first ); + vlc_cond_destroy( &p_fifo->wait_room ); + vlc_cond_destroy( &p_fifo->wait ); + vlc_mutex_destroy( &p_fifo->lock ); + free( p_fifo ); +} + +void block_FifoEmpty( block_fifo_t *p_fifo ) +{ + block_t *block; + + vlc_mutex_lock( &p_fifo->lock ); + block = p_fifo->p_first; + if (block != NULL) + { + p_fifo->i_depth = p_fifo->i_size = 0; + p_fifo->p_first = NULL; + p_fifo->pp_last = &p_fifo->p_first; + } + vlc_cond_broadcast( &p_fifo->wait_room ); + vlc_mutex_unlock( &p_fifo->lock ); + + while (block != NULL) + { + block_t *buf; + + buf = block->p_next; + block_Release (block); + block = buf; + } +} + +/** + * Wait until the FIFO gets below a certain size (if needed). + * + * Note that if more than one thread writes to the FIFO, you cannot assume that + * the FIFO is actually below the requested size upon return (since another + * thread could have refilled it already). This is typically not an issue, as + * this function is meant for (relaxed) congestion control. + * + * This function may be a cancellation point and it is cancel-safe. + * + * @param fifo queue to wait on + * @param max_depth wait until the queue has no more than this many blocks + * (use SIZE_MAX to ignore this constraint) + * @param max_size wait until the queue has no more than this many bytes + * (use SIZE_MAX to ignore this constraint) + * @return nothing. + */ +void block_FifoPace (block_fifo_t *fifo, size_t max_depth, size_t max_size) +{ + vlc_testcancel (); + + vlc_mutex_lock (&fifo->lock); + while ((fifo->i_depth > max_depth) || (fifo->i_size > max_size)) + { + mutex_cleanup_push (&fifo->lock); + vlc_cond_wait (&fifo->wait_room, &fifo->lock); + vlc_cleanup_pop (); + } + vlc_mutex_unlock (&fifo->lock); +} + +/** + * Immediately queue one block at the end of a FIFO. + * @param fifo queue + * @param block head of a block list to queue (may be NULL) + * @return total number of bytes appended to the queue + */ +size_t block_FifoPut( block_fifo_t *p_fifo, block_t *p_block ) +{ + size_t i_size = 0, i_depth = 0; + block_t *p_last; + + if (p_block == NULL) + return 0; + for (p_last = p_block; ; p_last = p_last->p_next) + { + i_size += p_last->i_buffer; + i_depth++; + if (!p_last->p_next) + break; + } + + vlc_mutex_lock (&p_fifo->lock); + *p_fifo->pp_last = p_block; + p_fifo->pp_last = &p_last->p_next; + p_fifo->i_depth += i_depth; + p_fifo->i_size += i_size; + /* We queued at least one block: wake up one read-waiting thread */ + vlc_cond_signal( &p_fifo->wait ); + vlc_mutex_unlock( &p_fifo->lock ); + + return i_size; +} + +void block_FifoWake( block_fifo_t *p_fifo ) +{ + vlc_mutex_lock( &p_fifo->lock ); + if( p_fifo->p_first == NULL ) + p_fifo->b_force_wake = true; + vlc_cond_broadcast( &p_fifo->wait ); + vlc_mutex_unlock( &p_fifo->lock ); +} + +/** + * Dequeue the first block from the FIFO. If necessary, wait until there is + * one block in the queue. This function is (always) cancellation point. + * + * @return a valid block, or NULL if block_FifoWake() was called. + */ +block_t *block_FifoGet( block_fifo_t *p_fifo ) +{ + block_t *b; + + vlc_testcancel( ); + + vlc_mutex_lock( &p_fifo->lock ); + mutex_cleanup_push( &p_fifo->lock ); + + /* Remember vlc_cond_wait() may cause spurious wakeups + * (on both Win32 and POSIX) */ + while( ( p_fifo->p_first == NULL ) && !p_fifo->b_force_wake ) + vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); + + vlc_cleanup_pop(); + b = p_fifo->p_first; + + p_fifo->b_force_wake = false; + if( b == NULL ) + { + /* Forced wakeup */ + vlc_mutex_unlock( &p_fifo->lock ); + return NULL; + } + + p_fifo->p_first = b->p_next; + p_fifo->i_depth--; + p_fifo->i_size -= b->i_buffer; + + if( p_fifo->p_first == NULL ) + { + p_fifo->pp_last = &p_fifo->p_first; + } + + /* We don't know how many threads can queue new packets now. */ + vlc_cond_broadcast( &p_fifo->wait_room ); + vlc_mutex_unlock( &p_fifo->lock ); + + b->p_next = NULL; + return b; +} + +/** + * Peeks the first block in the FIFO. + * If necessary, wait until there is one block. + * This function is (always) a cancellation point. + * + * @warning This function leaves the block in the FIFO. + * You need to protect against concurrent threads who could dequeue the block. + * Preferrably, there should be only one thread reading from the FIFO. + * + * @return a valid block. + */ +block_t *block_FifoShow( block_fifo_t *p_fifo ) +{ + block_t *b; + + vlc_testcancel( ); + + vlc_mutex_lock( &p_fifo->lock ); + mutex_cleanup_push( &p_fifo->lock ); + + while( p_fifo->p_first == NULL ) + vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); + + b = p_fifo->p_first; + + vlc_cleanup_run (); + return b; +} + +/* FIXME: not (really) thread-safe */ +size_t block_FifoSize (block_fifo_t *fifo) +{ + size_t size; + + vlc_mutex_lock (&fifo->lock); + size = fifo->i_size; + vlc_mutex_unlock (&fifo->lock); + return size; +} + +/* FIXME: not (really) thread-safe */ +size_t block_FifoCount (block_fifo_t *fifo) +{ + size_t depth; + + vlc_mutex_lock (&fifo->lock); + depth = fifo->i_depth; + vlc_mutex_unlock (&fifo->lock); + return depth; +} -- 2.39.2