root/trunk/libffado/src/libutil/ringbuffer.c

Revision 2802, 8.8 kB (checked in by jwoithe, 3 years ago)

Cosmetic: "Firewire" becomes "FireWire?".

Officially both the "F" and "W" were capitalised in the FireWire? name, so
reflect this throughout FFADO's source tree. This mostly affects comments.

This patch originated from pander on the ffado-devel mailing list. To
maintain consistency, the committed version has been expanded to include
files not originally included in the original patch.

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.