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