1 /*****************************************************************************
2  * fifo.c: FIFO management functions
3  *****************************************************************************
4  * Copyright (C) 2003-2004 VLC authors and VideoLAN
5  * Copyright (C) 2007-2015 Rémi Denis-Courmont
6  *
7  * Authors: Laurent Aimar <fenrir@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 
28 #include <assert.h>
29 #include <stdlib.h>
30 
31 #include <vlc_common.h>
32 #include <vlc_block.h>
33 #include "libvlc.h"
34 
35 /**
36  * Internal state for block queues
37  */
38 struct block_fifo_t
39 {
40     vlc_mutex_t         lock;                         /* fifo data lock */
41     vlc_cond_t          wait;      /**< Wait for data */
42 
43     block_t             *p_first;
44     block_t             **pp_last;
45     size_t              i_depth;
46     size_t              i_size;
47 };
48 
vlc_fifo_Lock(vlc_fifo_t * fifo)49 void vlc_fifo_Lock(vlc_fifo_t *fifo)
50 {
51     vlc_mutex_lock(&fifo->lock);
52 }
53 
vlc_fifo_Unlock(vlc_fifo_t * fifo)54 void vlc_fifo_Unlock(vlc_fifo_t *fifo)
55 {
56     vlc_mutex_unlock(&fifo->lock);
57 }
58 
vlc_fifo_Signal(vlc_fifo_t * fifo)59 void vlc_fifo_Signal(vlc_fifo_t *fifo)
60 {
61     vlc_cond_signal(&fifo->wait);
62 }
63 
vlc_fifo_Wait(vlc_fifo_t * fifo)64 void vlc_fifo_Wait(vlc_fifo_t *fifo)
65 {
66     vlc_fifo_WaitCond(fifo, &fifo->wait);
67 }
68 
vlc_fifo_WaitCond(vlc_fifo_t * fifo,vlc_cond_t * condvar)69 void vlc_fifo_WaitCond(vlc_fifo_t *fifo, vlc_cond_t *condvar)
70 {
71     vlc_cond_wait(condvar, &fifo->lock);
72 }
73 
vlc_fifo_TimedWaitCond(vlc_fifo_t * fifo,vlc_cond_t * condvar,mtime_t deadline)74 int vlc_fifo_TimedWaitCond(vlc_fifo_t *fifo, vlc_cond_t *condvar, mtime_t deadline)
75 {
76     return vlc_cond_timedwait(condvar, &fifo->lock, deadline);
77 }
78 
vlc_fifo_GetCount(const vlc_fifo_t * fifo)79 size_t vlc_fifo_GetCount(const vlc_fifo_t *fifo)
80 {
81     return fifo->i_depth;
82 }
83 
vlc_fifo_GetBytes(const vlc_fifo_t * fifo)84 size_t vlc_fifo_GetBytes(const vlc_fifo_t *fifo)
85 {
86     return fifo->i_size;
87 }
88 
vlc_fifo_QueueUnlocked(block_fifo_t * fifo,block_t * block)89 void vlc_fifo_QueueUnlocked(block_fifo_t *fifo, block_t *block)
90 {
91     vlc_assert_locked(&fifo->lock);
92     assert(*(fifo->pp_last) == NULL);
93 
94     *(fifo->pp_last) = block;
95 
96     while (block != NULL)
97     {
98         fifo->pp_last = &block->p_next;
99         fifo->i_depth++;
100         fifo->i_size += block->i_buffer;
101 
102         block = block->p_next;
103     }
104 
105     vlc_fifo_Signal(fifo);
106 }
107 
vlc_fifo_DequeueUnlocked(block_fifo_t * fifo)108 block_t *vlc_fifo_DequeueUnlocked(block_fifo_t *fifo)
109 {
110     vlc_assert_locked(&fifo->lock);
111 
112     block_t *block = fifo->p_first;
113 
114     if (block == NULL)
115         return NULL; /* Nothing to do */
116 
117     fifo->p_first = block->p_next;
118     if (block->p_next == NULL)
119         fifo->pp_last = &fifo->p_first;
120     block->p_next = NULL;
121 
122     assert(fifo->i_depth > 0);
123     fifo->i_depth--;
124     assert(fifo->i_size >= block->i_buffer);
125     fifo->i_size -= block->i_buffer;
126 
127     return block;
128 }
129 
vlc_fifo_DequeueAllUnlocked(block_fifo_t * fifo)130 block_t *vlc_fifo_DequeueAllUnlocked(block_fifo_t *fifo)
131 {
132     vlc_assert_locked(&fifo->lock);
133 
134     block_t *block = fifo->p_first;
135 
136     fifo->p_first = NULL;
137     fifo->pp_last = &fifo->p_first;
138     fifo->i_depth = 0;
139     fifo->i_size = 0;
140 
141     return block;
142 }
143 
block_FifoNew(void)144 block_fifo_t *block_FifoNew( void )
145 {
146     block_fifo_t *p_fifo = malloc( sizeof( block_fifo_t ) );
147     if( !p_fifo )
148         return NULL;
149 
150     vlc_mutex_init( &p_fifo->lock );
151     vlc_cond_init( &p_fifo->wait );
152     p_fifo->p_first = NULL;
153     p_fifo->pp_last = &p_fifo->p_first;
154     p_fifo->i_depth = p_fifo->i_size = 0;
155 
156     return p_fifo;
157 }
158 
block_FifoRelease(block_fifo_t * p_fifo)159 void block_FifoRelease( block_fifo_t *p_fifo )
160 {
161     block_ChainRelease( p_fifo->p_first );
162     vlc_cond_destroy( &p_fifo->wait );
163     vlc_mutex_destroy( &p_fifo->lock );
164     free( p_fifo );
165 }
166 
block_FifoEmpty(block_fifo_t * fifo)167 void block_FifoEmpty(block_fifo_t *fifo)
168 {
169     block_t *block;
170 
171     vlc_fifo_Lock(fifo);
172     block = vlc_fifo_DequeueAllUnlocked(fifo);
173     vlc_fifo_Unlock(fifo);
174     block_ChainRelease(block);
175 }
176 
block_FifoPut(block_fifo_t * fifo,block_t * block)177 void block_FifoPut(block_fifo_t *fifo, block_t *block)
178 {
179     vlc_fifo_Lock(fifo);
180     vlc_fifo_QueueUnlocked(fifo, block);
181     vlc_fifo_Unlock(fifo);
182 }
183 
block_FifoGet(block_fifo_t * fifo)184 block_t *block_FifoGet(block_fifo_t *fifo)
185 {
186     block_t *block;
187 
188     vlc_testcancel();
189 
190     vlc_fifo_Lock(fifo);
191     while (vlc_fifo_IsEmpty(fifo))
192     {
193         vlc_fifo_CleanupPush(fifo);
194         vlc_fifo_Wait(fifo);
195         vlc_cleanup_pop();
196     }
197     block = vlc_fifo_DequeueUnlocked(fifo);
198     vlc_fifo_Unlock(fifo);
199 
200     return block;
201 }
202 
block_FifoShow(block_fifo_t * p_fifo)203 block_t *block_FifoShow( block_fifo_t *p_fifo )
204 {
205     block_t *b;
206 
207     vlc_mutex_lock( &p_fifo->lock );
208     assert(p_fifo->p_first != NULL);
209     b = p_fifo->p_first;
210     vlc_mutex_unlock( &p_fifo->lock );
211 
212     return b;
213 }
214 
215 /* FIXME: not (really) thread-safe */
block_FifoSize(block_fifo_t * fifo)216 size_t block_FifoSize (block_fifo_t *fifo)
217 {
218     size_t size;
219 
220     vlc_mutex_lock (&fifo->lock);
221     size = fifo->i_size;
222     vlc_mutex_unlock (&fifo->lock);
223     return size;
224 }
225 
226 /* FIXME: not (really) thread-safe */
block_FifoCount(block_fifo_t * fifo)227 size_t block_FifoCount (block_fifo_t *fifo)
228 {
229     size_t depth;
230 
231     vlc_mutex_lock (&fifo->lock);
232     depth = fifo->i_depth;
233     vlc_mutex_unlock (&fifo->lock);
234     return depth;
235 }
236