custom_memory_manager.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2018 (c) Stefan Profanter, fortiss GmbH
  6. */
  7. /**
  8. * This memory manager allows to manually reduce the available RAM.
  9. *
  10. * It keeps track of malloc and free calls and counts the available RAM.
  11. * If the requested memory allocation results in hitting the limit,
  12. * it will return NULL and prevent the new allocation.
  13. */
  14. #include "custom_memory_manager.h"
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <stdint.h>
  18. #include <limits.h>
  19. #include <pthread.h>
  20. pthread_mutex_t mutex;
  21. struct UA_mm_entry {
  22. size_t size;
  23. void* address;
  24. struct UA_mm_entry *next;
  25. struct UA_mm_entry *prev;
  26. };
  27. unsigned long long totalMemorySize = 0;
  28. unsigned long long memoryLimit = ULONG_MAX;
  29. /*
  30. * Head and Tail of the double linked list
  31. */
  32. struct UA_mm_entry *address_map_first = NULL;
  33. struct UA_mm_entry *address_map_last = NULL;
  34. void UA_memoryManager_setLimit(unsigned long long newLimit) {
  35. memoryLimit = newLimit;
  36. printf("MemoryManager: Setting memory limit to %lld\n", newLimit);
  37. }
  38. int UA_memoryManager_setLimitFromLast4Bytes(const uint8_t *data, size_t size) {
  39. if (size <4)
  40. return 0;
  41. // just cast the last 4 bytes to uint32
  42. const uint32_t *newLimit = (const void*)&(data[size-4]);
  43. UA_memoryManager_setLimit(*newLimit);
  44. return 1;
  45. }
  46. /**
  47. * Add address entry to the linked list after it was allocated.
  48. *
  49. * @param size Size of the allocated memory block
  50. * @param addr Address of the allocated memory block
  51. * @return 1 on success, 0 if it failed
  52. */
  53. static int addToMap(size_t size, void *addr) {
  54. struct UA_mm_entry *newEntry = (struct UA_mm_entry*)malloc(sizeof(struct UA_mm_entry));
  55. if (!newEntry) {
  56. printf("MemoryManager: Could not allocate memory");
  57. return 0;
  58. }
  59. newEntry->size = size;
  60. newEntry->address = addr;
  61. newEntry->next = NULL;
  62. newEntry->prev = address_map_last;
  63. pthread_mutex_lock(&mutex);
  64. if (address_map_last)
  65. address_map_last->next = newEntry;
  66. address_map_last = newEntry;
  67. totalMemorySize += size;
  68. if (address_map_first == NULL) {
  69. address_map_first = newEntry;
  70. }
  71. pthread_mutex_unlock(&mutex);
  72. //printf("Total size (malloc): %lld And new address: %p Entry %p\n", totalMemorySize, addr, (void*)newEntry);
  73. return 1;
  74. }
  75. /**
  76. * Remove entry from the list before the memory block is freed.
  77. *
  78. * @param addr Address of the memory block which is freed.
  79. *
  80. * @return 1 on success, 0 if the memory block was not found in the list.
  81. */
  82. static int removeFromMap(void *addr) {
  83. if (addr == NULL)
  84. return 1;
  85. pthread_mutex_lock(&mutex);
  86. struct UA_mm_entry *e = address_map_last;
  87. while (e) {
  88. if (e->address == addr) {
  89. if (e == address_map_first)
  90. address_map_first = e->next;
  91. if (e == address_map_last)
  92. address_map_last = e->prev;
  93. if (e->prev) {
  94. e->prev->next = e->next;
  95. }
  96. if (e->next) {
  97. e->next->prev = e->prev;
  98. }
  99. totalMemorySize -= e->size;
  100. //printf("Total size (free): %lld after addr %p and deleting %p\n", totalMemorySize, addr, (void*)e);
  101. free(e);
  102. pthread_mutex_unlock(&mutex);
  103. return 1;
  104. }
  105. e = e->prev;
  106. }
  107. pthread_mutex_unlock(&mutex);
  108. printf("MemoryManager: Entry with address %p not found", addr);
  109. return 0;
  110. }
  111. void* UA_memoryManager_malloc(size_t size) {
  112. if (totalMemorySize + size > memoryLimit)
  113. return NULL;
  114. void *addr = malloc(size);
  115. if (!addr)
  116. return NULL;
  117. addToMap(size, addr);
  118. return addr;
  119. }
  120. void* UA_memoryManager_calloc(size_t num, size_t size) {
  121. if (totalMemorySize + (size * num) > memoryLimit)
  122. return NULL;
  123. void *addr = calloc(num, size);
  124. if (!addr)
  125. return NULL;
  126. addToMap(size*num, addr);
  127. return addr;
  128. }
  129. void* UA_memoryManager_realloc(void *ptr, size_t new_size) {
  130. removeFromMap(ptr);
  131. if (totalMemorySize + new_size > memoryLimit)
  132. return NULL;
  133. void *addr = realloc(ptr, new_size);
  134. if (!addr)
  135. return NULL;
  136. addToMap(new_size, addr);
  137. return addr;
  138. }
  139. void UA_memoryManager_free(void* ptr) {
  140. removeFromMap(ptr);
  141. free(ptr);
  142. }