00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <assert.h>
00043 #include <errno.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046
00047 #include "common/list.h"
00048 #include "common/avl.h"
00049 #include "common/avl_comp.h"
00050 #include "olsr.h"
00051 #include "defs.h"
00052 #include "olsr_memcookie.h"
00053 #include "olsr_logging.h"
00054
00055 struct avl_tree olsr_cookie_tree;
00056
00062 static INLINE size_t
00063 calc_aligned_size(size_t size) {
00064 static const size_t add = sizeof(size_t) * 2 - 1;
00065 static const size_t mask = ~(sizeof(size_t)*2 - 1);
00066
00067 return (size + add) & mask;
00068 }
00069
00074 static INLINE void
00075 olsr_cookie_usage_incr(struct olsr_memcookie_info *ci)
00076 {
00077 ci->ci_usage++;
00078 ci->ci_changes++;
00079 }
00080
00085 static INLINE void
00086 olsr_cookie_usage_decr(struct olsr_memcookie_info *ci)
00087 {
00088 ci->ci_usage--;
00089 ci->ci_changes++;
00090 }
00091
00095 void
00096 olsr_memcookie_init(void) {
00097
00098 assert (sizeof(struct olsr_memory_prefix)
00099 == calc_aligned_size(sizeof(struct olsr_memory_prefix)));
00100
00101 avl_init(&olsr_cookie_tree, &avl_comp_strcasecmp, false, NULL);
00102 }
00103
00107 void
00108 olsr_memcookie_cleanup(void)
00109 {
00110 struct olsr_memcookie_info *info, *iterator;
00111
00112 if (olsr_cookie_tree.comp == NULL) {
00113
00114 return;
00115 }
00116
00117
00118
00119
00120 OLSR_FOR_ALL_COOKIES(info, iterator) {
00121 olsr_memcookie_remove(info);
00122 }
00123 }
00124
00131 struct olsr_memcookie_info *
00132 olsr_memcookie_add(const char *cookie_name, size_t size)
00133 {
00134 struct olsr_memcookie_info *ci;
00135
00136 assert (cookie_name);
00137 ci = olsr_malloc(sizeof(struct olsr_memcookie_info), "memory cookie");
00138
00139
00140 ci->ci_name = olsr_strdup(cookie_name);
00141 ci->ci_node.key = ci->ci_name;
00142 ci->ci_size = size;
00143 ci->ci_custom_offset = sizeof(struct olsr_memory_prefix) + calc_aligned_size(size);
00144 ci->ci_min_free_count = COOKIE_FREE_LIST_THRESHOLD;
00145
00146
00147 ci->ci_total_size = ci->ci_custom_offset;
00148
00149
00150 list_init_head(&ci->ci_free_list);
00151 list_init_head(&ci->ci_used_list);
00152 list_init_head(&ci->ci_custom_list);
00153
00154 avl_insert(&olsr_cookie_tree, &ci->ci_node);
00155 return ci;
00156 }
00157
00162 void
00163 olsr_memcookie_remove(struct olsr_memcookie_info *ci)
00164 {
00165 struct olsr_memory_prefix *memory_entity, *iterator;
00166
00167
00168 avl_delete(&olsr_cookie_tree, &ci->ci_node);
00169
00170
00171 free(ci->ci_name);
00172
00173
00174
00175
00176
00177
00178
00179
00180 OLSR_FOR_ALL_FREE_MEM(ci, memory_entity, iterator) {
00181 free(memory_entity);
00182 }
00183
00184
00185 OLSR_FOR_ALL_USED_MEM(ci, memory_entity, iterator) {
00186 free(memory_entity->custom);
00187 free(memory_entity);
00188 }
00189
00190 free(ci);
00191 }
00192
00198 void *
00199 olsr_memcookie_malloc(struct olsr_memcookie_info *ci)
00200 {
00201 struct olsr_memory_prefix *mem;
00202 struct olsr_memcookie_custom *custom, *iterator;
00203
00204 #if !defined REMOVE_LOG_DEBUG
00205 bool reuse = false;
00206 #endif
00207
00208
00209
00210
00211 if (list_is_empty(&ci->ci_free_list)) {
00212
00213
00214
00215
00216 mem = olsr_malloc(ci->ci_total_size, ci->ci_name);
00217 } else {
00218
00219
00220
00221
00222 mem = list_first_element(&ci->ci_free_list, mem, node);
00223 list_remove(&mem->node);
00224
00225 memset(mem, 0, ci->ci_total_size);
00226
00227 ci->ci_free_list_usage--;
00228 #if !defined REMOVE_LOG_DEBUG
00229 reuse = true;
00230 #endif
00231 }
00232
00233
00234 list_add_tail(&ci->ci_used_list, &mem->node);
00235
00236
00237 if (!list_is_empty(&ci->ci_custom_list)) {
00238 mem->custom = ((uint8_t *)mem) + ci->ci_custom_offset;
00239
00240
00241 OLSR_FOR_ALL_CUSTOM_MEM(ci, custom, iterator) {
00242 if (custom->init) {
00243 custom->init(ci, mem + 1, mem->custom + custom->offset);
00244 }
00245 }
00246 }
00247
00248
00249 olsr_cookie_usage_incr(ci);
00250
00251 OLSR_DEBUG(LOG_COOKIE, "MEMORY: alloc %s, %p, %lu bytes%s\n",
00252 ci->ci_name, mem + 1, (unsigned long)ci->ci_size, reuse ? ", reuse" : "");
00253 return mem + 1;
00254 }
00255
00261 void
00262 olsr_memcookie_free(struct olsr_memcookie_info *ci, void *ptr)
00263 {
00264 struct olsr_memory_prefix *mem;
00265 #if !defined REMOVE_LOG_DEBUG
00266 bool reuse = false;
00267 #endif
00268
00269
00270 mem = ptr;
00271 mem--;
00272
00273
00274 list_remove(&mem->node);
00275
00276
00277
00278
00279
00280
00281 if (mem->is_inline && ((ci->ci_free_list_usage < ci->ci_min_free_count)
00282 || (ci->ci_free_list_usage < ci->ci_usage / COOKIE_FREE_LIST_THRESHOLD))) {
00283
00284 list_add_tail(&ci->ci_free_list, &mem->node);
00285
00286 ci->ci_free_list_usage++;
00287 #if !defined REMOVE_LOG_DEBUG
00288 reuse = true;
00289 #endif
00290 } else {
00291
00292
00293 if (!mem->is_inline) {
00294 free (mem->custom);
00295 }
00296 free(mem);
00297 }
00298
00299
00300 olsr_cookie_usage_decr(ci);
00301
00302 OLSR_DEBUG(LOG_COOKIE, "MEMORY: free %s, %p, %lu bytes%s\n",
00303 ci->ci_name, ptr, (unsigned long)ci->ci_total_size, reuse ? ", reuse" : "");
00304 }
00305
00327 struct olsr_memcookie_custom *
00328 olsr_memcookie_add_custom(const char *memcookie_name, const char *name, size_t size,
00329 void (*init)(struct olsr_memcookie_info *, void *, void *),
00330 void (*move)(struct olsr_memcookie_info *, void *, void *)) {
00331 struct olsr_memcookie_info *ci;
00332 struct olsr_memcookie_custom *custom_cookie;
00333 struct olsr_memcookie_custom *custom = NULL, *custom_iterator;
00334 struct olsr_memory_prefix *mem, *mem_iterator;
00335 size_t old_total_size, new_total_size;
00336
00337 ci = avl_find_element(&olsr_cookie_tree, memcookie_name, ci, ci_node);
00338 if (ci == NULL) {
00339 OLSR_WARN(LOG_COOKIE, "Memory cookie '%s' does not exist, cannot add custom block '%s'\n",
00340 memcookie_name, name);
00341 return NULL;
00342 }
00343
00344 custom_cookie = olsr_malloc(sizeof(struct olsr_memcookie_custom), name);
00345 custom_cookie->name = strdup(name);
00346 custom_cookie->size = calc_aligned_size(size);
00347 custom_cookie->init = init;
00348 custom_cookie->move = move;
00349
00350
00351 old_total_size = ci->ci_total_size - ci->ci_custom_offset;
00352 new_total_size = old_total_size + custom_cookie->size;
00353
00354 custom_cookie->offset = old_total_size;
00355 ci->ci_total_size += custom_cookie->size;
00356
00357
00358 OLSR_FOR_ALL_USED_MEM(ci, mem, mem_iterator) {
00359 uint8_t *new_custom;
00360
00361 new_custom = olsr_malloc(new_total_size, ci->ci_name);
00362
00363
00364 if (old_total_size > 0) {
00365 memmove(new_custom, mem->custom, old_total_size);
00366 }
00367
00368 mem->is_inline = false;
00369 mem->custom = new_custom;
00370
00371
00372 if (custom->init) {
00373 custom->init(ci, mem + 1, new_custom + old_total_size);
00374 }
00375
00376
00377 OLSR_FOR_ALL_CUSTOM_MEM(ci, custom, custom_iterator) {
00378 if (custom->move) {
00379 custom->move(ci, mem+1, new_custom + custom->offset);
00380 }
00381 }
00382 }
00383
00384
00385 OLSR_FOR_ALL_FREE_MEM(ci, mem, mem_iterator) {
00386 list_remove(&mem->node);
00387 free(mem);
00388 }
00389 ci->ci_free_list_usage = 0;
00390
00391
00392 list_add_tail(&ci->ci_custom_list, &custom_cookie->node);
00393 return custom_cookie;
00394 }
00395
00401 void
00402 olsr_memcookie_remove_custom(const char*memcookie_name, struct olsr_memcookie_custom *custom) {
00403 struct olsr_memcookie_info *ci;
00404 struct olsr_memory_prefix *mem, *mem_iterator;
00405 struct olsr_memcookie_custom *c_ptr, *c_iterator;
00406 size_t prefix_block, suffix_block;
00407 bool match;
00408
00409 ci = avl_find_element(&olsr_cookie_tree, memcookie_name, ci, ci_node);
00410 if (ci == NULL) {
00411 OLSR_WARN(LOG_COOKIE, "Memory cookie '%s' does not exist, cannot remove custom block '%s'\n",
00412 memcookie_name, custom->name);
00413 return;
00414 }
00415
00416 prefix_block = 0;
00417 suffix_block = 0;
00418 match = false;
00419
00420
00421 OLSR_FOR_ALL_CUSTOM_MEM(ci, c_ptr, c_iterator) {
00422 if (c_ptr == custom) {
00423 match = true;
00424 continue;
00425 }
00426
00427 if (match) {
00428 suffix_block += c_ptr->size;
00429 }
00430 else {
00431 prefix_block += c_ptr->size;
00432 }
00433 }
00434
00435
00436 if (suffix_block > 0) {
00437 OLSR_FOR_ALL_USED_MEM(ci, mem, mem_iterator) {
00438 memmove(mem->custom + prefix_block, mem->custom + prefix_block + custom->size, suffix_block);
00439
00440
00441 OLSR_FOR_ALL_CUSTOM_MEM(ci, c_ptr, c_iterator) {
00442 if (c_ptr == custom) {
00443 match = true;
00444 continue;
00445 }
00446
00447 if (match) {
00448 c_ptr->offset -= custom->size;
00449
00450 if (c_ptr->move) {
00451 c_ptr->move(ci, mem+1, mem->custom + c_ptr->offset);
00452 }
00453 }
00454 }
00455
00456 }
00457 }
00458 ci->ci_total_size -= custom->size;
00459
00460
00461 OLSR_FOR_ALL_FREE_MEM(ci, mem, mem_iterator) {
00462 list_remove(&mem->node);
00463 free(mem);
00464 }
00465 ci->ci_free_list_usage = 0;
00466
00467
00468 list_remove(&custom->node);
00469 free (custom->name);
00470 free (custom);
00471 }
00472
00473
00474
00475
00476
00477
00478
00479