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.
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. */
36 jack_ringbuffer_create (size_t sz
)
39 jack_ringbuffer_t
*rb
;
41 if ((rb
= malloc (sizeof (jack_ringbuffer_t
))) == 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
;
52 if ((rb
->buf
= malloc (rb
->size
)) == NULL
) {
61 /* Free all data associated with the ringbuffer `rb'. */
64 jack_ringbuffer_free (jack_ringbuffer_t
* rb
)
68 munlock (rb
->buf
, rb
->size
);
70 #endif /* USE_MLOCK */
75 /* Lock the data block of `rb' using the system call 'mlock'. */
78 jack_ringbuffer_mlock (jack_ringbuffer_t
* rb
)
81 if (mlock (rb
->buf
, rb
->size
)) {
84 #endif /* USE_MLOCK */
89 /* Reset the read and write pointers to zero. This is not thread
93 jack_ringbuffer_reset (jack_ringbuffer_t
* rb
)
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
104 jack_ringbuffer_read_space (const jack_ringbuffer_t
* rb
)
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
123 jack_ringbuffer_write_space (const jack_ringbuffer_t
* rb
)
131 return ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
139 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
140 `dest'. Returns the actual number of bytes copied. */
143 jack_ringbuffer_read (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
150 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 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
;
166 memcpy (dest
, &(rb
->buf
[rb
->read_ptr
]), n1
);
167 rb
->read_ptr
= (rb
->read_ptr
+ n1
) & rb
->size_mask
;
170 memcpy (dest
+ n1
, &(rb
->buf
[rb
->read_ptr
]), n2
);
171 rb
->read_ptr
= (rb
->read_ptr
+ n2
) & rb
->size_mask
;
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
182 jack_ringbuffer_peek (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
190 tmp_read_ptr
= rb
->read_ptr
;
192 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 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
;
208 memcpy (dest
, &(rb
->buf
[tmp_read_ptr
]), n1
);
209 tmp_read_ptr
= (tmp_read_ptr
+ n1
) & rb
->size_mask
;
212 memcpy (dest
+ n1
, &(rb
->buf
[tmp_read_ptr
]), n2
);
219 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
220 `src'. Returns the actual number of bytes copied. */
223 jack_ringbuffer_write (jack_ringbuffer_t
* rb
, const char *src
, size_t cnt
)
230 if ((free_cnt
= jack_ringbuffer_write_space (rb
)) == 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
;
246 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
, n1
);
247 rb
->write_ptr
= (rb
->write_ptr
+ n1
) & rb
->size_mask
;
250 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
+ n1
, n2
);
251 rb
->write_ptr
= (rb
->write_ptr
+ n2
) & rb
->size_mask
;
257 /* Advance the read pointer `cnt' places. */
260 jack_ringbuffer_read_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
262 size_t tmp
= (rb
->read_ptr
+ cnt
) & rb
->size_mask
;
266 /* Advance the write pointer `cnt' places. */
269 jack_ringbuffer_write_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
271 size_t tmp
= (rb
->write_ptr
+ cnt
) & rb
->size_mask
;
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
281 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t
* rb
,
282 jack_ringbuffer_data_t
* vec
)
294 free_cnt
= (w
- r
+ rb
->size
) & rb
->size_mask
;
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
;
311 /* Single part vector: just the rest of the buffer */
313 vec
[0].buf
= &(rb
->buf
[r
]);
314 vec
[0].len
= free_cnt
;
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
325 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t
* rb
,
326 jack_ringbuffer_data_t
* vec
)
336 free_cnt
= ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
338 free_cnt
= (r
- w
) - 1;
340 free_cnt
= rb
->size
- 1;
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
;
355 vec
[0].buf
= &(rb
->buf
[w
]);
356 vec
[0].len
= free_cnt
;