1 /* 2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ring_buffer.h" 8 9 #include <KernelExport.h> 10 #include <lock.h> 11 12 #include <stdlib.h> 13 #include <string.h> 14 15 16 /** This is a light-weight ring_buffer implementation. 17 * It does not provide any locking - you are supposed to ensure thread-safety 18 * with the restrictions you choose. Unless you are passing in unsafe buffers, 19 * the functions are safe to be called with interrupts turned off as well (not 20 * the user functions). 21 * They also don't use malloc() or any kind of locking after initialization. 22 */ 23 24 struct ring_buffer { 25 int32 first; 26 int32 in; 27 int32 size; 28 uint8 buffer[0]; 29 }; 30 31 32 static inline int32 33 space_left_in_buffer(struct ring_buffer *buffer) 34 { 35 return buffer->size - buffer->in; 36 } 37 38 39 static ssize_t 40 read_from_buffer(struct ring_buffer *buffer, uint8 *data, ssize_t length, 41 bool user) 42 { 43 int32 available = buffer->in; 44 45 if (length > available) 46 length = available; 47 48 if (length == 0) 49 return 0; 50 51 ssize_t bytesRead = length; 52 53 if (buffer->first + length <= buffer->size) { 54 // simple copy 55 if (user) { 56 if (user_memcpy(data, buffer->buffer + buffer->first, length) < B_OK) 57 return B_BAD_ADDRESS; 58 } else 59 memcpy(data, buffer->buffer + buffer->first, length); 60 } else { 61 // need to copy both ends 62 size_t upper = buffer->size - buffer->first; 63 size_t lower = length - upper; 64 65 if (user) { 66 if (user_memcpy(data, buffer->buffer + buffer->first, upper) < B_OK 67 || user_memcpy(data + upper, buffer->buffer, lower) < B_OK) 68 return B_BAD_ADDRESS; 69 } else { 70 memcpy(data, buffer->buffer + buffer->first, upper); 71 memcpy(data + upper, buffer->buffer, lower); 72 } 73 } 74 75 buffer->first = (buffer->first + bytesRead) % buffer->size; 76 buffer->in -= bytesRead; 77 78 return bytesRead; 79 } 80 81 82 static ssize_t 83 write_to_buffer(struct ring_buffer *buffer, const uint8 *data, ssize_t length, 84 bool user) 85 { 86 int32 left = space_left_in_buffer(buffer); 87 if (length > left) 88 length = left; 89 90 if (length == 0) 91 return 0; 92 93 ssize_t bytesWritten = length; 94 int32 position = (buffer->first + buffer->in) % buffer->size; 95 96 if (position + length <= buffer->size) { 97 // simple copy 98 if (user) { 99 if (user_memcpy(buffer->buffer + position, data, length) < B_OK) 100 return B_BAD_ADDRESS; 101 } else 102 memcpy(buffer->buffer + position, data, length); 103 } else { 104 // need to copy both ends 105 size_t upper = buffer->size - position; 106 size_t lower = length - upper; 107 108 if (user) { 109 if (user_memcpy(buffer->buffer + position, data, upper) < B_OK 110 || user_memcpy(buffer->buffer, data + upper, lower) < B_OK) 111 return B_BAD_ADDRESS; 112 } else { 113 memcpy(buffer->buffer + position, data, upper); 114 memcpy(buffer->buffer, data + upper, lower); 115 } 116 } 117 118 buffer->in += bytesWritten; 119 120 return bytesWritten; 121 } 122 123 124 // #pragma mark - 125 126 127 struct ring_buffer * 128 create_ring_buffer(size_t size) 129 { 130 struct ring_buffer *buffer = (ring_buffer *)malloc(sizeof(ring_buffer) + size); 131 if (buffer == NULL) 132 return NULL; 133 134 buffer->size = size; 135 ring_buffer_clear(buffer); 136 137 return buffer; 138 } 139 140 141 void 142 delete_ring_buffer(struct ring_buffer *buffer) 143 { 144 free(buffer); 145 } 146 147 148 void 149 ring_buffer_clear(struct ring_buffer *buffer) 150 { 151 buffer->in = 0; 152 buffer->first = 0; 153 } 154 155 156 size_t 157 ring_buffer_readable(struct ring_buffer *buffer) 158 { 159 return buffer->in; 160 } 161 162 163 size_t 164 ring_buffer_writable(struct ring_buffer *buffer) 165 { 166 return buffer->size - buffer->in; 167 } 168 169 170 void 171 ring_buffer_flush(struct ring_buffer *buffer, size_t length) 172 { 173 // we can't flush more bytes than there are 174 if (length > (size_t)buffer->in) 175 length = buffer->in; 176 177 buffer->in -= length; 178 buffer->first = (buffer->first + length) % buffer->size; 179 } 180 181 182 size_t 183 ring_buffer_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 184 { 185 return read_from_buffer(buffer, data, length, false); 186 } 187 188 189 size_t 190 ring_buffer_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 191 { 192 return write_to_buffer(buffer, data, length, false); 193 } 194 195 196 ssize_t 197 ring_buffer_user_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) 198 { 199 return read_from_buffer(buffer, data, length, true); 200 } 201 202 203 ssize_t 204 ring_buffer_user_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length) 205 { 206 return write_to_buffer(buffer, data, length, true); 207 } 208 209