1/* 2 * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 3 * 4 * All rights reserved. Distributed under the terms of the MIT License. 5 * 6 */ 7 8 9#include "snet_buffer.h" 10 11#include <malloc.h> 12#include <string.h> 13#include <KernelExport.h> 14 15 16struct snet_buffer { 17 struct list_link link; 18 19 uint8* buffer; 20 21 uint16 allocatedSize; 22 uint16 expectedSize; 23 uint16 puttingSize; 24 uint16 pullingSize; 25 26 void* cookie; 27}; 28 29 30snet_buffer* 31snb_create(uint16 size) 32{ 33 // TODO: pointer checking 34 35#ifdef SNB_BUFFER_ATTACHED 36 // Allocating these 2 buffers together might prevent memory fragmentation 37 snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size); 38 snb->buffer = ((uint8*)snb) + sizeof(snet_buffer); 39#else 40 snet_buffer* snb = malloc(sizeof (snet_buffer)); 41 snb->buffer = malloc(size); 42#endif 43 44 snb->pullingSize = snb->puttingSize = 0; 45 snb->expectedSize = snb->allocatedSize = size; 46 47 return snb; 48} 49 50 51void 52snb_put(snet_buffer* snb, void* data, uint16 size) 53{ 54 // TODO: check overflow 55 memcpy( &snb->buffer[snb->puttingSize], data, size); 56 snb->puttingSize+=size; 57} 58 59 60void* 61snb_pull(snet_buffer* snb, uint16 size) 62{ 63 // TODO: check overflow 64 snb->pullingSize+=size; 65 return &snb->buffer[snb->pullingSize - size]; 66 67} 68 69 70void 71snb_reset(snet_buffer* snb) 72{ 73 snb->puttingSize = snb->pullingSize = 0; 74} 75 76 77void 78snb_free(snet_buffer* snb) 79{ 80 if (snb == NULL) 81 return; 82 83#ifdef SNB_BUFFER_ATTACHED 84 free(snb); 85#else 86 free(snb->buffer); 87 free(snb); 88#endif 89 90} 91 92 93void* 94snb_get(snet_buffer* snb) 95{ 96 // TODO: pointer checking 97 return snb->buffer; 98} 99 100 101uint16 102snb_size(snet_buffer* snb) 103{ 104 // TODO: pointer checking 105 return snb->expectedSize; 106} 107 108 109void* 110snb_cookie(snet_buffer* snb) 111{ 112 // TODO: pointer checking 113 return snb->cookie; 114} 115 116 117void 118snb_set_cookie(snet_buffer* snb, void* cookie) 119{ 120 // TODO: pointer checking 121 snb->cookie = cookie; 122} 123 124 125// Return true if we canot "put" more data in the buffer 126bool 127snb_completed(snet_buffer* snb) 128{ 129 return (snb->expectedSize == snb->puttingSize); 130} 131 132 133// Return true if we cannot pull more more data from the buffer 134bool 135snb_finished(snet_buffer* snb) 136{ 137 return (snb->expectedSize == snb->pullingSize); 138} 139 140 141uint16 142snb_remaining_to_put(snet_buffer* snb) 143{ 144 return (snb->expectedSize - snb->puttingSize); 145} 146 147 148uint16 149snb_remaining_to_pull(snet_buffer* snb) 150{ 151 return (snb->expectedSize - snb->pullingSize); 152} 153 154/* 155 ISSUE1: Number of packets in the worst case(we always need a bigger 156 buffer than before) increases, never decreases: 157 158 SOL1: Delete the smallest when the queue is bigger than X elements 159 SOL2: ? 160 161 ISSUE2: If the queue is not gonna be used for long time. Memory c 162 ould be freed 163 164 SOL1: Provide purge func. 165 SOL2: ? 166*/ 167 168 169static snet_buffer* 170snb_attempt_reuse(snet_buffer* snb, uint16 size) 171{ 172 if (snb == NULL || (snb->allocatedSize < size)) { 173 174 // Impossible or not worth, Creating a new one 175 snb_free(snb); 176 return snb_create(size); 177 178 } else { 179 snb_reset(snb); 180 snb->expectedSize = size; 181 return snb; 182 } 183 184} 185 186 187void 188snb_park(struct list* l, snet_buffer* snb) 189{ 190 snet_buffer* item = NULL; 191 192 // insert it by order 193 while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) { 194 // This one has allocated more than us place us back 195 if (item->allocatedSize > snb->allocatedSize) { 196 list_insert_item_before(l, item, snb); 197 return; 198 } 199 } 200 // no buffer bigger than us(or empty).. then at the end 201 list_add_item(l, snb); 202} 203 204 205snet_buffer* 206snb_fetch(struct list* l, uint16 size) 207{ 208 snet_buffer* item = NULL; 209 snet_buffer* newitem = NULL; 210 211 if (!list_is_empty(l)) 212 while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) { 213 if (item->allocatedSize >= size) { 214 // This one is for us 215 break; 216 } 217 } 218 219 newitem = snb_attempt_reuse(item, size); 220 221 /* the resulting reused one is the same 222 * as we fetched? => remove it from list 223 */ 224 if (item == newitem) { 225 list_remove_item(l, item); 226 } 227 228 return newitem; 229} 230 231 232uint16 233snb_packets(struct list* l) 234{ 235 uint16 count = 0; 236 snet_buffer* item = NULL; 237 238 while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) 239 count++; 240 241 return count; 242} 243 244 245void 246snb_dump(snet_buffer* snb) 247{ 248 kprintf("item=%p\tprev=%p\tnext=%p\tallocated=%d\n", snb, snb->link.prev, 249 snb->link.next, snb->allocatedSize); 250} 251