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