1 /* 2 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ring_buffer.h" 8 9 #include <KernelExport.h> 10 #if 0 11 #include <port.h> 12 #endif 13 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/uio.h> 17 18 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 19 #define user_memcpy(x...) (memcpy(x), B_OK) 20 #endif 21 22 /*! This is a light-weight ring_buffer implementation. 23 * It does not provide any locking - you are supposed to ensure thread-safety 24 * with the restrictions you choose. Unless you are passing in unsafe buffers, 25 * the functions are safe to be called with interrupts turned off as well (not 26 * the user functions). 27 * They also don't use malloc() or any kind of locking after initialization. 28 */ 29 30 31 static inline int32 32 space_left_in_buffer(struct ring_buffer *buffer) 33 { 34 return buffer->size - buffer->in; 35 } 36 37 38 static ssize_t 39 read_from_buffer(struct ring_buffer *buffer, uint8 *data, ssize_t length, 40 bool user) 41 { 42 int32 available = buffer->in; 43 44 if (length > available) 45 length = available; 46 47 if (length == 0) 48 return 0; 49 50 ssize_t bytesRead = length; 51 52 if (buffer->first + length <= buffer->size) { 53 // simple copy 54 if (user) { 55 if (user_memcpy(data, buffer->buffer + buffer->first, length) < B_OK) 56 return B_BAD_ADDRESS; 57 } else 58 memcpy(data, buffer->buffer + buffer->first, length); 59 } else { 60 // need to copy both ends 61 size_t upper = buffer->size - buffer->first; 62 size_t lower = length - upper; 63 64 if (user) { 65 if (user_memcpy(data, buffer->buffer + buffer->first, upper) < B_OK 66 || user_memcpy(data + upper, buffer->buffer, lower) < B_OK) 67 return B_BAD_ADDRESS; 68 } else { 69 memcpy(data, buffer->buffer + buffer->first, upper); 70 memcpy(data + upper, buffer->buffer, lower); 71 } 72 } 73 74 buffer->first = (buffer->first + bytesRead) % buffer->size; 75 buffer->in -= bytesRead; 76 77 return bytesRead; 78 } 79 80 81 static ssize_t 82 write_to_buffer(struct ring_buffer *buffer, const uint8 *data, ssize_t length, 83 bool user) 84 { 85 int32 left = space_left_in_buffer(buffer); 86 if (length > left) 87 length = left; 88 89 if (length == 0) 90 return 0; 91 92 ssize_t bytesWritten = length; 93 int32 position = (buffer->first + buffer->in) % buffer->size; 94 95 if (position + length <= buffer->size) { 96 // simple copy 97 if (user) { 98 if (user_memcpy(buffer->buffer + position, data, length) < B_OK) 99 return B_BAD_ADDRESS; 100 } else 101 memcpy(buffer->buffer + position, data, length); 102 } else { 103 // need to copy both ends 104 size_t upper = buffer->size - position; 105 size_t lower = length - upper; 106 107 if (user) { 108 if (user_memcpy(buffer->buffer + position, data, upper) < B_OK 109 || user_memcpy(buffer->buffer, data + upper, lower) < B_OK) 110 return B_BAD_ADDRESS; 111 } else { 112 memcpy(buffer->buffer + position, data, upper); 113 memcpy(buffer->buffer, data + upper, lower); 114 } 115 } 116 117 buffer->in += bytesWritten; 118 119 return bytesWritten; 120 } 121 122 123 // #pragma mark - 124 125 126 struct ring_buffer* 127 create_ring_buffer(size_t size) 128 { 129 return create_ring_buffer_etc(NULL, size, 0); 130 } 131 132 133 struct ring_buffer* 134 create_ring_buffer_etc(void* memory, size_t size, uint32 flags) 135 { 136 if (memory == NULL) { 137 ring_buffer* buffer = (ring_buffer*)malloc(sizeof(ring_buffer) + size); 138 if (buffer == NULL) 139 return NULL; 140 141 buffer->size = size; 142 ring_buffer_clear(buffer); 143 144 return buffer; 145 } 146 147 size -= sizeof(ring_buffer); 148 ring_buffer* buffer = (ring_buffer*)memory; 149 150 buffer->size = size; 151 if ((flags & RING_BUFFER_INIT_FROM_BUFFER) != 0 152 && (size_t)buffer->size == size 153 && buffer->in >= 0 && (size_t)buffer->in <= size 154 && buffer->first >= 0 && (size_t)buffer->first < size) { 155 // structure looks valid 156 } else 157 ring_buffer_clear(buffer); 158 159 return buffer; 160 } 161 162 163 void 164 delete_ring_buffer(struct ring_buffer *buffer) 165 { 166 free(buffer); 167 } 168 169 170 void 171 ring_buffer_clear(struct ring_buffer *buffer) 172 { 173 buffer->in = 0; 174 buffer->first = 0; 175 } 176 177 178 size_t 179 ring_buffer_readable(struct ring_buffer *buffer) 180 { 181 return buffer->in; 182 } 183 184 185 size_t 186 ring_buffer_writable(struct ring_buffer *buffer) 187 { 188 return buffer->size - buffer->in; 189 } 190 191 192 void 193 ring_buffer_flush(struct ring_buffer *buffer, size_t length) 194 { 195 // we can't flush more bytes than there are 196 if (length > (size_t)buffer->in) 197 length = buffer->in; 198 199 buffer->in -= length; 200 buffer->first = (buffer->first + length) % buffer->size; 201 } 202 203 204 size_t 205 ring_buffer_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 206 { 207 return read_from_buffer(buffer, data, length, false); 208 } 209 210 211 size_t 212 ring_buffer_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 213 { 214 return write_to_buffer(buffer, data, length, false); 215 } 216 217 218 ssize_t 219 ring_buffer_user_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 220 { 221 return read_from_buffer(buffer, data, length, true); 222 } 223 224 225 ssize_t 226 ring_buffer_user_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 227 { 228 return write_to_buffer(buffer, data, length, true); 229 } 230 231 232 /*! Reads data from the ring buffer, but doesn't remove the data from it. 233 \param buffer The ring buffer. 234 \param offset The offset relative to the beginning of the data in the ring 235 buffer at which to start reading. 236 \param data The buffer to which to copy the data. 237 \param length The number of bytes to read at maximum. 238 \return The number of bytes actually read from the buffer. 239 */ 240 size_t 241 ring_buffer_peek(struct ring_buffer* buffer, size_t offset, void* data, 242 size_t length) 243 { 244 size_t available = buffer->in; 245 246 if (offset >= available || length == 0) 247 return 0; 248 249 if (offset + length > available) 250 length = available - offset; 251 252 if ((offset += buffer->first) >= (size_t)buffer->size) 253 offset -= buffer->size; 254 255 if (offset + length <= (size_t)buffer->size) { 256 // simple copy 257 memcpy(data, buffer->buffer + offset, length); 258 } else { 259 // need to copy both ends 260 size_t upper = buffer->size - offset; 261 size_t lower = length - upper; 262 263 memcpy(data, buffer->buffer + offset, upper); 264 memcpy((uint8*)data + upper, buffer->buffer, lower); 265 } 266 267 return length; 268 } 269 270 271 /*! Returns iovecs describing the contents of the ring buffer. 272 273 \param buffer The ring buffer. 274 \param vecs Pointer to an iovec array with at least 2 elements to be filled 275 in by the function. 276 \return The number of iovecs the function has filled in to describe the 277 contents of the ring buffer. \c 0, if empty, \c 2 at maximum. 278 */ 279 int32 280 ring_buffer_get_vecs(struct ring_buffer* buffer, struct iovec* vecs) 281 { 282 if (buffer->in == 0) 283 return 0; 284 285 if (buffer->first + buffer->in <= buffer->size) { 286 // one element 287 vecs[0].iov_base = buffer->buffer + buffer->first; 288 vecs[0].iov_len = buffer->in; 289 return 1; 290 } 291 292 // two elements 293 size_t upper = buffer->size - buffer->first; 294 size_t lower = buffer->in - upper; 295 296 vecs[0].iov_base = buffer->buffer + buffer->first; 297 vecs[0].iov_len = upper; 298 vecs[1].iov_base = buffer->buffer; 299 vecs[1].iov_len = lower; 300 301 return 2; 302 } 303 304 305 /*! Moves data from one ring buffer to another. 306 307 \param to The destination ring buffer. 308 \param length The maximum number of bytes to move. 309 \param from The source ring buffer. 310 \return The number of bytes actually moved. 311 */ 312 size_t 313 ring_buffer_move(struct ring_buffer *to, ssize_t length, 314 struct ring_buffer *from) 315 { 316 if (length > from->in) 317 length = from->in; 318 319 if (length > (to->size - to->in)) 320 length = to->size - to->in; 321 322 size_t bytesMoved = 0; 323 324 if ((from->first + length) <= from->size) { 325 // simple move 326 bytesMoved = ring_buffer_write(to, from->buffer + from->first, length); 327 } else { 328 // need to move both ends 329 size_t upper = from->size - from->first; 330 size_t lower = length - upper; 331 332 bytesMoved = ring_buffer_write(to, from->buffer + from->first, upper); 333 if (bytesMoved == upper) { 334 // only continue writing if the first part was completely written 335 bytesMoved += ring_buffer_write(to, from->buffer, lower); 336 } 337 } 338 339 from->first = (from->first + bytesMoved) % from->size; 340 from->in -= bytesMoved; 341 342 return bytesMoved; 343 } 344 345 346 #if 0 347 /** Sends the contents of the ring buffer to a port. 348 * The buffer will be empty afterwards only if sending the data actually works. 349 */ 350 351 status_t 352 ring_buffer_write_to_port(struct ring_buffer *buffer, port_id port, int32 code, 353 uint32 flags, bigtime_t timeout) 354 { 355 int32 length = buffer->in; 356 if (length == 0) 357 return B_OK; 358 359 status_t status; 360 361 if (buffer->first + length <= buffer->size) { 362 // simple write 363 status = write_port_etc(port, code, buffer->buffer + buffer->first, length, 364 flags, timeout); 365 } else { 366 // need to write both ends 367 size_t upper = buffer->size - buffer->first; 368 size_t lower = length - upper; 369 370 iovec vecs[2]; 371 vecs[0].iov_base = buffer->buffer + buffer->first; 372 vecs[0].iov_len = upper; 373 vecs[1].iov_base = buffer->buffer; 374 vecs[1].iov_len = lower; 375 376 status = writev_port_etc(port, code, vecs, 2, length, flags, timeout); 377 } 378 379 if (status < B_OK) 380 return status; 381 382 buffer->first = (buffer->first + length) % buffer->size; 383 buffer->in -= length; 384 385 return status; 386 } 387 #endif 388