root/branches/libffado-2.0/src/libutil/ringbuffer.c

Revision 1360, 8.8 kB (checked in by ppalmers, 12 years ago)

temporarily fix ringbuffer thread safeness issue pointed out for jack ringbuffer on LAU/LAD

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /*
25  * Copied from the jackd sources
26  * function names changed in order to avoid naming problems when using this in
27  * a jackd backend.
28  */
29
30 /* Original license:
31  * note that LGPL2.1 allows relicensing the code to GPLv3 or higher
32  *
33  *  Copyright (C) 2000 Paul Davis
34  *  Copyright (C) 2003 Rohan Drape
35  *
36  *  This program is free software; you can redistribute it and/or modify
37  *  it under the terms of the GNU Lesser General Public License as published by
38  *  the Free Software Foundation; either version 2.1 of the License, or
39  *  (at your option) version 3 of the License.
40  *
41  *  This program is distributed in the hope that it will be useful,
42  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
43  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44  *  GNU Lesser General Public License for more details.
45  *
46  *  You should have received a copy of the GNU Lesser General Public License
47  *  along with this program; if not, write to the Free Software
48  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
49  *
50  */
51
52 //#include <config.h>
53
54 #include <stdlib.h>
55 #include <string.h>
56 #ifdef USE_MLOCK
57 #include <sys/mman.h>
58 #endif /* USE_MLOCK */
59 #include "ringbuffer.h"
60
61 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
62    actual buffer size is rounded up to the next power of two.  */
63
64 ffado_ringbuffer_t *
65 ffado_ringbuffer_create (size_t sz)
66 {
67   int power_of_two;
68   ffado_ringbuffer_t *rb;
69
70   rb = malloc (sizeof (ffado_ringbuffer_t));
71
72   for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
73
74   rb->size = 1 << power_of_two;
75   rb->size_mask = rb->size;
76   rb->size_mask -= 1;
77   rb->write_ptr = 0;
78   rb->read_ptr = 0;
79   rb->buf = malloc (rb->size);
80   rb->mlocked = 0;
81
82   return rb;
83 }
84
85 /* Free all data associated with the ringbuffer `rb'. */
86
87 void
88 ffado_ringbuffer_free (ffado_ringbuffer_t * rb)
89 {
90 #ifdef USE_MLOCK
91   if (rb->mlocked) {
92     munlock (rb->buf, rb->size);
93   }
94 #endif /* USE_MLOCK */
95   free (rb->buf);
96 }
97
98 /* Lock the data block of `rb' using the system call 'mlock'.  */
99
100 int
101 ffado_ringbuffer_mlock (ffado_ringbuffer_t * rb)
102 {
103 #ifdef USE_MLOCK
104   if (mlock (rb->buf, rb->size)) {
105     return -1;
106   }
107 #endif /* USE_MLOCK */
108   rb->mlocked = 1;
109   return 0;
110 }
111
112 /* Reset the read and write pointers to zero. This is not thread
113    safe. */
114
115 void
116 ffado_ringbuffer_reset (ffado_ringbuffer_t * rb)
117 {
118   rb->read_ptr = 0;
119   rb->write_ptr = 0;
120 }
121
122 /* Return the number of bytes available for reading.  This is the
123    number of bytes in front of the read pointer and behind the write
124    pointer.  */
125
126 size_t
127 ffado_ringbuffer_read_space (const ffado_ringbuffer_t * rb)
128 {
129   size_t w, r;
130
131   w = rb->write_ptr;
132   r = rb->read_ptr;
133
134   if (w > r) {
135     return w - r;
136   } else {
137     return (w - r + rb->size) & rb->size_mask;
138   }
139 }
140
141 /* Return the number of bytes available for writing.  This is the
142    number of bytes in front of the write pointer and behind the read
143    pointer.  */
144
145 size_t
146 ffado_ringbuffer_write_space (const ffado_ringbuffer_t * rb)
147 {
148   size_t w, r;
149
150   w = rb->write_ptr;
151   r = rb->read_ptr;
152
153   if (w > r) {
154     return ((r - w + rb->size) & rb->size_mask) - 1;
155   } else if (w < r) {
156     return (r - w) - 1;
157   } else {
158     return rb->size - 1;
159   }
160 }
161
162 /* The copying data reader.  Copy at most `cnt' bytes from `rb' to
163    `dest'.  Returns the actual number of bytes copied. */
164
165 size_t
166 ffado_ringbuffer_read (ffado_ringbuffer_t * rb, char *dest, size_t cnt)
167 {
168   size_t free_cnt;
169   size_t cnt2;
170   size_t to_read;
171   size_t n1, n2;
172
173   if ((free_cnt = ffado_ringbuffer_read_space (rb)) == 0) {
174     return 0;
175   }
176
177   to_read = cnt > free_cnt ? free_cnt : cnt;
178
179   cnt2 = rb->read_ptr + to_read;
180
181   if (cnt2 > rb->size) {
182     n1 = rb->size - rb->read_ptr;
183     n2 = cnt2 & rb->size_mask;
184   } else {
185     n1 = to_read;
186     n2 = 0;
187   }
188
189   memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
190   rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
191
192   if (n2) {
193     memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
194     rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
195   }
196
197   return to_read;
198 }
199
200 /* The copying data reader w/o read pointer advance.  Copy at most
201    `cnt' bytes from `rb' to `dest'.  Returns the actual number of bytes
202 copied. */
203
204 size_t
205 ffado_ringbuffer_peek (ffado_ringbuffer_t * rb, char *dest, size_t cnt)
206 {
207   size_t free_cnt;
208   size_t cnt2;
209   size_t to_read;
210   size_t n1, n2;
211   size_t tmp_read_ptr;
212
213   tmp_read_ptr = rb->read_ptr;
214
215   if ((free_cnt = ffado_ringbuffer_read_space (rb)) == 0) {
216     return 0;
217   }
218
219   to_read = cnt > free_cnt ? free_cnt : cnt;
220
221   cnt2 = tmp_read_ptr + to_read;
222
223   if (cnt2 > rb->size) {
224     n1 = rb->size - tmp_read_ptr;
225     n2 = cnt2 & rb->size_mask;
226   } else {
227     n1 = to_read;
228     n2 = 0;
229   }
230
231   memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
232   tmp_read_ptr += n1;
233   tmp_read_ptr &= rb->size_mask;
234
235   if (n2) {
236     memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
237     // FIXME: tmp_read_ptr is not used anymore
238     tmp_read_ptr += n2;
239     tmp_read_ptr &= rb->size_mask;
240   }
241
242   return to_read;
243 }
244
245
246 /* The copying data writer.  Copy at most `cnt' bytes to `rb' from
247    `src'.  Returns the actual number of bytes copied. */
248
249 size_t
250 ffado_ringbuffer_write (ffado_ringbuffer_t * rb, const char *src, size_t cnt)
251 {
252   size_t free_cnt;
253   size_t cnt2;
254   size_t to_write;
255   size_t n1, n2;
256
257   if ((free_cnt = ffado_ringbuffer_write_space (rb)) == 0) {
258     return 0;
259   }
260
261   to_write = cnt > free_cnt ? free_cnt : cnt;
262
263   cnt2 = rb->write_ptr + to_write;
264
265   if (cnt2 > rb->size) {
266     n1 = rb->size - rb->write_ptr;
267     n2 = cnt2 & rb->size_mask;
268   } else {
269     n1 = to_write;
270     n2 = 0;
271   }
272
273   memcpy (&(rb->buf[rb->write_ptr]), src, n1);
274   rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
275
276   if (n2) {
277     memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
278     rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
279   }
280
281   return to_write;
282 }
283
284 /* Advance the read pointer `cnt' places. */
285
286 void
287 ffado_ringbuffer_read_advance (ffado_ringbuffer_t * rb, size_t cnt)
288 {
289   rb->read_ptr = (rb->read_ptr + cnt) & rb->size_mask;
290 }
291
292 /* Advance the write pointer `cnt' places. */
293
294 void
295 ffado_ringbuffer_write_advance (ffado_ringbuffer_t * rb, size_t cnt)
296 {
297   rb->write_ptr = (rb->write_ptr + cnt) & rb->size_mask;
298 }
299
300 /* The non-copying data reader.  `vec' is an array of two places.  Set
301    the values at `vec' to hold the current readable data at `rb'.  If
302    the readable data is in one segment the second segment has zero
303    length.  */
304
305 void
306 ffado_ringbuffer_get_read_vector (const ffado_ringbuffer_t * rb,
307                                  ffado_ringbuffer_data_t * vec)
308 {
309   size_t free_cnt;
310   size_t cnt2;
311   size_t w, r;
312
313   w = rb->write_ptr;
314   r = rb->read_ptr;
315
316   if (w > r) {
317     free_cnt = w - r;
318   } else {
319     free_cnt = (w - r + rb->size) & rb->size_mask;
320   }
321
322   cnt2 = r + free_cnt;
323
324   if (cnt2 > rb->size) {
325
326     /* Two part vector: the rest of the buffer after the current write
327        ptr, plus some from the start of the buffer. */
328
329     vec[0].buf = &(rb->buf[r]);
330     vec[0].len = rb->size - r;
331     vec[1].buf = rb->buf;
332     vec[1].len = cnt2 & rb->size_mask;
333
334   } else {
335
336     /* Single part vector: just the rest of the buffer */
337
338     vec[0].buf = &(rb->buf[r]);
339     vec[0].len = free_cnt;
340     vec[1].len = 0;
341   }
342 }
343
344 /* The non-copying data writer.  `vec' is an array of two places.  Set
345    the values at `vec' to hold the current writeable data at `rb'.  If
346    the writeable data is in one segment the second segment has zero
347    length.  */
348
349 void
350 ffado_ringbuffer_get_write_vector (const ffado_ringbuffer_t * rb,
351                                   ffado_ringbuffer_data_t * vec)
352 {
353   size_t free_cnt;
354   size_t cnt2;
355   size_t w, r;
356
357   w = rb->write_ptr;
358   r = rb->read_ptr;
359
360   if (w > r) {
361     free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
362   } else if (w < r) {
363     free_cnt = (r - w) - 1;
364   } else {
365     free_cnt = rb->size - 1;
366   }
367
368   cnt2 = w + free_cnt;
369
370   if (cnt2 > rb->size) {
371
372     /* Two part vector: the rest of the buffer after the current write
373        ptr, plus some from the start of the buffer. */
374
375     vec[0].buf = &(rb->buf[w]);
376     vec[0].len = rb->size - w;
377     vec[1].buf = rb->buf;
378     vec[1].len = cnt2 & rb->size_mask;
379   } else {
380     vec[0].buf = &(rb->buf[w]);
381     vec[0].len = free_cnt;
382     vec[1].len = 0;
383   }
384 }
Note: See TracBrowser for help on using the browser.