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