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;
-}
--- /dev/null
+/*****************************************************************************
+ * fifo.c: FIFO management functions
+ *****************************************************************************
+ * Copyright (C) 2003-2004 VLC authors and VideoLAN
+ * Copyright (C) 2007-2009 Rémi Denis-Courmont
+ *
+ * Authors: Laurent Aimar <fenrir@videolan.org>
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+
+/**
+ * @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;
+}