/* * This file is part of the PCEPlib, a PCEP protocol library. * * Copyright (C) 2020 Volta Networks https://voltanet.io/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author : Brady Johnson * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "pcep_utils_logging.h" #include "pcep_utils_memory.h" /* Set default values for memory function pointers */ static pceplib_malloc_func mfunc = NULL; static pceplib_calloc_func cfunc = NULL; static pceplib_realloc_func rfunc = NULL; static pceplib_strdup_func sfunc = NULL; static pceplib_free_func ffunc = NULL; /* Internal memory types */ struct pceplib_memory_type pceplib_infra_mt = { .memory_type_name = "PCEPlib Infrastructure memory", .total_bytes_allocated = 0, .num_allocates = 0, .total_bytes_freed = 0, .num_frees = 0}; struct pceplib_memory_type pceplib_messages_mt = { .memory_type_name = "PCEPlib Messages memory", .total_bytes_allocated = 0, .num_allocates = 0, .total_bytes_freed = 0, .num_frees = 0}; /* The memory type pointers default to the internal memory types */ void *PCEPLIB_INFRA = &pceplib_infra_mt; void *PCEPLIB_MESSAGES = &pceplib_messages_mt; /* Initialize memory function pointers and memory type pointers */ bool pceplib_memory_initialize(void *pceplib_infra_mt, void *pceplib_messages_mt, pceplib_malloc_func mf, pceplib_calloc_func cf, pceplib_realloc_func rf, pceplib_strdup_func sf, pceplib_free_func ff) { PCEPLIB_INFRA = (pceplib_infra_mt ? pceplib_infra_mt : PCEPLIB_INFRA); PCEPLIB_MESSAGES = (pceplib_messages_mt ? pceplib_messages_mt : PCEPLIB_MESSAGES); mfunc = (mf ? mf : mfunc); cfunc = (cf ? cf : cfunc); rfunc = (rf ? rf : rfunc); sfunc = (sf ? sf : sfunc); ffunc = (ff ? ff : ffunc); return true; } void pceplib_memory_reset() { pceplib_infra_mt.total_bytes_allocated = 0; pceplib_infra_mt.num_allocates = 0; pceplib_infra_mt.total_bytes_freed = 0; pceplib_infra_mt.num_frees = 0; pceplib_messages_mt.total_bytes_allocated = 0; pceplib_messages_mt.num_allocates = 0; pceplib_messages_mt.total_bytes_freed = 0; pceplib_messages_mt.num_frees = 0; } void pceplib_memory_dump() { if (PCEPLIB_INFRA) { pcep_log( LOG_INFO, "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]", __func__, ((struct pceplib_memory_type *)PCEPLIB_INFRA) ->memory_type_name, ((struct pceplib_memory_type *)PCEPLIB_INFRA) ->num_allocates, ((struct pceplib_memory_type *)PCEPLIB_INFRA) ->total_bytes_allocated, ((struct pceplib_memory_type *)PCEPLIB_INFRA) ->num_frees); } if (PCEPLIB_MESSAGES) { pcep_log( LOG_INFO, "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]", __func__, ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) ->memory_type_name, ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) ->num_allocates, ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) ->total_bytes_allocated, ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) ->num_frees); } } /* PCEPlib memory functions: * They either call the supplied function pointers, or use the internal * implementations, which just increment simple counters and call the * C stdlib memory implementations. */ void *pceplib_malloc(void *mem_type, size_t size) { if (mfunc == NULL) { if (mem_type != NULL) { ((struct pceplib_memory_type *)mem_type) ->total_bytes_allocated += size; ((struct pceplib_memory_type *)mem_type) ->num_allocates++; } return malloc(size); } else { return mfunc(mem_type, size); } } void *pceplib_calloc(void *mem_type, size_t size) { if (cfunc == NULL) { if (mem_type != NULL) { ((struct pceplib_memory_type *)mem_type) ->total_bytes_allocated += size; ((struct pceplib_memory_type *)mem_type) ->num_allocates++; } return calloc(1, size); } else { return cfunc(mem_type, size); } } void *pceplib_realloc(void *mem_type, void *ptr, size_t size) { if (rfunc == NULL) { if (mem_type != NULL) { /* TODO should add previous allocated bytes to * total_bytes_freed */ ((struct pceplib_memory_type *)mem_type) ->total_bytes_allocated += size; ((struct pceplib_memory_type *)mem_type) ->num_allocates++; } return realloc(ptr, size); } else { return rfunc(mem_type, ptr, size); } } void *pceplib_strdup(void *mem_type, const char *str) { if (sfunc == NULL) { if (mem_type != NULL) { ((struct pceplib_memory_type *)mem_type) ->total_bytes_allocated += strlen(str); ((struct pceplib_memory_type *)mem_type) ->num_allocates++; } return strdup(str); } else { return sfunc(mem_type, str); } } void pceplib_free(void *mem_type, void *ptr) { if (ffunc == NULL) { if (mem_type != NULL) { /* TODO in order to increment total_bytes_freed, we need * to keep track of the bytes allocated per pointer. * Currently not implemented. */ ((struct pceplib_memory_type *)mem_type)->num_frees++; if (((struct pceplib_memory_type *)mem_type) ->num_allocates < ((struct pceplib_memory_type *)mem_type) ->num_frees) { pcep_log( LOG_ERR, "%s: pceplib_free MT N_Alloc < N_Free: MemType [%s] NumAllocates [%d] NumFrees [%d]", __func__, ((struct pceplib_memory_type *)mem_type) ->memory_type_name, ((struct pceplib_memory_type *)mem_type) ->num_allocates, ((struct pceplib_memory_type *)mem_type) ->num_frees); } } return free(ptr); } else { return ffunc(mem_type, ptr); } }