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

Revision 742, 8.8 kB (checked in by ppalmers, 16 years ago)

- Remove some obsolete support files and dirs

- Clean up the license statements in the source files. Everything is

GPL version 3 now.

- Add license and copyright notices to scons scripts

- Clean up some other text files

Line 
1 /*
2  * Copyright (C) 2005-2007 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 3 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 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) any later version.
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.