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 rb
= malloc (sizeof (jack_ringbuffer_t
));
43 for (power_of_two
= 1; 1 << power_of_two
< sz
; power_of_two
++);
45 rb
->size
= 1 << power_of_two
;
46 rb
->size_mask
= rb
->size
;
50 rb
->buf
= malloc (rb
->size
);
56 /* Free all data associated with the ringbuffer `rb'. */
59 jack_ringbuffer_free (jack_ringbuffer_t
* rb
)
63 munlock (rb
->buf
, rb
->size
);
65 #endif /* USE_MLOCK */
70 /* Lock the data block of `rb' using the system call 'mlock'. */
73 jack_ringbuffer_mlock (jack_ringbuffer_t
* rb
)
76 if (mlock (rb
->buf
, rb
->size
)) {
79 #endif /* USE_MLOCK */
84 /* Reset the read and write pointers to zero. This is not thread
88 jack_ringbuffer_reset (jack_ringbuffer_t
* rb
)
94 /* Return the number of bytes available for reading. This is the
95 number of bytes in front of the read pointer and behind the write
99 jack_ringbuffer_read_space (const jack_ringbuffer_t
* rb
)
109 return (w
- r
+ rb
->size
) & rb
->size_mask
;
113 /* Return the number of bytes available for writing. This is the
114 number of bytes in front of the write pointer and behind the read
118 jack_ringbuffer_write_space (const jack_ringbuffer_t
* rb
)
126 return ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
134 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
135 `dest'. Returns the actual number of bytes copied. */
138 jack_ringbuffer_read (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
145 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
149 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
151 cnt2
= rb
->read_ptr
+ to_read
;
153 if (cnt2
> rb
->size
) {
154 n1
= rb
->size
- rb
->read_ptr
;
155 n2
= cnt2
& rb
->size_mask
;
161 memcpy (dest
, &(rb
->buf
[rb
->read_ptr
]), n1
);
162 rb
->read_ptr
= (rb
->read_ptr
+ n1
) & rb
->size_mask
;
165 memcpy (dest
+ n1
, &(rb
->buf
[rb
->read_ptr
]), n2
);
166 rb
->read_ptr
= (rb
->read_ptr
+ n2
) & rb
->size_mask
;
172 /* The copying data reader w/o read pointer advance. Copy at most
173 `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
177 jack_ringbuffer_peek (jack_ringbuffer_t
* rb
, char *dest
, size_t cnt
)
185 tmp_read_ptr
= rb
->read_ptr
;
187 if ((free_cnt
= jack_ringbuffer_read_space (rb
)) == 0) {
191 to_read
= cnt
> free_cnt
? free_cnt
: cnt
;
193 cnt2
= tmp_read_ptr
+ to_read
;
195 if (cnt2
> rb
->size
) {
196 n1
= rb
->size
- tmp_read_ptr
;
197 n2
= cnt2
& rb
->size_mask
;
203 memcpy (dest
, &(rb
->buf
[tmp_read_ptr
]), n1
);
204 tmp_read_ptr
= (tmp_read_ptr
+ n1
) & rb
->size_mask
;
207 memcpy (dest
+ n1
, &(rb
->buf
[tmp_read_ptr
]), n2
);
214 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
215 `src'. Returns the actual number of bytes copied. */
218 jack_ringbuffer_write (jack_ringbuffer_t
* rb
, const char *src
, size_t cnt
)
225 if ((free_cnt
= jack_ringbuffer_write_space (rb
)) == 0) {
229 to_write
= cnt
> free_cnt
? free_cnt
: cnt
;
231 cnt2
= rb
->write_ptr
+ to_write
;
233 if (cnt2
> rb
->size
) {
234 n1
= rb
->size
- rb
->write_ptr
;
235 n2
= cnt2
& rb
->size_mask
;
241 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
, n1
);
242 rb
->write_ptr
= (rb
->write_ptr
+ n1
) & rb
->size_mask
;
245 memcpy (&(rb
->buf
[rb
->write_ptr
]), src
+ n1
, n2
);
246 rb
->write_ptr
= (rb
->write_ptr
+ n2
) & rb
->size_mask
;
252 /* Advance the read pointer `cnt' places. */
255 jack_ringbuffer_read_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
257 size_t tmp
= (rb
->read_ptr
+ cnt
) & rb
->size_mask
;
261 /* Advance the write pointer `cnt' places. */
264 jack_ringbuffer_write_advance (jack_ringbuffer_t
* rb
, size_t cnt
)
266 size_t tmp
= (rb
->write_ptr
+ cnt
) & rb
->size_mask
;
270 /* The non-copying data reader. `vec' is an array of two places. Set
271 the values at `vec' to hold the current readable data at `rb'. If
272 the readable data is in one segment the second segment has zero
276 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t
* rb
,
277 jack_ringbuffer_data_t
* vec
)
289 free_cnt
= (w
- r
+ rb
->size
) & rb
->size_mask
;
294 if (cnt2
> rb
->size
) {
296 /* Two part vector: the rest of the buffer after the current write
297 ptr, plus some from the start of the buffer. */
299 vec
[0].buf
= &(rb
->buf
[r
]);
300 vec
[0].len
= rb
->size
- r
;
301 vec
[1].buf
= rb
->buf
;
302 vec
[1].len
= cnt2
& rb
->size_mask
;
306 /* Single part vector: just the rest of the buffer */
308 vec
[0].buf
= &(rb
->buf
[r
]);
309 vec
[0].len
= free_cnt
;
314 /* The non-copying data writer. `vec' is an array of two places. Set
315 the values at `vec' to hold the current writeable data at `rb'. If
316 the writeable data is in one segment the second segment has zero
320 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t
* rb
,
321 jack_ringbuffer_data_t
* vec
)
331 free_cnt
= ((r
- w
+ rb
->size
) & rb
->size_mask
) - 1;
333 free_cnt
= (r
- w
) - 1;
335 free_cnt
= rb
->size
- 1;
340 if (cnt2
> rb
->size
) {
342 /* Two part vector: the rest of the buffer after the current write
343 ptr, plus some from the start of the buffer. */
345 vec
[0].buf
= &(rb
->buf
[w
]);
346 vec
[0].len
= rb
->size
- w
;
347 vec
[1].buf
= rb
->buf
;
348 vec
[1].len
= cnt2
& rb
->size_mask
;
350 vec
[0].buf
= &(rb
->buf
[w
]);
351 vec
[0].len
= free_cnt
;