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