~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
JACK/libjack/ringbuffer.c


** 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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.