FreeBSD: Cleanup tab indents.
[jack2.git] / common / ringbuffer.c
blob9de844f6ecc655aa9f2ae508946fba4e9cee5435
1 /*
2 Copyright (C) 2000 Paul Davis
3 Copyright (C) 2003 Rohan Drape
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code.
20 This is safe for the case of one read thread and one write thread.
23 #include <stdlib.h>
24 #include <string.h>
25 #ifdef USE_MLOCK
26 #include <sys/mman.h>
27 #endif /* USE_MLOCK */
28 #include "JackCompilerDeps.h"
30 typedef struct {
31 char *buf;
32 size_t len;
34 jack_ringbuffer_data_t ;
36 typedef struct {
37 char *buf;
38 volatile size_t write_ptr;
39 volatile size_t read_ptr;
40 size_t size;
41 size_t size_mask;
42 int mlocked;
44 jack_ringbuffer_t ;
46 LIB_EXPORT jack_ringbuffer_t *jack_ringbuffer_create(size_t sz);
47 LIB_EXPORT void jack_ringbuffer_free(jack_ringbuffer_t *rb);
48 LIB_EXPORT void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t *rb,
49 jack_ringbuffer_data_t *vec);
50 LIB_EXPORT void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t *rb,
51 jack_ringbuffer_data_t *vec);
52 LIB_EXPORT size_t jack_ringbuffer_read(jack_ringbuffer_t *rb, char *dest, size_t cnt);
53 LIB_EXPORT size_t jack_ringbuffer_peek(jack_ringbuffer_t *rb, char *dest, size_t cnt);
54 LIB_EXPORT void jack_ringbuffer_read_advance(jack_ringbuffer_t *rb, size_t cnt);
55 LIB_EXPORT size_t jack_ringbuffer_read_space(const jack_ringbuffer_t *rb);
56 LIB_EXPORT int jack_ringbuffer_mlock(jack_ringbuffer_t *rb);
57 LIB_EXPORT void jack_ringbuffer_reset(jack_ringbuffer_t *rb);
58 LIB_EXPORT void jack_ringbuffer_reset_size (jack_ringbuffer_t * rb, size_t sz);
59 LIB_EXPORT size_t jack_ringbuffer_write(jack_ringbuffer_t *rb, const char *src,
60 size_t cnt);
61 void jack_ringbuffer_write_advance(jack_ringbuffer_t *rb, size_t cnt);
62 size_t jack_ringbuffer_write_space(const jack_ringbuffer_t *rb);
64 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
65 actual buffer size is rounded up to the next power of two. */
67 LIB_EXPORT jack_ringbuffer_t *
68 jack_ringbuffer_create (size_t sz)
70 int power_of_two;
71 jack_ringbuffer_t *rb;
73 if ((rb = (jack_ringbuffer_t *) malloc (sizeof (jack_ringbuffer_t))) == NULL) {
74 return NULL;
77 for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
79 rb->size = 1 << power_of_two;
80 rb->size_mask = rb->size;
81 rb->size_mask -= 1;
82 rb->write_ptr = 0;
83 rb->read_ptr = 0;
84 if ((rb->buf = (char *) malloc (rb->size)) == NULL) {
85 free (rb);
86 return NULL;
88 rb->mlocked = 0;
90 return rb;
93 /* Free all data associated with the ringbuffer `rb'. */
95 LIB_EXPORT void
96 jack_ringbuffer_free (jack_ringbuffer_t * rb)
98 #ifdef USE_MLOCK
99 if (rb->mlocked) {
100 munlock (rb->buf, rb->size);
102 #endif /* USE_MLOCK */
103 free (rb->buf);
104 free (rb);
107 /* Lock the data block of `rb' using the system call 'mlock'. */
109 LIB_EXPORT int
110 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
112 #ifdef USE_MLOCK
113 if (mlock (rb->buf, rb->size)) {
114 return -1;
116 #endif /* USE_MLOCK */
117 rb->mlocked = 1;
118 return 0;
121 /* Reset the read and write pointers to zero. This is not thread
122 safe. */
124 LIB_EXPORT void
125 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
127 rb->read_ptr = 0;
128 rb->write_ptr = 0;
129 memset(rb->buf, 0, rb->size);
132 /* Reset the read and write pointers to zero. This is not thread
133 safe. */
135 LIB_EXPORT void
136 jack_ringbuffer_reset_size (jack_ringbuffer_t * rb, size_t sz)
138 rb->size = sz;
139 rb->size_mask = rb->size;
140 rb->size_mask -= 1;
141 rb->read_ptr = 0;
142 rb->write_ptr = 0;
145 /* Return the number of bytes available for reading. This is the
146 number of bytes in front of the read pointer and behind the write
147 pointer. */
149 LIB_EXPORT size_t
150 jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
152 size_t w, r;
154 w = rb->write_ptr;
155 r = rb->read_ptr;
157 if (w > r) {
158 return w - r;
159 } else {
160 return (w - r + rb->size) & rb->size_mask;
164 /* Return the number of bytes available for writing. This is the
165 number of bytes in front of the write pointer and behind the read
166 pointer. */
168 LIB_EXPORT size_t
169 jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
171 size_t w, r;
173 w = rb->write_ptr;
174 r = rb->read_ptr;
176 if (w > r) {
177 return ((r - w + rb->size) & rb->size_mask) - 1;
178 } else if (w < r) {
179 return (r - w) - 1;
180 } else {
181 return rb->size - 1;
185 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
186 `dest'. Returns the actual number of bytes copied. */
188 LIB_EXPORT size_t
189 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
191 size_t free_cnt;
192 size_t cnt2;
193 size_t to_read;
194 size_t n1, n2;
196 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
197 return 0;
200 to_read = cnt > free_cnt ? free_cnt : cnt;
202 cnt2 = rb->read_ptr + to_read;
204 if (cnt2 > rb->size) {
205 n1 = rb->size - rb->read_ptr;
206 n2 = cnt2 & rb->size_mask;
207 } else {
208 n1 = to_read;
209 n2 = 0;
212 memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
213 rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
215 if (n2) {
216 memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
217 rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
220 return to_read;
223 /* The copying data reader w/o read pointer advance. Copy at most
224 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
225 copied. */
227 LIB_EXPORT size_t
228 jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
230 size_t free_cnt;
231 size_t cnt2;
232 size_t to_read;
233 size_t n1, n2;
234 size_t tmp_read_ptr;
236 tmp_read_ptr = rb->read_ptr;
238 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
239 return 0;
242 to_read = cnt > free_cnt ? free_cnt : cnt;
244 cnt2 = tmp_read_ptr + to_read;
246 if (cnt2 > rb->size) {
247 n1 = rb->size - tmp_read_ptr;
248 n2 = cnt2 & rb->size_mask;
249 } else {
250 n1 = to_read;
251 n2 = 0;
254 memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
255 tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
257 if (n2) {
258 memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
261 return to_read;
264 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
265 `src'. Returns the actual number of bytes copied. */
267 LIB_EXPORT size_t
268 jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
270 size_t free_cnt;
271 size_t cnt2;
272 size_t to_write;
273 size_t n1, n2;
275 if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
276 return 0;
279 to_write = cnt > free_cnt ? free_cnt : cnt;
281 cnt2 = rb->write_ptr + to_write;
283 if (cnt2 > rb->size) {
284 n1 = rb->size - rb->write_ptr;
285 n2 = cnt2 & rb->size_mask;
286 } else {
287 n1 = to_write;
288 n2 = 0;
291 memcpy (&(rb->buf[rb->write_ptr]), src, n1);
292 rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
294 if (n2) {
295 memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
296 rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
299 return to_write;
302 /* Advance the read pointer `cnt' places. */
304 LIB_EXPORT void
305 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
307 size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
308 rb->read_ptr = tmp;
311 /* Advance the write pointer `cnt' places. */
313 LIB_EXPORT void
314 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
316 size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
317 rb->write_ptr = tmp;
320 /* The non-copying data reader. `vec' is an array of two places. Set
321 the values at `vec' to hold the current readable data at `rb'. If
322 the readable data is in one segment the second segment has zero
323 length. */
325 LIB_EXPORT void
326 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
327 jack_ringbuffer_data_t * vec)
329 size_t free_cnt;
330 size_t cnt2;
331 size_t w, r;
333 w = rb->write_ptr;
334 r = rb->read_ptr;
336 if (w > r) {
337 free_cnt = w - r;
338 } else {
339 free_cnt = (w - r + rb->size) & rb->size_mask;
342 cnt2 = r + free_cnt;
344 if (cnt2 > rb->size) {
346 /* Two part vector: the rest of the buffer after the current write
347 ptr, plus some from the start of the buffer. */
349 vec[0].buf = &(rb->buf[r]);
350 vec[0].len = rb->size - r;
351 vec[1].buf = rb->buf;
352 vec[1].len = cnt2 & rb->size_mask;
354 } else {
356 /* Single part vector: just the rest of the buffer */
358 vec[0].buf = &(rb->buf[r]);
359 vec[0].len = free_cnt;
360 vec[1].len = 0;
364 /* The non-copying data writer. `vec' is an array of two places. Set
365 the values at `vec' to hold the current writeable data at `rb'. If
366 the writeable data is in one segment the second segment has zero
367 length. */
369 LIB_EXPORT void
370 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
371 jack_ringbuffer_data_t * vec)
373 size_t free_cnt;
374 size_t cnt2;
375 size_t w, r;
377 w = rb->write_ptr;
378 r = rb->read_ptr;
380 if (w > r) {
381 free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
382 } else if (w < r) {
383 free_cnt = (r - w) - 1;
384 } else {
385 free_cnt = rb->size - 1;
388 cnt2 = w + free_cnt;
390 if (cnt2 > rb->size) {
392 /* Two part vector: the rest of the buffer after the current write
393 ptr, plus some from the start of the buffer. */
395 vec[0].buf = &(rb->buf[w]);
396 vec[0].len = rb->size - w;
397 vec[1].buf = rb->buf;
398 vec[1].len = cnt2 & rb->size_mask;
399 } else {
400 vec[0].buf = &(rb->buf[w]);
401 vec[0].len = free_cnt;
402 vec[1].len = 0;