[alsa-out] this seems okish.
[jack.git] / libjack / ringbuffer.c
blobf66a4e6be7bb49e9771ef40a39cd31f3cc2a6d6c
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 <config.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef USE_MLOCK
28 #include <sys/mman.h>
29 #endif /* USE_MLOCK */
30 #include <jack/ringbuffer.h>
32 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
33 actual buffer size is rounded up to the next power of two. */
35 jack_ringbuffer_t *
36 jack_ringbuffer_create (size_t sz)
38 int power_of_two;
39 jack_ringbuffer_t *rb;
41 rb = malloc (sizeof (jack_ringbuffer_t));
43 for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
45 rb->size = 1 << power_of_two;
46 rb->size_mask = rb->size;
47 rb->size_mask -= 1;
48 rb->write_ptr = 0;
49 rb->read_ptr = 0;
50 rb->buf = malloc (rb->size);
51 rb->mlocked = 0;
53 return rb;
56 /* Free all data associated with the ringbuffer `rb'. */
58 void
59 jack_ringbuffer_free (jack_ringbuffer_t * rb)
61 #ifdef USE_MLOCK
62 if (rb->mlocked) {
63 munlock (rb->buf, rb->size);
65 #endif /* USE_MLOCK */
66 free (rb->buf);
67 free (rb);
70 /* Lock the data block of `rb' using the system call 'mlock'. */
72 int
73 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
75 #ifdef USE_MLOCK
76 if (mlock (rb->buf, rb->size)) {
77 return -1;
79 #endif /* USE_MLOCK */
80 rb->mlocked = 1;
81 return 0;
84 /* Reset the read and write pointers to zero. This is not thread
85 safe. */
87 void
88 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
90 rb->read_ptr = 0;
91 rb->write_ptr = 0;
94 /* Return the number of bytes available for reading. This is the
95 number of bytes in front of the read pointer and behind the write
96 pointer. */
98 size_t
99 jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
101 size_t w, r;
103 w = rb->write_ptr;
104 r = rb->read_ptr;
106 if (w > r) {
107 return w - r;
108 } else {
109 return (w - r + rb->size) & rb->size_mask;
113 /* Return the number of bytes available for writing. This is the
114 number of bytes in front of the write pointer and behind the read
115 pointer. */
117 size_t
118 jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
120 size_t w, r;
122 w = rb->write_ptr;
123 r = rb->read_ptr;
125 if (w > r) {
126 return ((r - w + rb->size) & rb->size_mask) - 1;
127 } else if (w < r) {
128 return (r - w) - 1;
129 } else {
130 return rb->size - 1;
134 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
135 `dest'. Returns the actual number of bytes copied. */
137 size_t
138 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
140 size_t free_cnt;
141 size_t cnt2;
142 size_t to_read;
143 size_t n1, n2;
145 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
146 return 0;
149 to_read = cnt > free_cnt ? free_cnt : cnt;
151 cnt2 = rb->read_ptr + to_read;
153 if (cnt2 > rb->size) {
154 n1 = rb->size - rb->read_ptr;
155 n2 = cnt2 & rb->size_mask;
156 } else {
157 n1 = to_read;
158 n2 = 0;
161 memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
162 rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
164 if (n2) {
165 memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
166 rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
169 return to_read;
172 /* The copying data reader w/o read pointer advance. Copy at most
173 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
174 copied. */
176 size_t
177 jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
179 size_t free_cnt;
180 size_t cnt2;
181 size_t to_read;
182 size_t n1, n2;
183 size_t tmp_read_ptr;
185 tmp_read_ptr = rb->read_ptr;
187 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
188 return 0;
191 to_read = cnt > free_cnt ? free_cnt : cnt;
193 cnt2 = tmp_read_ptr + to_read;
195 if (cnt2 > rb->size) {
196 n1 = rb->size - tmp_read_ptr;
197 n2 = cnt2 & rb->size_mask;
198 } else {
199 n1 = to_read;
200 n2 = 0;
203 memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
204 tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
206 if (n2) {
207 memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
210 return to_read;
214 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
215 `src'. Returns the actual number of bytes copied. */
217 size_t
218 jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
220 size_t free_cnt;
221 size_t cnt2;
222 size_t to_write;
223 size_t n1, n2;
225 if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
226 return 0;
229 to_write = cnt > free_cnt ? free_cnt : cnt;
231 cnt2 = rb->write_ptr + to_write;
233 if (cnt2 > rb->size) {
234 n1 = rb->size - rb->write_ptr;
235 n2 = cnt2 & rb->size_mask;
236 } else {
237 n1 = to_write;
238 n2 = 0;
241 memcpy (&(rb->buf[rb->write_ptr]), src, n1);
242 rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
244 if (n2) {
245 memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
246 rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
249 return to_write;
252 /* Advance the read pointer `cnt' places. */
254 void
255 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
257 size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
258 rb->read_ptr = tmp;
261 /* Advance the write pointer `cnt' places. */
263 void
264 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
266 size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
267 rb->write_ptr = tmp;
270 /* The non-copying data reader. `vec' is an array of two places. Set
271 the values at `vec' to hold the current readable data at `rb'. If
272 the readable data is in one segment the second segment has zero
273 length. */
275 void
276 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
277 jack_ringbuffer_data_t * vec)
279 size_t free_cnt;
280 size_t cnt2;
281 size_t w, r;
283 w = rb->write_ptr;
284 r = rb->read_ptr;
286 if (w > r) {
287 free_cnt = w - r;
288 } else {
289 free_cnt = (w - r + rb->size) & rb->size_mask;
292 cnt2 = r + free_cnt;
294 if (cnt2 > rb->size) {
296 /* Two part vector: the rest of the buffer after the current write
297 ptr, plus some from the start of the buffer. */
299 vec[0].buf = &(rb->buf[r]);
300 vec[0].len = rb->size - r;
301 vec[1].buf = rb->buf;
302 vec[1].len = cnt2 & rb->size_mask;
304 } else {
306 /* Single part vector: just the rest of the buffer */
308 vec[0].buf = &(rb->buf[r]);
309 vec[0].len = free_cnt;
310 vec[1].len = 0;
314 /* The non-copying data writer. `vec' is an array of two places. Set
315 the values at `vec' to hold the current writeable data at `rb'. If
316 the writeable data is in one segment the second segment has zero
317 length. */
319 void
320 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
321 jack_ringbuffer_data_t * vec)
323 size_t free_cnt;
324 size_t cnt2;
325 size_t w, r;
327 w = rb->write_ptr;
328 r = rb->read_ptr;
330 if (w > r) {
331 free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
332 } else if (w < r) {
333 free_cnt = (r - w) - 1;
334 } else {
335 free_cnt = rb->size - 1;
338 cnt2 = w + free_cnt;
340 if (cnt2 > rb->size) {
342 /* Two part vector: the rest of the buffer after the current write
343 ptr, plus some from the start of the buffer. */
345 vec[0].buf = &(rb->buf[w]);
346 vec[0].len = rb->size - w;
347 vec[1].buf = rb->buf;
348 vec[1].len = cnt2 & rb->size_mask;
349 } else {
350 vec[0].buf = &(rb->buf[w]);
351 vec[0].len = free_cnt;
352 vec[1].len = 0;