** Warning: Cannot open xref database.
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 #include <sys/mman.h>
26 #include <jack/ringbuffer.h>
27
28 /* Create a new ringbuffer to hold at least `sz' bytes of data. The
29 actual buffer size is rounded up to the next power of two. */
30
31 jack_ringbuffer_t *
32 jack_ringbuffer_create (size_t sz)
33 {
34 int power_of_two;
35 jack_ringbuffer_t *rb;
36
37 rb = malloc (sizeof (jack_ringbuffer_t));
38
39 for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
40
41 rb->size = 1 << power_of_two;
42 rb->size_mask = rb->size;
43 rb->size_mask -= 1;
44 rb->write_ptr = 0;
45 rb->read_ptr = 0;
46 rb->buf = malloc (rb->size);
47 rb->mlocked = 0;
48
49 return rb;
50 }
51
52 /* Free all data associated with the ringbuffer `rb'. */
53
54 void
55 jack_ringbuffer_free (jack_ringbuffer_t * rb)
56 {
57 if (rb->mlocked) {
58 munlock (rb->buf, rb->size);
59 }
60 free (rb->buf);
61 }
62
63 /* Lock the data block of `rb' using the system call 'mlock'. */
64
65 int
66 jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
67 {
68 if (mlock (rb->buf, rb->size)) {
69 return -1;
70 }
71 rb->mlocked = 1;
72 return 0;
73 }
74
75 /* Reset the read and write pointers to zero. This is not thread
76 safe. */
77
78 void
79 jack_ringbuffer_reset (jack_ringbuffer_t * rb)
80 {
81 rb->read_ptr = 0;
82 rb->write_ptr = 0;
83 }
84
85 /* Return the number of bytes available for reading. This is the
86 number of bytes in front of the read pointer and behind the write
87 pointer. */
88
89 size_t
90 jack_ringbuffer_read_space (jack_ringbuffer_t * rb)
91 {
92 size_t w, r;
93
94 w = rb->write_ptr;
95 r = rb->read_ptr;
96
97 if (w > r) {
98 return w - r;
99 } else {
100 return (w - r + rb->size) & rb->size_mask;
101 }
102 }
103
104 /* Return the number of bytes available for writing. This is the
105 number of bytes in front of the write pointer and behind the read
106 pointer. */
107
108 size_t
109 jack_ringbuffer_write_space (jack_ringbuffer_t * rb)
110 {
111 size_t w, r;
112
113 w = rb->write_ptr;
114 r = rb->read_ptr;
115
116 if (w > r) {
117 return ((r - w + rb->size) & rb->size_mask) - 1;
118 } else if (w < r) {
119 return (r - w) - 1;
120 } else {
121 return rb->size - 1;
122 }
123 }
124
125 /* The copying data reader. Copy at most `cnt' bytes from `rb' to
126 `dest'. Returns the actual number of bytes copied. */
127
128 size_t
129 jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
130 {
131 size_t free_cnt;
132 size_t cnt2;
133 size_t to_read;
134 size_t n1, n2;
135
136 if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
137 return 0;
138 }
139
140 to_read = cnt > free_cnt ? free_cnt : cnt;
141
142 cnt2 = rb->read_ptr + to_read;
143
144 if (cnt2 > rb->size) {
145 n1 = rb->size - rb->read_ptr;
146 n2 = cnt2 & rb->size_mask;
147 } else {
148 n1 = to_read;
149 n2 = 0;
150 }
151
152 memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
153 rb->read_ptr += n1;
154 rb->read_ptr &= rb->size_mask;
155
156 if (n2) {
157 memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
158 rb->read_ptr += n2;
159 rb->read_ptr &= rb->size_mask;
160 }
161
162 return to_read;
163 }
164
165 /* The copying data writer. Copy at most `cnt' bytes to `rb' from
166 `src'. Returns the actual number of bytes copied. */
167
168 size_t
169 jack_ringbuffer_write (jack_ringbuffer_t * rb, char *src, size_t cnt)
170 {
171 size_t free_cnt;
172 size_t cnt2;
173 size_t to_write;
174 size_t n1, n2;
175
176 if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
177 return 0;
178 }
179
180 to_write = cnt > free_cnt ? free_cnt : cnt;
181
182 cnt2 = rb->write_ptr + to_write;
183
184 if (cnt2 > rb->size) {
185 n1 = rb->size - rb->write_ptr;
186 n2 = cnt2 & rb->size_mask;
187 } else {
188 n1 = to_write;
189 n2 = 0;
190 }
191
192 memcpy (&(rb->buf[rb->write_ptr]), src, n1);
193 rb->write_ptr += n1;
194 rb->write_ptr &= rb->size_mask;
195
196 if (n2) {
197 memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
198 rb->write_ptr += n2;
199 rb->write_ptr &= rb->size_mask;
200 }
201
202 return to_write;
203 }
204
205 /* Advance the read pointer `cnt' places. */
206
207 void
208 jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
209 {
210 rb->read_ptr += cnt;
211 rb->read_ptr &= rb->size_mask;
212 }
213
214 /* Advance the write pointer `cnt' places. */
215
216 void
217 jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
218 {
219 rb->write_ptr += cnt;
220 rb->write_ptr &= rb->size_mask;
221 }
222
223 /* The non-copying data reader. `vec' is an array of two places. Set
224 the values at `vec' to hold the current readable data at `rb'. If
225 the readable data is in one segment the second segment has zero
226 length. */
227
228 void
229 jack_ringbuffer_get_read_vector (jack_ringbuffer_t * rb,
230 jack_ringbuffer_data_t * vec)
231 {
232 size_t free_cnt;
233 size_t cnt2;
234 size_t w, r;
235
236 w = rb->write_ptr;
237 r = rb->read_ptr;
238
239 if (w > r) {
240 free_cnt = w - r;
241 } else {
242 free_cnt = (w - r + rb->size) & rb->size_mask;
243 }
244
245 cnt2 = r + free_cnt;
246
247 if (cnt2 > rb->size) {
248
249 /* Two part vector: the rest of the buffer after the current write
250 ptr, plus some from the start of the buffer. */
251
252 vec[0].buf = &(rb->buf[r]);
253 vec[0].len = rb->size - r;
254 vec[1].buf = rb->buf;
255 vec[1].len = cnt2 & rb->size_mask;
256
257 } else {
258
259 /* Single part vector: just the rest of the buffer */
260
261 vec[0].buf = &(rb->buf[r]);
262 vec[0].len = free_cnt;
263 vec[1].len = 0;
264 }
265 }
266
267 /* The non-copying data writer. `vec' is an array of two places. Set
268 the values at `vec' to hold the current writeable data at `rb'. If
269 the writeable data is in one segment the second segment has zero
270 length. */
271
272 void
273 jack_ringbuffer_get_write_vector (jack_ringbuffer_t * rb,
274 jack_ringbuffer_data_t * vec)
275 {
276 size_t free_cnt;
277 size_t cnt2;
278 size_t w, r;
279
280 w = rb->write_ptr;
281 r = rb->read_ptr;
282
283 if (w > r) {
284 free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
285 } else if (w < r) {
286 free_cnt = (r - w) - 1;
287 } else {
288 free_cnt = rb->size - 1;
289 }
290
291 cnt2 = w + free_cnt;
292
293 if (cnt2 > rb->size) {
294
295 /* Two part vector: the rest of the buffer after the current write
296 ptr, plus some from the start of the buffer. */
297
298 vec[0].buf = &(rb->buf[w]);
299 vec[0].len = rb->size - w;
300 vec[1].buf = rb->buf;
301 vec[1].len = cnt2 & rb->size_mask;
302 } else {
303 vec[0].buf = &(rb->buf[w]);
304 vec[0].len = free_cnt;
305 vec[1].len = 0;
306 }
307 }
308
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.