|
@@ -0,0 +1,165 @@
|
|
|
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
+ *
|
|
|
|
+ * Copyright 2018 (c) Stefan Profanter, fortiss GmbH
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * This memory manager allows to manually reduce the available RAM.
|
|
|
|
+ *
|
|
|
|
+ * It keeps track of malloc and free calls and counts the available RAM.
|
|
|
|
+ * If the requested memory allocation results in hitting the limit,
|
|
|
|
+ * it will return NULL and prevent the new allocation.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#include "custom_memory_manager.h"
|
|
|
|
+#include <stdlib.h>
|
|
|
|
+#include <stdio.h>
|
|
|
|
+#include <stdint.h>
|
|
|
|
+#include <limits.h>
|
|
|
|
+
|
|
|
|
+#include <pthread.h>
|
|
|
|
+
|
|
|
|
+pthread_mutex_t mutex;
|
|
|
|
+
|
|
|
|
+struct UA_mm_entry {
|
|
|
|
+ size_t size;
|
|
|
|
+ void* address;
|
|
|
|
+ struct UA_mm_entry *next;
|
|
|
|
+ struct UA_mm_entry *prev;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+unsigned long long totalMemorySize = 0;
|
|
|
|
+unsigned long long memoryLimit = ULONG_MAX;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Head and Tail of the double linked list
|
|
|
|
+ */
|
|
|
|
+struct UA_mm_entry *address_map_first = NULL;
|
|
|
|
+struct UA_mm_entry *address_map_last = NULL;
|
|
|
|
+
|
|
|
|
+void UA_memoryManager_setLimit(unsigned long long newLimit) {
|
|
|
|
+ memoryLimit = newLimit;
|
|
|
|
+ printf("MemoryManager: Setting memory limit to %lld\n", newLimit);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int UA_memoryManager_setLimitFromLast4Bytes(const uint8_t *data, size_t size) {
|
|
|
|
+ if (size <4)
|
|
|
|
+ return 0;
|
|
|
|
+ // just cast the last 4 bytes to uint32
|
|
|
|
+ const uint32_t *newLimit = (const void*)&(data[size-4]);
|
|
|
|
+ UA_memoryManager_setLimit(*newLimit);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Add address entry to the linked list after it was allocated.
|
|
|
|
+ *
|
|
|
|
+ * @param size Size of the allocated memory block
|
|
|
|
+ * @param addr Address of the allocated memory block
|
|
|
|
+ * @return 1 on success, 0 if it failed
|
|
|
|
+ */
|
|
|
|
+static int addToMap(size_t size, void *addr) {
|
|
|
|
+ struct UA_mm_entry *newEntry = (struct UA_mm_entry*)malloc(sizeof(struct UA_mm_entry));
|
|
|
|
+ if (!newEntry) {
|
|
|
|
+ printf("MemoryManager: Could not allocate memory");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ newEntry->size = size;
|
|
|
|
+ newEntry->address = addr;
|
|
|
|
+ newEntry->next = NULL;
|
|
|
|
+ newEntry->prev = address_map_last;
|
|
|
|
+ pthread_mutex_lock(&mutex);
|
|
|
|
+ if (address_map_last)
|
|
|
|
+ address_map_last->next = newEntry;
|
|
|
|
+ address_map_last = newEntry;
|
|
|
|
+ totalMemorySize += size;
|
|
|
|
+ if (address_map_first == NULL) {
|
|
|
|
+ address_map_first = newEntry;
|
|
|
|
+ }
|
|
|
|
+ pthread_mutex_unlock(&mutex);
|
|
|
|
+ //printf("Total size (malloc): %lld And new address: %p Entry %p\n", totalMemorySize, addr, (void*)newEntry);
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Remove entry from the list before the memory block is freed.
|
|
|
|
+ *
|
|
|
|
+ * @param addr Address of the memory block which is freed.
|
|
|
|
+ *
|
|
|
|
+ * @return 1 on success, 0 if the memory block was not found in the list.
|
|
|
|
+ */
|
|
|
|
+static int removeFromMap(void *addr) {
|
|
|
|
+ if (addr == NULL)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(&mutex);
|
|
|
|
+
|
|
|
|
+ struct UA_mm_entry *e = address_map_last;
|
|
|
|
+
|
|
|
|
+ while (e) {
|
|
|
|
+ if (e->address == addr) {
|
|
|
|
+ if (e == address_map_first)
|
|
|
|
+ address_map_first = e->next;
|
|
|
|
+ if (e == address_map_last)
|
|
|
|
+ address_map_last = e->prev;
|
|
|
|
+ if (e->prev) {
|
|
|
|
+ e->prev->next = e->next;
|
|
|
|
+ }
|
|
|
|
+ if (e->next) {
|
|
|
|
+ e->next->prev = e->prev;
|
|
|
|
+ }
|
|
|
|
+ totalMemorySize -= e->size;
|
|
|
|
+
|
|
|
|
+ //printf("Total size (free): %lld after addr %p and deleting %p\n", totalMemorySize, addr, (void*)e);
|
|
|
|
+ free(e);
|
|
|
|
+ pthread_mutex_unlock(&mutex);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ e = e->prev;
|
|
|
|
+ }
|
|
|
|
+ pthread_mutex_unlock(&mutex);
|
|
|
|
+ printf("MemoryManager: Entry with address %p not found", addr);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void* UA_memoryManager_malloc(size_t size) {
|
|
|
|
+ if (totalMemorySize + size > memoryLimit)
|
|
|
|
+ return NULL;
|
|
|
|
+ void *addr = malloc(size);
|
|
|
|
+ if (!addr)
|
|
|
|
+ return NULL;
|
|
|
|
+ addToMap(size, addr);
|
|
|
|
+ return addr;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void* UA_memoryManager_calloc(size_t num, size_t size) {
|
|
|
|
+ if (totalMemorySize + (size * num) > memoryLimit)
|
|
|
|
+ return NULL;
|
|
|
|
+ void *addr = calloc(num, size);
|
|
|
|
+ if (!addr)
|
|
|
|
+ return NULL;
|
|
|
|
+ addToMap(size*num, addr);
|
|
|
|
+ return addr;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void* UA_memoryManager_realloc(void *ptr, size_t new_size) {
|
|
|
|
+ removeFromMap(ptr);
|
|
|
|
+ if (totalMemorySize + new_size > memoryLimit)
|
|
|
|
+ return NULL;
|
|
|
|
+ void *addr = realloc(ptr, new_size);
|
|
|
|
+ if (!addr)
|
|
|
|
+ return NULL;
|
|
|
|
+ addToMap(new_size, addr);
|
|
|
|
+ return addr;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void UA_memoryManager_free(void* ptr) {
|
|
|
|
+ removeFromMap(ptr);
|
|
|
|
+ free(ptr);
|
|
|
|
+}
|
|
|
|
+
|