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