vlc | branch: master | Rémi Denis-Courmont <[email protected]> | Tue Feb 24 23:07:36 2015 +0200| [26d23afcec399aacc37badcdea105399cd89c4a8] | committer: Rémi Denis-Courmont
block: add low-level functions for block FIFOs In some cases, the thread(s) consuming a FIFO needs to wake up in other circumstances than the FIFO being non-empty. For that purpose, this new set of functions is vastly more flexible than block_FifoWake(). > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=26d23afcec399aacc37badcdea105399cd89c4a8 --- include/vlc_block.h | 24 +++++++ src/libvlccore.sym | 10 +++ src/misc/fifo.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 225 insertions(+), 1 deletion(-) diff --git a/include/vlc_block.h b/include/vlc_block.h index ba113d4..b62fd69 100644 --- a/include/vlc_block.h +++ b/include/vlc_block.h @@ -320,4 +320,28 @@ VLC_API block_t * block_FifoShow( block_fifo_t * ); size_t block_FifoSize(block_fifo_t *) VLC_USED; VLC_API size_t block_FifoCount(block_fifo_t *) VLC_USED; +typedef struct block_fifo_t vlc_fifo_t; + +VLC_API void vlc_fifo_Lock(vlc_fifo_t *); +VLC_API void vlc_fifo_Unlock(vlc_fifo_t *); +VLC_API void vlc_fifo_Signal(vlc_fifo_t *); +VLC_API void vlc_fifo_Wait(vlc_fifo_t *); +VLC_API void vlc_fifo_WaitCond(vlc_fifo_t *, vlc_cond_t *); +VLC_API void vlc_fifo_QueueUnlocked(vlc_fifo_t *, block_t *); +VLC_API block_t *vlc_fifo_DequeueUnlocked(vlc_fifo_t *) VLC_USED; +VLC_API block_t *vlc_fifo_DequeueAllUnlocked(vlc_fifo_t *) VLC_USED; +VLC_API size_t vlc_fifo_GetCount(const vlc_fifo_t *) VLC_USED; +VLC_API size_t vlc_fifo_GetBytes(const vlc_fifo_t *) VLC_USED; + +VLC_USED static inline bool vlc_fifo_IsEmpty(const vlc_fifo_t *fifo) +{ + return vlc_fifo_GetCount(fifo) == 0; +} + +static inline void vlc_fifo_Cleanup(void *fifo) +{ + vlc_fifo_Unlock((vlc_fifo_t *)fifo); +} +#define vlc_fifo_CleanupPush(fifo) vlc_cleanup_push(vlc_fifo_Cleanup, fifo) + #endif /* VLC_BLOCK_H */ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 7f06ed6..943c570 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -596,6 +596,16 @@ vlc_epg_Delete vlc_epg_AddEvent vlc_epg_SetCurrent vlc_epg_Merge +vlc_fifo_Lock +vlc_fifo_Unlock +vlc_fifo_Signal +vlc_fifo_Wait +vlc_fifo_WaitCond +vlc_fifo_QueueUnlocked +vlc_fifo_DequeueUnlocked +vlc_fifo_DequeueAllUnlocked +vlc_fifo_GetCount +vlc_fifo_GetBytes vlc_gl_Create vlc_gl_Destroy vlc_gl_surface_Create diff --git a/src/misc/fifo.c b/src/misc/fifo.c index 0c927a1..39b2bca 100644 --- a/src/misc/fifo.c +++ b/src/misc/fifo.c @@ -2,7 +2,7 @@ * fifo.c: FIFO management functions ***************************************************************************** * Copyright (C) 2003-2004 VLC authors and VideoLAN - * Copyright (C) 2007-2009 Rémi Denis-Courmont + * Copyright (C) 2007-2015 Rémi Denis-Courmont * * Authors: Laurent Aimar <[email protected]> * @@ -30,6 +30,7 @@ #include <vlc_common.h> #include <vlc_block.h> +#include "libvlc.h" /** * @section Thread-safe block queue functions @@ -52,6 +53,195 @@ struct block_fifo_t }; /** + * Locks a block FIFO. No more than one thread can lock the FIFO at any given + * time, and no other thread can modify the FIFO while it is locked. + * vlc_fifo_Unlock() releases the lock. + * + * @note If the FIFO is already locked by another thread, this function waits. + * This function is not a cancellation point. + * + * @warning Recursively locking a single FIFO is undefined. Locking more than + * one FIFO at a time may lead to lock inversion; mind the locking order. + */ +void vlc_fifo_Lock(vlc_fifo_t *fifo) +{ + vlc_mutex_lock(&fifo->lock); +} + +/** + * Unlocks a block FIFO previously locked by block_FifoLock(). + * + * @note This function is not a cancellation point. + * + * @warning Unlocking a FIFO not locked by the calling thread is undefined. + */ +void vlc_fifo_Unlock(vlc_fifo_t *fifo) +{ + vlc_mutex_unlock(&fifo->lock); +} + +/** + * Wakes up one thread waiting on the FIFO, if any. + * + * @note This function is not a cancellation point. + * + * @warning For race-free operations, the FIFO should be locked by the calling + * thread. The function can be called on a unlocked FIFO however. + */ +void vlc_fifo_Signal(vlc_fifo_t *fifo) +{ + vlc_cond_signal(&fifo->wait); +} + +/** + * Atomically unlocks the FIFO and waits until one thread signals the FIFO, + * then locks the FIFO again. A signal can be sent by queueing a block to the + * previously empty FIFO or by calling vlc_fifo_Signal() directly. + * This function may also return spuriously at any moment. + * + * @note This function is a cancellation point. In case of cancellation, the + * the FIFO will be locked before cancellation cleanup handlers are processed. + */ +void vlc_fifo_Wait(vlc_fifo_t *fifo) +{ + vlc_fifo_WaitCond(fifo, &fifo->wait); +} + +void vlc_fifo_WaitCond(vlc_fifo_t *fifo, vlc_cond_t *condvar) +{ + vlc_cond_wait(condvar, &fifo->lock); +} + +/** + * Checks how many blocks are queued in a locked FIFO. + * + * @note This function is not cancellation point. + * + * @warning The FIFO must be locked by the calling thread using + * vlc_fifo_Lock(). Otherwise behaviour is undefined. + * + * @return the number of blocks in the FIFO (zero if it is empty) + */ +size_t vlc_fifo_GetCount(const vlc_fifo_t *fifo) +{ + return fifo->i_depth; +} + +/** + * Checks how many bytes are queued in a locked FIFO. + * + * @note This function is not cancellation point. + * + * @warning The FIFO must be locked by the calling thread using + * vlc_fifo_Lock(). Otherwise behaviour is undefined. + * + * @return the total number of bytes + * + * @note Zero bytes does not necessarily mean that the FIFO is empty since + * a block could contain zero bytes. Use vlc_fifo_GetCount() to determine if + * a FIFO is empty. + */ +size_t vlc_fifo_GetBytes(const vlc_fifo_t *fifo) +{ + return fifo->i_size; +} + +/** + * Queues a linked-list of blocks into a locked FIFO. + * + * @param block the head of the list of blocks + * (if NULL, this function has no effects) + * + * @note This function is not a cancellation point. + * + * @warning The FIFO must be locked by the calling thread using + * vlc_fifo_Lock(). Otherwise behaviour is undefined. + */ +void vlc_fifo_QueueUnlocked(block_fifo_t *fifo, block_t *block) +{ + vlc_assert_locked(&fifo->lock); + assert(*(fifo->pp_last) == NULL); + + *(fifo->pp_last) = block; + + while (block != NULL) + { + fifo->pp_last = &block->p_next; + fifo->i_depth++; + fifo->i_size += block->i_size; + + block = block->p_next; + } + + vlc_cond_signal(&fifo->wait); +} + +/** + * Dequeues the first block from a locked FIFO, if any. + * + * @note This function is not a cancellation point. + * + * @warning The FIFO must be locked by the calling thread using + * vlc_fifo_Lock(). Otherwise behaviour is undefined. + * + * @return the first block in the FIFO or NULL if the FIFO is empty + */ +block_t *vlc_fifo_DequeueUnlocked(block_fifo_t *fifo) +{ + vlc_assert_locked(&fifo->lock); + + block_t *block = fifo->p_first; + + if (block == NULL) + return NULL; /* Nothing to do */ + + fifo->p_first = block->p_next; + if (block->p_next == NULL) + fifo->pp_last = &fifo->p_first; + block->p_next = NULL; + + assert(fifo->i_depth > 0); + fifo->i_depth--; + assert(fifo->i_size >= block->i_buffer); + fifo->i_size -= block->i_buffer; + + /* We don't know how many threads can queue new packets now. */ + vlc_cond_broadcast(&fifo->wait_room); + + return block; +} + +/** + * Dequeues the all blocks from a locked FIFO. This is equivalent to calling + * vlc_fifo_DequeueUnlocked() repeatedly until the FIFO is emptied, but this + * function is faster. + * + * @note This function is not a cancellation point. + * + * @warning The FIFO must be locked by the calling thread using + * vlc_fifo_Lock(). Otherwise behaviour is undefined. + * + * @return a linked-list of all blocks in the FIFO (possibly NULL) + */ +block_t *vlc_fifo_DequeueAllUnlocked(block_fifo_t *fifo) +{ + vlc_assert_locked(&fifo->lock); + + block_t *block = fifo->p_first; + + fifo->p_first = NULL; + fifo->pp_last = &fifo->p_first; + fifo->i_depth = 0; + fifo->i_size = 0; + + /* We don't know how many threads can queue new packets now. */ + vlc_cond_broadcast(&fifo->wait_room); + + return block; +} + + +/** * Creates a thread-safe FIFO queue of blocks. * See also block_FifoPut() and block_FifoGet(). * @return the FIFO or NULL on memory error _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
