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 "CarlaDefines.h"
36 jack_ringbuffer_data_t
;
40 volatile size_t write_ptr
;
41 volatile size_t read_ptr
;
48 CARLA_PLUGIN_EXPORT jack_ringbuffer_t
*jack_ringbuffer_create(size_t sz
);
49 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_free(jack_ringbuffer_t
*rb
);
50 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t
*rb
, jack_ringbuffer_data_t
*vec
);
51 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t
*rb
, jack_ringbuffer_data_t
*vec
);
52 CARLA_PLUGIN_EXPORT
size_t jack_ringbuffer_read(jack_ringbuffer_t
*rb
, char *dest
, size_t cnt
);
53 CARLA_PLUGIN_EXPORT
size_t jack_ringbuffer_peek(jack_ringbuffer_t
*rb
, char *dest
, size_t cnt
);
54 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_read_advance(jack_ringbuffer_t
*rb
, size_t cnt
);
55 CARLA_PLUGIN_EXPORT
size_t jack_ringbuffer_read_space(const jack_ringbuffer_t
*rb
);
56 CARLA_PLUGIN_EXPORT
int jack_ringbuffer_mlock(jack_ringbuffer_t
*rb
);
57 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_reset(jack_ringbuffer_t
*rb
);
58 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_reset_size (jack_ringbuffer_t
* rb
, size_t sz
);
59 CARLA_PLUGIN_EXPORT
size_t jack_ringbuffer_write(jack_ringbuffer_t
*rb
, const char *src
, size_t cnt
);
60 CARLA_PLUGIN_EXPORT
void jack_ringbuffer_write_advance(jack_ringbuffer_t
*rb
, size_t cnt
);
61 CARLA_PLUGIN_EXPORT
size_t jack_ringbuffer_write_space(const jack_ringbuffer_t
*rb
);
63 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
64 actual buffer size is rounded up to the next power of two. */
66 CARLA_PLUGIN_EXPORT jack_ringbuffer_t
*
67 jack_ringbuffer_create (size_t sz
)
69 unsigned int power_of_two
;
70 jack_ringbuffer_t
*rb
;
72 if ((rb
= (jack_ringbuffer_t
*) malloc (sizeof (jack_ringbuffer_t
))) == NULL
) {
76 for (power_of_two
= 1U; 1U << power_of_two
< sz
; power_of_two
++);
78 rb
->size
= 1U << power_of_two
;
79 rb
->size_mask
= rb
->size
;
83 if ((rb
->buf
= (char *) malloc (rb
->size
)) == NULL
) {
92 /* Free all data associated with the ringbuffer `rb'. */
94 CARLA_PLUGIN_EXPORT
void
95 jack_ringbuffer_free (jack_ringbuffer_t
* rb
)
99 munlock (rb
->buf
, rb
->size
);
101 #endif /* USE_MLOCK */
106 /* Lock the data block of `rb' using the system call 'mlock'. */
108 CARLA_PLUGIN_EXPORT
int
109 jack_ringbuffer_mlock (jack_ringbuffer_t
* rb
)
112 if (mlock (rb
->buf
, rb
->size
)) {
115 #endif /* USE_MLOCK */
120 /* Reset the read and write pointers to zero. This is not thread
123 CARLA_PLUGIN_EXPORT
void
124 jack_ringbuffer_reset (jack_ringbuffer_t
* rb
)
128 memset(rb
->buf
, 0, rb
->size
);
131 /* Reset the read and write pointers to zero. This is not thread
134 CARLA_PLUGIN_EXPORT
void
135 jack_ringbuffer_reset_size (jack_ringbuffer_t
* rb
, size_t sz
)
138 rb
->size_mask
= rb
->size
;
144 /* Return the number of bytes available for reading. This is the
145 number of bytes in front of the read pointer and behind the write
148 CARLA_PLUGIN_EXPORT
size_t
149 jack_ringbuffer_read_space (const jack_ringbuffer_t
* rb
)
159 return (w
- r
+ rb
->size
) & rb
->size_mask
;
163 /* Return the number of bytes available for writing. This is the
164 number of bytes in front of the write pointer and behind the read
167 CARLA_PLUGIN_EXPORT
size_t
168 jack_ringbuffer_write_space (const jack_ringbuffer_t
* rb
)
176 return ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
184 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
185 `dest'. Returns the actual number of bytes copied. */
187 CARLA_PLUGIN_EXPORT
size_t
188 jack_ringbuffer_read (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
195 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
199 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
201 cnt2
= rb
->read_ptr
+ to_read
;
203 if (cnt2
> rb
->size
) {
204 n1
= rb
->size
- rb
->read_ptr
;
205 n2
= cnt2
& rb
->size_mask
;
211 memcpy (dest
, &(rb
->buf
[rb
->read_ptr
]), n1
);
212 rb
->read_ptr
= (rb
->read_ptr
+ n1
) & rb
->size_mask
;
215 memcpy (dest
+ n1
, &(rb
->buf
[rb
->read_ptr
]), n2
);
216 rb
->read_ptr
= (rb
->read_ptr
+ n2
) & rb
->size_mask
;
222 /* The copying data reader w/o read pointer advance. Copy at most
223 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
226 CARLA_PLUGIN_EXPORT
size_t
227 jack_ringbuffer_peek (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
235 tmp_read_ptr
= rb
->read_ptr
;
237 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
241 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
243 cnt2
= tmp_read_ptr
+ to_read
;
245 if (cnt2
> rb
->size
) {
246 n1
= rb
->size
- tmp_read_ptr
;
247 n2
= cnt2
& rb
->size_mask
;
253 memcpy (dest
, &(rb
->buf
[tmp_read_ptr
]), n1
);
254 tmp_read_ptr
= (tmp_read_ptr
+ n1
) & rb
->size_mask
;
257 memcpy (dest
+ n1
, &(rb
->buf
[tmp_read_ptr
]), n2
);
263 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
264 `src'. Returns the actual number of bytes copied. */
266 CARLA_PLUGIN_EXPORT
size_t
267 jack_ringbuffer_write (jack_ringbuffer_t
* rb
, const char *src
, size_t cnt
)
274 if ((free_cnt
= jack_ringbuffer_write_space (rb
)) == 0) {
278 to_write
= cnt
> free_cnt
? free_cnt
: cnt
;
280 cnt2
= rb
->write_ptr
+ to_write
;
282 if (cnt2
> rb
->size
) {
283 n1
= rb
->size
- rb
->write_ptr
;
284 n2
= cnt2
& rb
->size_mask
;
290 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
, n1
);
291 rb
->write_ptr
= (rb
->write_ptr
+ n1
) & rb
->size_mask
;
294 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
+ n1
, n2
);
295 rb
->write_ptr
= (rb
->write_ptr
+ n2
) & rb
->size_mask
;
301 /* Advance the read pointer `cnt' places. */
303 CARLA_PLUGIN_EXPORT
void
304 jack_ringbuffer_read_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
306 size_t tmp
= (rb
->read_ptr
+ cnt
) & rb
->size_mask
;
310 /* Advance the write pointer `cnt' places. */
312 CARLA_PLUGIN_EXPORT
void
313 jack_ringbuffer_write_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
315 size_t tmp
= (rb
->write_ptr
+ cnt
) & rb
->size_mask
;
319 /* The non-copying data reader. `vec' is an array of two places. Set
320 the values at `vec' to hold the current readable data at `rb'. If
321 the readable data is in one segment the second segment has zero
324 CARLA_PLUGIN_EXPORT
void
325 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t
* rb
,
326 jack_ringbuffer_data_t
* vec
)
338 free_cnt
= (w
- r
+ rb
->size
) & rb
->size_mask
;
343 if (cnt2
> rb
->size
) {
345 /* Two part vector: the rest of the buffer after the current write
346 ptr, plus some from the start of the buffer. */
348 vec
[0].buf
= &(rb
->buf
[r
]);
349 vec
[0].len
= rb
->size
- r
;
350 vec
[1].buf
= rb
->buf
;
351 vec
[1].len
= cnt2
& rb
->size_mask
;
355 /* Single part vector: just the rest of the buffer */
357 vec
[0].buf
= &(rb
->buf
[r
]);
358 vec
[0].len
= free_cnt
;
363 /* The non-copying data writer. `vec' is an array of two places. Set
364 the values at `vec' to hold the current writeable data at `rb'. If
365 the writeable data is in one segment the second segment has zero
368 CARLA_PLUGIN_EXPORT
void
369 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t
* rb
,
370 jack_ringbuffer_data_t
* vec
)
380 free_cnt
= ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
382 free_cnt
= (r
- w
) - 1;
384 free_cnt
= rb
->size
- 1;
389 if (cnt2
> rb
->size
) {
391 /* Two part vector: the rest of the buffer after the current write
392 ptr, plus some from the start of the buffer. */
394 vec
[0].buf
= &(rb
->buf
[w
]);
395 vec
[0].len
= rb
->size
- w
;
396 vec
[1].buf
= rb
->buf
;
397 vec
[1].len
= cnt2
& rb
->size_mask
;
399 vec
[0].buf
= &(rb
->buf
[w
]);
400 vec
[0].len
= free_cnt
;