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 17 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 18 #define user_memcpy(x...) (memcpy(x), B_OK) 19 #endif 20 21 /*! This is a light-weight ring_buffer implementation. 22 * It does not provide any locking - you are supposed to ensure thread-safety 23 * with the restrictions you choose. Unless you are passing in unsafe buffers, 24 * the functions are safe to be called with interrupts turned off as well (not 25 * the user functions). 26 * They also don't use malloc() or any kind of locking after initialization. 27 */ 28 29 30 static inline int32 31 space_left_in_buffer(struct ring_buffer *buffer) 32 { 33 return buffer->size - buffer->in; 34 } 35 36 37 static ssize_t 38 read_from_buffer(struct ring_buffer *buffer, uint8 *data, ssize_t length, 39 bool user) 40 { 41 int32 available = buffer->in; 42 43 if (length > available) 44 length = available; 45 46 if (length == 0) 47 return 0; 48 49 ssize_t bytesRead = length; 50 51 if (buffer->first + length <= buffer->size) { 52 // simple copy 53 if (user) { 54 if (user_memcpy(data, buffer->buffer + buffer->first, length) < B_OK) 55 return B_BAD_ADDRESS; 56 } else 57 memcpy(data, buffer->buffer + buffer->first, length); 58 } else { 59 // need to copy both ends 60 size_t upper = buffer->size - buffer->first; 61 size_t lower = length - upper; 62 63 if (user) { 64 if (user_memcpy(data, buffer->buffer + buffer->first, upper) < B_OK 65 || user_memcpy(data + upper, buffer->buffer, lower) < B_OK) 66 return B_BAD_ADDRESS; 67 } else { 68 memcpy(data, buffer->buffer + buffer->first, upper); 69 memcpy(data + upper, buffer->buffer, lower); 70 } 71 } 72 73 buffer->first = (buffer->first + bytesRead) % buffer->size; 74 buffer->in -= bytesRead; 75 76 return bytesRead; 77 } 78 79 80 static ssize_t 81 write_to_buffer(struct ring_buffer *buffer, const uint8 *data, ssize_t length, 82 bool user) 83 { 84 int32 left = space_left_in_buffer(buffer); 85 if (length > left) 86 length = left; 87 88 if (length == 0) 89 return 0; 90 91 ssize_t bytesWritten = length; 92 int32 position = (buffer->first + buffer->in) % buffer->size; 93 94 if (position + length <= buffer->size) { 95 // simple copy 96 if (user) { 97 if (user_memcpy(buffer->buffer + position, data, length) < B_OK) 98 return B_BAD_ADDRESS; 99 } else 100 memcpy(buffer->buffer + position, data, length); 101 } else { 102 // need to copy both ends 103 size_t upper = buffer->size - position; 104 size_t lower = length - upper; 105 106 if (user) { 107 if (user_memcpy(buffer->buffer + position, data, upper) < B_OK 108 || user_memcpy(buffer->buffer, data + upper, lower) < B_OK) 109 return B_BAD_ADDRESS; 110 } else { 111 memcpy(buffer->buffer + position, data, upper); 112 memcpy(buffer->buffer, data + upper, lower); 113 } 114 } 115 116 buffer->in += bytesWritten; 117 118 return bytesWritten; 119 } 120 121 122 // #pragma mark - 123 124 125 struct ring_buffer* 126 create_ring_buffer(size_t size) 127 { 128 return create_ring_buffer_etc(NULL, size, 0); 129 } 130 131 132 struct ring_buffer* 133 create_ring_buffer_etc(void* memory, size_t size, uint32 flags) 134 { 135 if (memory == NULL) { 136 ring_buffer* buffer = (ring_buffer*)malloc(sizeof(ring_buffer) + size); 137 if (buffer == NULL) 138 return NULL; 139 140 buffer->size = size; 141 ring_buffer_clear(buffer); 142 143 return buffer; 144 } 145 146 size -= sizeof(ring_buffer); 147 ring_buffer* buffer = (ring_buffer*)memory; 148 149 buffer->size = size; 150 if ((flags & RING_BUFFER_INIT_FROM_BUFFER) != 0 151 && (size_t)buffer->size == size 152 && buffer->in >= 0 && (size_t)buffer->in <= size 153 && buffer->first >= 0 && (size_t)buffer->first < size) { 154 // structure looks valid 155 } else 156 ring_buffer_clear(buffer); 157 158 return buffer; 159 } 160 161 162 void 163 delete_ring_buffer(struct ring_buffer *buffer) 164 { 165 free(buffer); 166 } 167 168 169 void 170 ring_buffer_clear(struct ring_buffer *buffer) 171 { 172 buffer->in = 0; 173 buffer->first = 0; 174 } 175 176 177 size_t 178 ring_buffer_readable(struct ring_buffer *buffer) 179 { 180 return buffer->in; 181 } 182 183 184 size_t 185 ring_buffer_writable(struct ring_buffer *buffer) 186 { 187 return buffer->size - buffer->in; 188 } 189 190 191 void 192 ring_buffer_flush(struct ring_buffer *buffer, size_t length) 193 { 194 // we can't flush more bytes than there are 195 if (length > (size_t)buffer->in) 196 length = buffer->in; 197 198 buffer->in -= length; 199 buffer->first = (buffer->first + length) % buffer->size; 200 } 201 202 203 size_t 204 ring_buffer_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 205 { 206 return read_from_buffer(buffer, data, length, false); 207 } 208 209 210 size_t 211 ring_buffer_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 212 { 213 return write_to_buffer(buffer, data, length, false); 214 } 215 216 217 ssize_t 218 ring_buffer_user_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 219 { 220 return read_from_buffer(buffer, data, length, true); 221 } 222 223 224 ssize_t 225 ring_buffer_user_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 226 { 227 return write_to_buffer(buffer, data, length, true); 228 } 229 230 231 /*! Reads data from the ring buffer, but doesn't remove the data from it. 232 \param buffer The ring buffer. 233 \param offset The offset relative to the beginning of the data in the ring 234 buffer at which to start reading. 235 \param data The buffer to which to copy the data. 236 \param length The number of bytes to read at maximum. 237 \return The number of bytes actually read from the buffer. 238 */ 239 size_t 240 ring_buffer_peek(struct ring_buffer* buffer, size_t offset, void* data, 241 size_t length) 242 { 243 size_t available = buffer->in; 244 245 if (offset >= available || length == 0) 246 return 0; 247 248 if (offset + length > available) 249 length = available - offset; 250 251 if ((offset += buffer->first) >= (size_t)buffer->size) 252 offset -= buffer->size; 253 254 if (offset + length <= (size_t)buffer->size) { 255 // simple copy 256 memcpy(data, buffer->buffer + offset, length); 257 } else { 258 // need to copy both ends 259 size_t upper = buffer->size - offset; 260 size_t lower = length - upper; 261 262 memcpy(data, buffer->buffer + offset, upper); 263 memcpy((uint8*)data + upper, buffer->buffer, lower); 264 } 265 266 return length; 267 } 268 269 270 #if 0 271 /** Sends the contents of the ring buffer to a port. 272 * The buffer will be empty afterwards only if sending the data actually works. 273 */ 274 275 status_t 276 ring_buffer_write_to_port(struct ring_buffer *buffer, port_id port, int32 code, 277 uint32 flags, bigtime_t timeout) 278 { 279 int32 length = buffer->in; 280 if (length == 0) 281 return B_OK; 282 283 status_t status; 284 285 if (buffer->first + length <= buffer->size) { 286 // simple write 287 status = write_port_etc(port, code, buffer->buffer + buffer->first, length, 288 flags, timeout); 289 } else { 290 // need to write both ends 291 size_t upper = buffer->size - buffer->first; 292 size_t lower = length - upper; 293 294 iovec vecs[2]; 295 vecs[0].iov_base = buffer->buffer + buffer->first; 296 vecs[0].iov_len = upper; 297 vecs[1].iov_base = buffer->buffer; 298 vecs[1].iov_len = lower; 299 300 status = writev_port_etc(port, code, vecs, 2, length, flags, timeout); 301 } 302 303 if (status < B_OK) 304 return status; 305 306 buffer->first = (buffer->first + length) % buffer->size; 307 buffer->in -= length; 308 309 return status; 310 } 311 #endif 312