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"
30 /* Portable definitions for acquire and release fences */
32 #if defined(_M_AMD64) || defined(_M_IX86) || defined(_M_X64)
33 /* Only compiler fences are needed on x86. In fact, GCC
34 * will generate no instructions for acq/rel fences on
37 #define JACK_ACQ_FENCE() _ReadBarrier()
38 #define JACK_REL_FENCE() _WriteBarrier()
40 /* Use full memory fence for non-x86 systems with msvc */
42 #define JACK_ACQ_FENCE() MemoryBarrier()
43 #define JACK_REL_FENCE() MemoryBarrier()
45 #elif defined(__GNUC__)
46 #ifdef __ATOMIC_ACQUIRE
47 #define JACK_ACQ_FENCE() __atomic_thread_fence(__ATOMIC_ACQUIRE)
48 #define JACK_REL_FENCE() __atomic_thread_fence(__ATOMIC_RELEASE)
50 /* Fallback to the legacy __sync builtin (full memory fence) */
51 #define JACK_ACQ_FENCE() __sync_synchronize()
52 #define JACK_REL_FENCE() __sync_synchronize()
55 #define JACK_ACQ_FENCE()
56 #define JACK_REL_FENCE()
63 jack_ringbuffer_data_t
;
75 LIB_EXPORT jack_ringbuffer_t
*jack_ringbuffer_create(size_t sz
);
76 LIB_EXPORT
void jack_ringbuffer_free(jack_ringbuffer_t
*rb
);
77 LIB_EXPORT
void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t
*rb
,
78 jack_ringbuffer_data_t
*vec
);
79 LIB_EXPORT
void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t
*rb
,
80 jack_ringbuffer_data_t
*vec
);
81 LIB_EXPORT
size_t jack_ringbuffer_read(jack_ringbuffer_t
*rb
, char *dest
, size_t cnt
);
82 LIB_EXPORT
size_t jack_ringbuffer_peek(jack_ringbuffer_t
*rb
, char *dest
, size_t cnt
);
83 LIB_EXPORT
void jack_ringbuffer_read_advance(jack_ringbuffer_t
*rb
, size_t cnt
);
84 LIB_EXPORT
size_t jack_ringbuffer_read_space(const jack_ringbuffer_t
*rb
);
85 LIB_EXPORT
int jack_ringbuffer_mlock(jack_ringbuffer_t
*rb
);
86 LIB_EXPORT
void jack_ringbuffer_reset(jack_ringbuffer_t
*rb
);
87 LIB_EXPORT
void jack_ringbuffer_reset_size (jack_ringbuffer_t
* rb
, size_t sz
);
88 LIB_EXPORT
size_t jack_ringbuffer_write(jack_ringbuffer_t
*rb
, const char *src
,
90 void jack_ringbuffer_write_advance(jack_ringbuffer_t
*rb
, size_t cnt
);
91 size_t jack_ringbuffer_write_space(const jack_ringbuffer_t
*rb
);
93 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
94 actual buffer size is rounded up to the next power of two. */
96 LIB_EXPORT jack_ringbuffer_t
*
97 jack_ringbuffer_create (size_t sz
)
100 jack_ringbuffer_t
*rb
;
102 if ((rb
= (jack_ringbuffer_t
*) malloc (sizeof (jack_ringbuffer_t
))) == NULL
) {
106 for (power_of_two
= 1; 1 << power_of_two
< sz
; power_of_two
++);
108 rb
->size
= 1 << power_of_two
;
109 rb
->size_mask
= rb
->size
;
113 if ((rb
->buf
= (char *) malloc (rb
->size
)) == NULL
) {
122 /* Free all data associated with the ringbuffer `rb'. */
125 jack_ringbuffer_free (jack_ringbuffer_t
* rb
)
129 munlock (rb
->buf
, rb
->size
);
131 #endif /* USE_MLOCK */
136 /* Lock the data block of `rb' using the system call 'mlock'. */
139 jack_ringbuffer_mlock (jack_ringbuffer_t
* rb
)
142 if (mlock (rb
->buf
, rb
->size
)) {
145 #endif /* USE_MLOCK */
150 /* Reset the read and write pointers to zero. This is not thread
154 jack_ringbuffer_reset (jack_ringbuffer_t
* rb
)
158 memset(rb
->buf
, 0, rb
->size
);
161 /* Reset the read and write pointers to zero. This is not thread
165 jack_ringbuffer_reset_size (jack_ringbuffer_t
* rb
, size_t sz
)
168 rb
->size_mask
= rb
->size
;
174 /* Return the number of bytes available for reading. This is the
175 number of bytes in front of the read pointer and behind the write
179 jack_ringbuffer_read_space (const jack_ringbuffer_t
* rb
)
187 return (w
- r
) & rb
->size_mask
;
190 /* Return the number of bytes available for writing. This is the
191 number of bytes in front of the write pointer and behind the read
195 jack_ringbuffer_write_space (const jack_ringbuffer_t
* rb
)
203 return (r
- w
- 1) & rb
->size_mask
;
206 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
207 `dest'. Returns the actual number of bytes copied. */
210 jack_ringbuffer_read (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
217 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
221 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
223 /* note: relaxed load here, rb->read_ptr cannot be
224 * modified from writing thread */
225 cnt2
= rb
->read_ptr
+ to_read
;
227 if (cnt2
> rb
->size
) {
228 n1
= rb
->size
- rb
->read_ptr
;
229 n2
= cnt2
& rb
->size_mask
;
235 memcpy (dest
, &(rb
->buf
[rb
->read_ptr
]), n1
);
236 JACK_REL_FENCE(); /* ensure pointer increment happens after copy */
237 rb
->read_ptr
= (rb
->read_ptr
+ n1
) & rb
->size_mask
;
240 memcpy (dest
+ n1
, &(rb
->buf
[rb
->read_ptr
]), n2
);
241 JACK_REL_FENCE(); /* ensure pointer increment happens after copy */
242 rb
->read_ptr
= (rb
->read_ptr
+ n2
) & rb
->size_mask
;
248 /* The copying data reader w/o read pointer advance. Copy at most
249 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
253 jack_ringbuffer_peek (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
261 tmp_read_ptr
= rb
->read_ptr
;
263 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
267 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
269 cnt2
= tmp_read_ptr
+ to_read
;
271 if (cnt2
> rb
->size
) {
272 n1
= rb
->size
- tmp_read_ptr
;
273 n2
= cnt2
& rb
->size_mask
;
279 memcpy (dest
, &(rb
->buf
[tmp_read_ptr
]), n1
);
280 tmp_read_ptr
= (tmp_read_ptr
+ n1
) & rb
->size_mask
;
283 memcpy (dest
+ n1
, &(rb
->buf
[tmp_read_ptr
]), n2
);
289 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
290 `src'. Returns the actual number of bytes copied. */
293 jack_ringbuffer_write (jack_ringbuffer_t
* rb
, const char *src
, size_t cnt
)
300 if ((free_cnt
= jack_ringbuffer_write_space (rb
)) == 0) {
304 to_write
= cnt
> free_cnt
? free_cnt
: cnt
;
306 /* note: relaxed load here, rb->write_ptr cannot be
307 * modified from reading thread */
308 cnt2
= rb
->write_ptr
+ to_write
;
310 if (cnt2
> rb
->size
) {
311 n1
= rb
->size
- rb
->write_ptr
;
312 n2
= cnt2
& rb
->size_mask
;
318 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
, n1
);
319 JACK_REL_FENCE(); /* ensure pointer increment happens after copy */
320 rb
->write_ptr
= (rb
->write_ptr
+ n1
) & rb
->size_mask
;
323 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
+ n1
, n2
);
324 JACK_REL_FENCE(); /* ensure pointer increment happens after copy */
325 rb
->write_ptr
= (rb
->write_ptr
+ n2
) & rb
->size_mask
;
331 /* Advance the read pointer `cnt' places. */
334 jack_ringbuffer_read_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
336 size_t tmp
= (rb
->read_ptr
+ cnt
) & rb
->size_mask
;
337 JACK_REL_FENCE(); /* ensure pointer increment happens after copy (by user) */
341 /* Advance the write pointer `cnt' places. */
344 jack_ringbuffer_write_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
346 size_t tmp
= (rb
->write_ptr
+ cnt
) & rb
->size_mask
;
347 JACK_REL_FENCE(); /* ensure pointer increment happens after copy (by user) */
351 /* The non-copying data reader. `vec' is an array of two places. Set
352 the values at `vec' to hold the current readable data at `rb'. If
353 the readable data is in one segment the second segment has zero
357 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t
* rb
,
358 jack_ringbuffer_data_t
* vec
)
365 free_cnt
= jack_ringbuffer_read_space(rb
);
368 if (cnt2
> rb
->size
) {
370 /* Two part vector: the rest of the buffer after the current write
371 ptr, plus some from the start of the buffer. */
373 vec
[0].buf
= &(rb
->buf
[r
]);
374 vec
[0].len
= rb
->size
- r
;
375 vec
[1].buf
= rb
->buf
;
376 vec
[1].len
= cnt2
& rb
->size_mask
;
380 /* Single part vector: just the rest of the buffer */
382 vec
[0].buf
= &(rb
->buf
[r
]);
383 vec
[0].len
= free_cnt
;
388 /* The non-copying data writer. `vec' is an array of two places. Set
389 the values at `vec' to hold the current writeable data at `rb'. If
390 the writeable data is in one segment the second segment has zero
394 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t
* rb
,
395 jack_ringbuffer_data_t
* vec
)
402 free_cnt
= jack_ringbuffer_write_space(rb
);
405 if (cnt2
> rb
->size
) {
407 /* Two part vector: the rest of the buffer after the current write
408 ptr, plus some from the start of the buffer. */
410 vec
[0].buf
= &(rb
->buf
[w
]);
411 vec
[0].len
= rb
->size
- w
;
412 vec
[1].buf
= rb
->buf
;
413 vec
[1].len
= cnt2
& rb
->size_mask
;
415 vec
[0].buf
= &(rb
->buf
[w
]);
416 vec
[0].len
= free_cnt
;