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

Revision 864, 8.8 kB (checked in by ppalmers, 15 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

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 += n1;
191   rb->read_ptr &= rb->size_mask;
192
193   if (n2) {
194     memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
195     rb->read_ptr += n2;
196     rb->read_ptr &= rb->size_mask;
197   }
198
199   return to_read;
200 }
201
202 /* The copying data reader w/o read pointer advance.  Copy at most
203    `cnt' bytes from `rb' to `dest'.  Returns the actual number of bytes
204 copied. */
205
206 size_t
207 ffado_ringbuffer_peek (ffado_ringbuffer_t * rb, char *dest, size_t cnt)
208 {
209   size_t free_cnt;
210   size_t cnt2;
211   size_t to_read;
212   size_t n1, n2;
213   size_t tmp_read_ptr;
214
215   tmp_read_ptr = rb->read_ptr;
216
217   if ((free_cnt = ffado_ringbuffer_read_space (rb)) == 0) {
218     return 0;
219   }
220
221   to_read = cnt > free_cnt ? free_cnt : cnt;
222
223   cnt2 = tmp_read_ptr + to_read;
224
225   if (cnt2 > rb->size) {
226     n1 = rb->size - tmp_read_ptr;
227     n2 = cnt2 & rb->size_mask;
228   } else {
229     n1 = to_read;
230     n2 = 0;
231   }
232
233   memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
234   tmp_read_ptr += n1;
235   tmp_read_ptr &= rb->size_mask;
236
237   if (n2) {
238     memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
239     tmp_read_ptr += n2;
240     tmp_read_ptr &= rb->size_mask;
241   }
242
243   return to_read;
244 }
245
246
247 /* The copying data writer.  Copy at most `cnt' bytes to `rb' from
248    `src'.  Returns the actual number of bytes copied. */
249
250 size_t
251 ffado_ringbuffer_write (ffado_ringbuffer_t * rb, const char *src, size_t cnt)
252 {
253   size_t free_cnt;
254   size_t cnt2;
255   size_t to_write;
256   size_t n1, n2;
257
258   if ((free_cnt = ffado_ringbuffer_write_space (rb)) == 0) {
259     return 0;
260   }
261
262   to_write = cnt > free_cnt ? free_cnt : cnt;
263
264   cnt2 = rb->write_ptr + to_write;
265
266   if (cnt2 > rb->size) {
267     n1 = rb->size - rb->write_ptr;
268     n2 = cnt2 & rb->size_mask;
269   } else {
270     n1 = to_write;
271     n2 = 0;
272   }
273
274   memcpy (&(rb->buf[rb->write_ptr]), src, n1);
275   rb->write_ptr += n1;
276   rb->write_ptr &= rb->size_mask;
277
278   if (n2) {
279     memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
280     rb->write_ptr += n2;
281     rb->write_ptr &= rb->size_mask;
282   }
283
284   return to_write;
285 }
286
287 /* Advance the read pointer `cnt' places. */
288
289 void
290 ffado_ringbuffer_read_advance (ffado_ringbuffer_t * rb, size_t cnt)
291 {
292   rb->read_ptr += cnt;
293   rb->read_ptr &= rb->size_mask;
294 }
295
296 /* Advance the write pointer `cnt' places. */
297
298 void
299 ffado_ringbuffer_write_advance (ffado_ringbuffer_t * rb, size_t cnt)
300 {
301   rb->write_ptr += cnt;
302   rb->write_ptr &= rb->size_mask;
303 }
304
305 /* The non-copying data reader.  `vec' is an array of two places.  Set
306    the values at `vec' to hold the current readable data at `rb'.  If
307    the readable data is in one segment the second segment has zero
308    length.  */
309
310 void
311 ffado_ringbuffer_get_read_vector (const ffado_ringbuffer_t * rb,
312                                  ffado_ringbuffer_data_t * vec)
313 {
314   size_t free_cnt;
315   size_t cnt2;
316   size_t w, r;
317
318   w = rb->write_ptr;
319   r = rb->read_ptr;
320
321   if (w > r) {
322     free_cnt = w - r;
323   } else {
324     free_cnt = (w - r + rb->size) & rb->size_mask;
325   }
326
327   cnt2 = r + free_cnt;
328
329   if (cnt2 > rb->size) {
330
331     /* Two part vector: the rest of the buffer after the current write
332        ptr, plus some from the start of the buffer. */
333
334     vec[0].buf = &(rb->buf[r]);
335     vec[0].len = rb->size - r;
336     vec[1].buf = rb->buf;
337     vec[1].len = cnt2 & rb->size_mask;
338
339   } else {
340
341     /* Single part vector: just the rest of the buffer */
342
343     vec[0].buf = &(rb->buf[r]);
344     vec[0].len = free_cnt;
345     vec[1].len = 0;
346   }
347 }
348
349 /* The non-copying data writer.  `vec' is an array of two places.  Set
350    the values at `vec' to hold the current writeable data at `rb'.  If
351    the writeable data is in one segment the second segment has zero
352    length.  */
353
354 void
355 ffado_ringbuffer_get_write_vector (const ffado_ringbuffer_t * rb,
356                                   ffado_ringbuffer_data_t * vec)
357 {
358   size_t free_cnt;
359   size_t cnt2;
360   size_t w, r;
361
362   w = rb->write_ptr;
363   r = rb->read_ptr;
364
365   if (w > r) {
366     free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
367   } else if (w < r) {
368     free_cnt = (r - w) - 1;
369   } else {
370     free_cnt = rb->size - 1;
371   }
372
373   cnt2 = w + free_cnt;
374
375   if (cnt2 > rb->size) {
376
377     /* Two part vector: the rest of the buffer after the current write
378        ptr, plus some from the start of the buffer. */
379
380     vec[0].buf = &(rb->buf[w]);
381     vec[0].len = rb->size - w;
382     vec[1].buf = rb->buf;
383     vec[1].len = cnt2 & rb->size_mask;
384   } else {
385     vec[0].buf = &(rb->buf[w]);
386     vec[0].len = free_cnt;
387     vec[1].len = 0;
388   }
389 }
Note: See TracBrowser for help on using the browser.