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

Revision 445, 8.0 kB (checked in by pieterpalmers, 14 years ago)

* name change from FreeBoB to FFADO
* replaced tabs by 4 spaces
* got rid of end-of-line spaces
* made all license and copyrights conform

library becomes LGPL, apps become GPL
explicitly state LGPL v2.1 and GPL v2 (don't like v3 draft)

copyrights are 2005-2007 Daniel & Pieter
except for the MotU stuff (C) Jonathan, Pieter

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