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 16 struct 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 30 snet_buffer* 31 snb_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 51 void 52 snb_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 60 void* 61 snb_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 70 void 71 snb_reset(snet_buffer* snb) 72 { 73 snb->puttingSize = snb->pullingSize = 0; 74 } 75 76 77 void 78 snb_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 93 void* 94 snb_get(snet_buffer* snb) 95 { 96 // TODO: pointer checking 97 return snb->buffer; 98 } 99 100 101 uint16 102 snb_size(snet_buffer* snb) 103 { 104 // TODO: pointer checking 105 return snb->expectedSize; 106 } 107 108 109 void* 110 snb_cookie(snet_buffer* snb) 111 { 112 // TODO: pointer checking 113 return snb->cookie; 114 } 115 116 117 void 118 snb_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 126 bool 127 snb_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 134 bool 135 snb_finished(snet_buffer* snb) 136 { 137 return (snb->expectedSize == snb->pullingSize); 138 } 139 140 141 uint16 142 snb_remaining_to_put(snet_buffer* snb) 143 { 144 return (snb->expectedSize - snb->puttingSize); 145 } 146 147 148 uint16 149 snb_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 169 static snet_buffer* 170 snb_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 187 void 188 snb_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 205 snet_buffer* 206 snb_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 232 uint16 233 snb_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 245 void 246 snb_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