ensure that client-side message buffer thread calls thread_init callback if/when...
[jack.git] / libjack / ringbuffer.c
blobc06a1b2534dc2bd2d2694a681b86fe86cfc310d8
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 if ((rb = malloc (sizeof (jack_ringbuffer_t))) == NULL) {
42 return NULL;
45 for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
47 rb->size = 1 << power_of_two;
48 rb->size_mask = rb->size;
49 rb->size_mask -= 1;
50 rb->write_ptr = 0;
51 rb->read_ptr = 0;
52 if ((rb->buf = malloc (rb->size)) == NULL) {
53 free (rb);
54 return NULL;
56 rb->mlocked = 0;
58 return rb;
61 /* Free all data associated with the ringbuffer `rb'. */
63 void
64 jack_ringbuffer_free (jack_ringbuffer_t * rb)
66 #ifdef USE_MLOCK
67 if (rb->mlocked) {
68 munlock (rb->buf, rb->size);
70 #endif /* USE_MLOCK */
71 free (rb->buf);
72 free (rb);
75 /* Lock the data block of `rb' using the system call 'mlock'. */
77 int
78 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
80 #ifdef USE_MLOCK
81 if (mlock (rb->buf, rb->size)) {
82 return -1;
84 #endif /* USE_MLOCK */
85 rb->mlocked = 1;
86 return 0;
89 /* Reset the read and write pointers to zero. This is not thread
90 safe. */
92 void
93 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
95 rb->read_ptr = 0;
96 rb->write_ptr = 0;
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. */
103 size_t
104 jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
106 size_t w, r;
108 w = rb->write_ptr;
109 r = rb->read_ptr;
111 if (w > r) {
112 return w - r;
113 } else {
114 return (w - r + rb->size) & rb->size_mask;
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. */
122 size_t
123 jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
125 size_t w, r;
127 w = rb->write_ptr;
128 r = rb->read_ptr;
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;
139 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
140 `dest'. Returns the actual number of bytes copied. */
142 size_t
143 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
145 size_t free_cnt;
146 size_t cnt2;
147 size_t to_read;
148 size_t n1, n2;
150 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
151 return 0;
154 to_read = cnt > free_cnt ? free_cnt : cnt;
156 cnt2 = rb->read_ptr + to_read;
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;
166 memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
167 rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
169 if (n2) {
170 memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
171 rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
174 return to_read;
177 /* The copying data reader w/o read pointer advance. Copy at most
178 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
179 copied. */
181 size_t
182 jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
184 size_t free_cnt;
185 size_t cnt2;
186 size_t to_read;
187 size_t n1, n2;
188 size_t tmp_read_ptr;
190 tmp_read_ptr = rb->read_ptr;
192 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
193 return 0;
196 to_read = cnt > free_cnt ? free_cnt : cnt;
198 cnt2 = tmp_read_ptr + to_read;
200 if (cnt2 > rb->size) {
201 n1 = rb->size - tmp_read_ptr;
202 n2 = cnt2 & rb->size_mask;
203 } else {
204 n1 = to_read;
205 n2 = 0;
208 memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
209 tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
211 if (n2) {
212 memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
215 return to_read;
219 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
220 `src'. Returns the actual number of bytes copied. */
222 size_t
223 jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
225 size_t free_cnt;
226 size_t cnt2;
227 size_t to_write;
228 size_t n1, n2;
230 if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
231 return 0;
234 to_write = cnt > free_cnt ? free_cnt : cnt;
236 cnt2 = rb->write_ptr + to_write;
238 if (cnt2 > rb->size) {
239 n1 = rb->size - rb->write_ptr;
240 n2 = cnt2 & rb->size_mask;
241 } else {
242 n1 = to_write;
243 n2 = 0;
246 memcpy (&(rb->buf[rb->write_ptr]), src, n1);
247 rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
249 if (n2) {
250 memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
251 rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
254 return to_write;
257 /* Advance the read pointer `cnt' places. */
259 void
260 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
262 size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
263 rb->read_ptr = tmp;
266 /* Advance the write pointer `cnt' places. */
268 void
269 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
271 size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
272 rb->write_ptr = tmp;
275 /* The non-copying data reader. `vec' is an array of two places. Set
276 the values at `vec' to hold the current readable data at `rb'. If
277 the readable data is in one segment the second segment has zero
278 length. */
280 void
281 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
282 jack_ringbuffer_data_t * vec)
284 size_t free_cnt;
285 size_t cnt2;
286 size_t w, r;
288 w = rb->write_ptr;
289 r = rb->read_ptr;
291 if (w > r) {
292 free_cnt = w - r;
293 } else {
294 free_cnt = (w - r + rb->size) & rb->size_mask;
297 cnt2 = r + free_cnt;
299 if (cnt2 > rb->size) {
301 /* Two part vector: the rest of the buffer after the current write
302 ptr, plus some from the start of the buffer. */
304 vec[0].buf = &(rb->buf[r]);
305 vec[0].len = rb->size - r;
306 vec[1].buf = rb->buf;
307 vec[1].len = cnt2 & rb->size_mask;
309 } else {
311 /* Single part vector: just the rest of the buffer */
313 vec[0].buf = &(rb->buf[r]);
314 vec[0].len = free_cnt;
315 vec[1].len = 0;
319 /* The non-copying data writer. `vec' is an array of two places. Set
320 the values at `vec' to hold the current writeable data at `rb'. If
321 the writeable data is in one segment the second segment has zero
322 length. */
324 void
325 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
326 jack_ringbuffer_data_t * vec)
328 size_t free_cnt;
329 size_t cnt2;
330 size_t w, r;
332 w = rb->write_ptr;
333 r = rb->read_ptr;
335 if (w > r) {
336 free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
337 } else if (w < r) {
338 free_cnt = (r - w) - 1;
339 } else {
340 free_cnt = rb->size - 1;
343 cnt2 = w + free_cnt;
345 if (cnt2 > rb->size) {
347 /* Two part vector: the rest of the buffer after the current write
348 ptr, plus some from the start of the buffer. */
350 vec[0].buf = &(rb->buf[w]);
351 vec[0].len = rb->size - w;
352 vec[1].buf = rb->buf;
353 vec[1].len = cnt2 & rb->size_mask;
354 } else {
355 vec[0].buf = &(rb->buf[w]);
356 vec[0].len = free_cnt;
357 vec[1].len = 0;