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 #include <stdlib.h>
24 #include <string.h>
25 #ifdef USE_MLOCK
26 #include <sys/mman.h>
27 #endif /* USE_MLOCK */
28 #include "JackCompilerDeps.h"
29 
30 typedef struct {
31     char *buf;
32     size_t len;
33 }
34 jack_ringbuffer_data_t ;
35 
36 typedef struct {
37     char	*buf;
38     volatile size_t write_ptr;
39     volatile size_t read_ptr;
40     size_t	size;
41     size_t	size_mask;
42     int	mlocked;
43 }
44 jack_ringbuffer_t ;
45 
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,
60                                  size_t cnt);
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);
63 
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.  */
66 
67 LIB_EXPORT jack_ringbuffer_t *
jack_ringbuffer_create(size_t sz)68 jack_ringbuffer_create (size_t sz)
69 {
70 	int power_of_two;
71 	jack_ringbuffer_t *rb;
72 
73 	if ((rb = (jack_ringbuffer_t *) malloc (sizeof (jack_ringbuffer_t))) == NULL) {
74 		return NULL;
75 	}
76 
77 	for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
78 
79 	rb->size = 1 << power_of_two;
80 	rb->size_mask = rb->size;
81 	rb->size_mask -= 1;
82 	rb->write_ptr = 0;
83 	rb->read_ptr = 0;
84 	if ((rb->buf = (char *) malloc (rb->size)) == NULL) {
85 		free (rb);
86 		return NULL;
87 	}
88 	rb->mlocked = 0;
89 
90 	return rb;
91 }
92 
93 /* Free all data associated with the ringbuffer `rb'. */
94 
95 LIB_EXPORT void
jack_ringbuffer_free(jack_ringbuffer_t * rb)96 jack_ringbuffer_free (jack_ringbuffer_t * rb)
97 {
98 #ifdef USE_MLOCK
99 	if (rb->mlocked) {
100 		munlock (rb->buf, rb->size);
101 	}
102 #endif /* USE_MLOCK */
103 	free (rb->buf);
104 	free (rb);
105 }
106 
107 /* Lock the data block of `rb' using the system call 'mlock'.  */
108 
109 LIB_EXPORT int
jack_ringbuffer_mlock(jack_ringbuffer_t * rb)110 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
111 {
112 #ifdef USE_MLOCK
113 	if (mlock (rb->buf, rb->size)) {
114 		return -1;
115 	}
116 #endif /* USE_MLOCK */
117 	rb->mlocked = 1;
118 	return 0;
119 }
120 
121 /* Reset the read and write pointers to zero. This is not thread
122    safe. */
123 
124 LIB_EXPORT void
jack_ringbuffer_reset(jack_ringbuffer_t * rb)125 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
126 {
127 	rb->read_ptr = 0;
128 	rb->write_ptr = 0;
129     memset(rb->buf, 0, rb->size);
130 }
131 
132 /* Reset the read and write pointers to zero. This is not thread
133    safe. */
134 
135 LIB_EXPORT void
jack_ringbuffer_reset_size(jack_ringbuffer_t * rb,size_t sz)136 jack_ringbuffer_reset_size (jack_ringbuffer_t * rb, size_t sz)
137 {
138     rb->size = sz;
139     rb->size_mask = rb->size;
140     rb->size_mask -= 1;
141     rb->read_ptr = 0;
142     rb->write_ptr = 0;
143 }
144 
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
147    pointer.  */
148 
149 LIB_EXPORT size_t
jack_ringbuffer_read_space(const jack_ringbuffer_t * rb)150 jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
151 {
152 	size_t w, r;
153 
154 	w = rb->write_ptr;
155 	r = rb->read_ptr;
156 
157 	if (w > r) {
158 		return w - r;
159 	} else {
160 		return (w - r + rb->size) & rb->size_mask;
161 	}
162 }
163 
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
166    pointer.  */
167 
168 LIB_EXPORT size_t
jack_ringbuffer_write_space(const jack_ringbuffer_t * rb)169 jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
170 {
171 	size_t w, r;
172 
173 	w = rb->write_ptr;
174 	r = rb->read_ptr;
175 
176 	if (w > r) {
177 		return ((r - w + rb->size) & rb->size_mask) - 1;
178 	} else if (w < r) {
179 		return (r - w) - 1;
180 	} else {
181 		return rb->size - 1;
182 	}
183 }
184 
185 /* The copying data reader.  Copy at most `cnt' bytes from `rb' to
186    `dest'.  Returns the actual number of bytes copied. */
187 
188 LIB_EXPORT size_t
jack_ringbuffer_read(jack_ringbuffer_t * rb,char * dest,size_t cnt)189 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
190 {
191 	size_t free_cnt;
192 	size_t cnt2;
193 	size_t to_read;
194 	size_t n1, n2;
195 
196 	if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
197 		return 0;
198 	}
199 
200 	to_read = cnt > free_cnt ? free_cnt : cnt;
201 
202 	cnt2 = rb->read_ptr + to_read;
203 
204 	if (cnt2 > rb->size) {
205 		n1 = rb->size - rb->read_ptr;
206 		n2 = cnt2 & rb->size_mask;
207 	} else {
208 		n1 = to_read;
209 		n2 = 0;
210 	}
211 
212 	memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
213 	rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
214 
215 	if (n2) {
216 		memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
217 		rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
218 	}
219 
220 	return to_read;
221 }
222 
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
225    copied. */
226 
227 LIB_EXPORT size_t
jack_ringbuffer_peek(jack_ringbuffer_t * rb,char * dest,size_t cnt)228 jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
229 {
230 	size_t free_cnt;
231 	size_t cnt2;
232 	size_t to_read;
233 	size_t n1, n2;
234 	size_t tmp_read_ptr;
235 
236 	tmp_read_ptr = rb->read_ptr;
237 
238 	if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
239 		return 0;
240 	}
241 
242 	to_read = cnt > free_cnt ? free_cnt : cnt;
243 
244 	cnt2 = tmp_read_ptr + to_read;
245 
246 	if (cnt2 > rb->size) {
247 		n1 = rb->size - tmp_read_ptr;
248 		n2 = cnt2 & rb->size_mask;
249 	} else {
250 		n1 = to_read;
251 		n2 = 0;
252 	}
253 
254 	memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
255 	tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
256 
257 	if (n2) {
258 		memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
259 	}
260 
261 	return to_read;
262 }
263 
264 /* The copying data writer.  Copy at most `cnt' bytes to `rb' from
265    `src'.  Returns the actual number of bytes copied. */
266 
267 LIB_EXPORT size_t
jack_ringbuffer_write(jack_ringbuffer_t * rb,const char * src,size_t cnt)268 jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
269 {
270 	size_t free_cnt;
271 	size_t cnt2;
272 	size_t to_write;
273 	size_t n1, n2;
274 
275 	if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
276 		return 0;
277 	}
278 
279 	to_write = cnt > free_cnt ? free_cnt : cnt;
280 
281 	cnt2 = rb->write_ptr + to_write;
282 
283 	if (cnt2 > rb->size) {
284 		n1 = rb->size - rb->write_ptr;
285 		n2 = cnt2 & rb->size_mask;
286 	} else {
287 		n1 = to_write;
288 		n2 = 0;
289 	}
290 
291 	memcpy (&(rb->buf[rb->write_ptr]), src, n1);
292 	rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
293 
294 	if (n2) {
295 		memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
296 		rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
297 	}
298 
299 	return to_write;
300 }
301 
302 /* Advance the read pointer `cnt' places. */
303 
304 LIB_EXPORT void
jack_ringbuffer_read_advance(jack_ringbuffer_t * rb,size_t cnt)305 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
306 {
307 	size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
308 	rb->read_ptr = tmp;
309 }
310 
311 /* Advance the write pointer `cnt' places. */
312 
313 LIB_EXPORT void
jack_ringbuffer_write_advance(jack_ringbuffer_t * rb,size_t cnt)314 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
315 {
316 	size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
317 	rb->write_ptr = tmp;
318 }
319 
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
323    length.  */
324 
325 LIB_EXPORT void
jack_ringbuffer_get_read_vector(const jack_ringbuffer_t * rb,jack_ringbuffer_data_t * vec)326 jack_ringbuffer_get_read_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 = w - r;
338 	} else {
339 		free_cnt = (w - r + rb->size) & rb->size_mask;
340 	}
341 
342 	cnt2 = r + free_cnt;
343 
344 	if (cnt2 > rb->size) {
345 
346 		/* Two part vector: the rest of the buffer after the current write
347 		   ptr, plus some from the start of the buffer. */
348 
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;
353 
354 	} else {
355 
356 		/* Single part vector: just the rest of the buffer */
357 
358 		vec[0].buf = &(rb->buf[r]);
359 		vec[0].len = free_cnt;
360 		vec[1].len = 0;
361 	}
362 }
363 
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
367    length.  */
368 
369 LIB_EXPORT void
jack_ringbuffer_get_write_vector(const jack_ringbuffer_t * rb,jack_ringbuffer_data_t * vec)370 jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
371 				  jack_ringbuffer_data_t * vec)
372 {
373 	size_t free_cnt;
374 	size_t cnt2;
375 	size_t w, r;
376 
377 	w = rb->write_ptr;
378 	r = rb->read_ptr;
379 
380 	if (w > r) {
381 		free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
382 	} else if (w < r) {
383 		free_cnt = (r - w) - 1;
384 	} else {
385 		free_cnt = rb->size - 1;
386 	}
387 
388 	cnt2 = w + free_cnt;
389 
390 	if (cnt2 > rb->size) {
391 
392 		/* Two part vector: the rest of the buffer after the current write
393 		   ptr, plus some from the start of the buffer. */
394 
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;
399 	} else {
400 		vec[0].buf = &(rb->buf[w]);
401 		vec[0].len = free_cnt;
402 		vec[1].len = 0;
403 	}
404 }
405 
406