1 /*
2   Copyright (C) 2000 Paul Davis
3   Copyright (C) 2003 Rohan Drape
4 
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.
9 
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.
14 
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.
18 
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.
21 */
22 
23 // Modified to compile without warnings on g++
24 // Harry van Haaren <harryhaaren@gmail.com>
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef USE_MLOCK
29 #include <sys/mman.h>
30 #endif /* USE_MLOCK */
31 #include "ringbuffer.h"
32 
33 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
34    actual buffer size is rounded up to the next power of two.  */
35 
36 jack_ringbuffer_t *
jack_ringbuffer_create(size_t sz)37 jack_ringbuffer_create (size_t sz)
38 {
39 	int power_of_two;
40 	jack_ringbuffer_t *rb;
41 
42 	if ((rb = (jack_ringbuffer_t*)malloc (sizeof (jack_ringbuffer_t))) == NULL) {
43 		return NULL;
44 	}
45 
46 	for (power_of_two = 1; 1 << power_of_two < (signed int)sz; power_of_two++);
47 
48 	rb->size = 1 << power_of_two;
49 	rb->size_mask = rb->size;
50 	rb->size_mask -= 1;
51 	rb->write_ptr = 0;
52 	rb->read_ptr = 0;
53 	if ((rb->buf = (char*)malloc (rb->size)) == NULL) {
54 		free (rb);
55 		return NULL;
56 	}
57 	rb->mlocked = 0;
58 
59 	return rb;
60 }
61 
62 /* Free all data associated with the ringbuffer `rb'. */
63 
64 void
jack_ringbuffer_free(jack_ringbuffer_t * rb)65 jack_ringbuffer_free (jack_ringbuffer_t * rb)
66 {
67 #ifdef USE_MLOCK
68 	if (rb->mlocked) {
69 		munlock (rb->buf, rb->size);
70 	}
71 #endif /* USE_MLOCK */
72 	free (rb->buf);
73 	free (rb);
74 }
75 
76 /* Lock the data block of `rb' using the system call 'mlock'.  */
77 
78 int
jack_ringbuffer_mlock(jack_ringbuffer_t * rb)79 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
80 {
81 #ifdef USE_MLOCK
82 	if (mlock (rb->buf, rb->size)) {
83 		return -1;
84 	}
85 #endif /* USE_MLOCK */
86 	rb->mlocked = 1;
87 	return 0;
88 }
89 
90 /* Reset the read and write pointers to zero. This is not thread
91    safe. */
92 
93 void
jack_ringbuffer_reset(jack_ringbuffer_t * rb)94 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
95 {
96 	rb->read_ptr = 0;
97 	rb->write_ptr = 0;
98 }
99 
100 /* Return the number of bytes available for reading.  This is the
101    number of bytes in front of the read pointer and behind the write
102    pointer.  */
103 
104 size_t
jack_ringbuffer_read_space(const jack_ringbuffer_t * rb)105 jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
106 {
107 	size_t w, r;
108 
109 	w = rb->write_ptr;
110 	r = rb->read_ptr;
111 
112 	if (w > r) {
113 		return w - r;
114 	} else {
115 		return (w - r + rb->size) & rb->size_mask;
116 	}
117 }
118 
119 /* Return the number of bytes available for writing.  This is the
120    number of bytes in front of the write pointer and behind the read
121    pointer.  */
122 
123 size_t
jack_ringbuffer_write_space(const jack_ringbuffer_t * rb)124 jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
125 {
126 	size_t w, r;
127 
128 	w = rb->write_ptr;
129 	r = rb->read_ptr;
130 
131 	if (w > r) {
132 		return ((r - w + rb->size) & rb->size_mask) - 1;
133 	} else if (w < r) {
134 		return (r - w) - 1;
135 	} else {
136 		return rb->size - 1;
137 	}
138 }
139 
140 /* The copying data reader.  Copy at most `cnt' bytes from `rb' to
141    `dest'.  Returns the actual number of bytes copied. */
142 
143 size_t
jack_ringbuffer_read(jack_ringbuffer_t * rb,char * dest,size_t cnt)144 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
145 {
146 	size_t free_cnt;
147 	size_t cnt2;
148 	size_t to_read;
149 	size_t n1, n2;
150 
151 	if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
152 		return 0;
153 	}
154 
155 	to_read = cnt > free_cnt ? free_cnt : cnt;
156 
157 	cnt2 = rb->read_ptr + to_read;
158 
159 	if (cnt2 > rb->size) {
160 		n1 = rb->size - rb->read_ptr;
161 		n2 = cnt2 & rb->size_mask;
162 	} else {
163 		n1 = to_read;
164 		n2 = 0;
165 	}
166 
167 	memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
168 	rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
169 
170 	if (n2) {
171 		memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
172 		rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
173 	}
174 
175 	return to_read;
176 }
177 
178 /* The copying data reader w/o read pointer advance.  Copy at most
179    `cnt' bytes from `rb' to `dest'.  Returns the actual number of bytes
180    copied. */
181 
182 size_t
jack_ringbuffer_peek(jack_ringbuffer_t * rb,char * dest,size_t cnt)183 jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
184 {
185 	size_t free_cnt;
186 	size_t cnt2;
187 	size_t to_read;
188 	size_t n1, n2;
189 	size_t tmp_read_ptr;
190 
191 	tmp_read_ptr = rb->read_ptr;
192 
193 	if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
194 		return 0;
195 	}
196 
197 	to_read = cnt > free_cnt ? free_cnt : cnt;
198 
199 	cnt2 = tmp_read_ptr + to_read;
200 
201 	if (cnt2 > rb->size) {
202 		n1 = rb->size - tmp_read_ptr;
203 		n2 = cnt2 & rb->size_mask;
204 	} else {
205 		n1 = to_read;
206 		n2 = 0;
207 	}
208 
209 	memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
210 	tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
211 
212 	if (n2) {
213 		memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
214 	}
215 
216 	return to_read;
217 }
218 
219 
220 /* The copying data writer.  Copy at most `cnt' bytes to `rb' from
221    `src'.  Returns the actual number of bytes copied. */
222 
223 size_t
jack_ringbuffer_write(jack_ringbuffer_t * rb,const char * src,size_t cnt)224 jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
225 {
226 	size_t free_cnt;
227 	size_t cnt2;
228 	size_t to_write;
229 	size_t n1, n2;
230 
231 	if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
232 		return 0;
233 	}
234 
235 	to_write = cnt > free_cnt ? free_cnt : cnt;
236 
237 	cnt2 = rb->write_ptr + to_write;
238 
239 	if (cnt2 > rb->size) {
240 		n1 = rb->size - rb->write_ptr;
241 		n2 = cnt2 & rb->size_mask;
242 	} else {
243 		n1 = to_write;
244 		n2 = 0;
245 	}
246 
247 	memcpy (&(rb->buf[rb->write_ptr]), src, n1);
248 	rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
249 
250 	if (n2) {
251 		memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
252 		rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
253 	}
254 
255 	return to_write;
256 }
257 
258 /* Advance the read pointer `cnt' places. */
259 
260 void
jack_ringbuffer_read_advance(jack_ringbuffer_t * rb,size_t cnt)261 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
262 {
263 	size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
264 	rb->read_ptr = tmp;
265 }
266 
267 /* Advance the write pointer `cnt' places. */
268 
269 void
jack_ringbuffer_write_advance(jack_ringbuffer_t * rb,size_t cnt)270 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
271 {
272 	size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
273 	rb->write_ptr = tmp;
274 }
275 
276 /* The non-copying data reader.  `vec' is an array of two places.  Set
277    the values at `vec' to hold the current readable data at `rb'.  If
278    the readable data is in one segment the second segment has zero
279    length.  */
280 
281 void
jack_ringbuffer_get_read_vector(const jack_ringbuffer_t * rb,jack_ringbuffer_data_t * vec)282 jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
283                                  jack_ringbuffer_data_t * vec)
284 {
285 	size_t free_cnt;
286 	size_t cnt2;
287 	size_t w, r;
288 
289 	w = rb->write_ptr;
290 	r = rb->read_ptr;
291 
292 	if (w > r) {
293 		free_cnt = w - r;
294 	} else {
295 		free_cnt = (w - r + rb->size) & rb->size_mask;
296 	}
297 
298 	cnt2 = r + free_cnt;
299 
300 	if (cnt2 > rb->size) {
301 
302 		/* Two part vector: the rest of the buffer after the current write
303 		   ptr, plus some from the start of the buffer. */
304 
305 		vec[0].buf = &(rb->buf[r]);
306 		vec[0].len = rb->size - r;
307 		vec[1].buf = rb->buf;
308 		vec[1].len = cnt2 & rb->size_mask;
309 
310 	} else {
311 
312 		/* Single part vector: just the rest of the buffer */
313 
314 		vec[0].buf = &(rb->buf[r]);
315 		vec[0].len = free_cnt;
316 		vec[1].len = 0;
317 	}
318 }
319 
320 /* The non-copying data writer.  `vec' is an array of two places.  Set
321    the values at `vec' to hold the current writeable data at `rb'.  If
322    the writeable data is in one segment the second segment has zero
323    length.  */
324 
325 void
jack_ringbuffer_get_write_vector(const jack_ringbuffer_t * rb,jack_ringbuffer_data_t * vec)326 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
327                                   jack_ringbuffer_data_t * vec)
328 {
329 	size_t free_cnt;
330 	size_t cnt2;
331 	size_t w, r;
332 
333 	w = rb->write_ptr;
334 	r = rb->read_ptr;
335 
336 	if (w > r) {
337 		free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
338 	} else if (w < r) {
339 		free_cnt = (r - w) - 1;
340 	} else {
341 		free_cnt = rb->size - 1;
342 	}
343 
344 	cnt2 = w + free_cnt;
345 
346 	if (cnt2 > rb->size) {
347 
348 		/* Two part vector: the rest of the buffer after the current write
349 		   ptr, plus some from the start of the buffer. */
350 
351 		vec[0].buf = &(rb->buf[w]);
352 		vec[0].len = rb->size - w;
353 		vec[1].buf = rb->buf;
354 		vec[1].len = cnt2 & rb->size_mask;
355 	} else {
356 		vec[0].buf = &(rb->buf[w]);
357 		vec[0].len = free_cnt;
358 		vec[1].len = 0;
359 	}
360 }
361