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.
27 #endif /* USE_MLOCK */
28 #include "JackCompilerDeps.h"
34 jack_ringbuffer_data_t
;
38 volatile size_t write_ptr
;
39 volatile size_t read_ptr
;
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
,
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
)
71 jack_ringbuffer_t
*rb
;
73 if ((rb
= (jack_ringbuffer_t
*) malloc (sizeof (jack_ringbuffer_t
))) == 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
;
84 if ((rb
->buf
= (char *) malloc (rb
->size
)) == NULL
) {
93 /* Free all data associated with the ringbuffer `rb'. */
96 jack_ringbuffer_free (jack_ringbuffer_t
* rb
)
100 munlock (rb
->buf
, rb
->size
);
102 #endif /* USE_MLOCK */
107 /* Lock the data block of `rb' using the system call 'mlock'. */
110 jack_ringbuffer_mlock (jack_ringbuffer_t
* rb
)
113 if (mlock (rb
->buf
, rb
->size
)) {
116 #endif /* USE_MLOCK */
121 /* Reset the read and write pointers to zero. This is not thread
125 jack_ringbuffer_reset (jack_ringbuffer_t
* rb
)
129 memset(rb
->buf
, 0, rb
->size
);
132 /* Reset the read and write pointers to zero. This is not thread
136 jack_ringbuffer_reset_size (jack_ringbuffer_t
* rb
, size_t sz
)
139 rb
->size_mask
= rb
->size
;
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
150 jack_ringbuffer_read_space (const jack_ringbuffer_t
* rb
)
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
169 jack_ringbuffer_write_space (const jack_ringbuffer_t
* rb
)
177 return ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
185 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
186 `dest'. Returns the actual number of bytes copied. */
189 jack_ringbuffer_read (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
196 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 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
;
212 memcpy (dest
, &(rb
->buf
[rb
->read_ptr
]), n1
);
213 rb
->read_ptr
= (rb
->read_ptr
+ n1
) & rb
->size_mask
;
216 memcpy (dest
+ n1
, &(rb
->buf
[rb
->read_ptr
]), n2
);
217 rb
->read_ptr
= (rb
->read_ptr
+ n2
) & rb
->size_mask
;
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
228 jack_ringbuffer_peek (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
236 tmp_read_ptr
= rb
->read_ptr
;
238 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 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
;
254 memcpy (dest
, &(rb
->buf
[tmp_read_ptr
]), n1
);
255 tmp_read_ptr
= (tmp_read_ptr
+ n1
) & rb
->size_mask
;
258 memcpy (dest
+ n1
, &(rb
->buf
[tmp_read_ptr
]), n2
);
264 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
265 `src'. Returns the actual number of bytes copied. */
268 jack_ringbuffer_write (jack_ringbuffer_t
* rb
, const char *src
, size_t cnt
)
275 if ((free_cnt
= jack_ringbuffer_write_space (rb
)) == 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
;
291 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
, n1
);
292 rb
->write_ptr
= (rb
->write_ptr
+ n1
) & rb
->size_mask
;
295 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
+ n1
, n2
);
296 rb
->write_ptr
= (rb
->write_ptr
+ n2
) & rb
->size_mask
;
302 /* Advance the read pointer `cnt' places. */
305 jack_ringbuffer_read_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
307 size_t tmp
= (rb
->read_ptr
+ cnt
) & rb
->size_mask
;
311 /* Advance the write pointer `cnt' places. */
314 jack_ringbuffer_write_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
316 size_t tmp
= (rb
->write_ptr
+ cnt
) & rb
->size_mask
;
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
326 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t
* rb
,
327 jack_ringbuffer_data_t
* vec
)
339 free_cnt
= (w
- r
+ rb
->size
) & rb
->size_mask
;
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
;
356 /* Single part vector: just the rest of the buffer */
358 vec
[0].buf
= &(rb
->buf
[r
]);
359 vec
[0].len
= free_cnt
;
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
370 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t
* rb
,
371 jack_ringbuffer_data_t
* vec
)
381 free_cnt
= ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
383 free_cnt
= (r
- w
) - 1;
385 free_cnt
= rb
->size
- 1;
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
;
400 vec
[0].buf
= &(rb
->buf
[w
]);
401 vec
[0].len
= free_cnt
;