amath  1.8.5
Simple command line calculator
mem.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * Project homepage:
26  * https://amath.innolan.net
27  *
28  */
29 
30 #include "amathc.h"
31 
32 #if defined(AMIGA)
33 #include <stddef.h>
34 #include <exec/types.h>
35 #include <exec/memory.h>
36 #include <exec/semaphores.h>
37 #include <clib/exec_protos.h>
38 #define ALLOC_MEM(x) AllocVec(x, MEMF_ANY | MEMF_CLEAR)
39 #define FREE_MEM(x) FreeVec(x)
40 #define Debug(x,y,z)
41 #else
42 #include <stdlib.h>
43 #define ALLOC_MEM(x) calloc(1L,x)
44 #define FREE_MEM(x) free(x)
45 #define Debug(x,y,z)
46 #endif
47 
48 #if defined(__x86_64__) || defined(__aarch64__) ||
49  defined(_M_AMD64) || defined(_M_ARM64) ||
50  defined(__powerpc64__)
51 #define P64BIT
52 #endif
53 
54 /**
55  * @brief Block of allocated memory.
56  */
58 {
59  struct MemoryBlock* next;
60  size_t size;
61  void* address;
62 };
63 
64 /**
65  * @brief List of allocated memory. Uses the LIFO principle.
66  */
67 struct MemoryList
68 {
69  struct MemoryBlock* first;
70  size_t peak;
71  size_t size;
72  long count;
73 };
74 
75 /**
76  * @brief Global list of allocated memory.
77  */
78 struct MemoryList* list = nullptr;
79 
80 void alloc_error(char*, size_t);
81 void dealloc_error(char*, void*);
82 
83 /**
84  * @brief Allocate memory and add it to the global memory list.
85  */
86 void* AllocMemSafe(size_t size)
87 {
88  struct MemoryBlock* newblock;
89  size_t allocsize;
90 
91  if (list == nullptr)
92  {
93  list = (struct MemoryList*)ALLOC_MEM(sizeof(struct MemoryList));
94  if (!list)
95  {
96  alloc_error("list", sizeof(struct MemoryList));
97  return 0;
98  }
99 
100  list->first = nullptr;
101  list->peak = 0;
102  list->size = 0;
103  list->count = 0;
104  }
105 
106 #ifdef P64BIT
107  // Align to bytes of 8
108  allocsize = (size + 7) & ~0x07;
109 #else
110  // Align to bytes of 4
111  allocsize = (size + 3) & ~0x03;
112 #endif
113 
114  newblock = (struct MemoryBlock*)ALLOC_MEM(sizeof(struct MemoryBlock));
115  if (!newblock)
116  {
117  alloc_error("block", sizeof(struct MemoryBlock));
118  return 0;
119  }
120 
121  newblock->address = (struct MemoryBlock*)ALLOC_MEM(allocsize);
122  if (!newblock->address)
123  {
124  FREE_MEM(newblock);
125  alloc_error("memory", allocsize);
126  return 0;
127  }
128 
129  newblock->size = allocsize;
130  newblock->next = list->first;
131  list->first = newblock;
132  list->size += allocsize;
133  list->count++;
134 
135  if (list->size > list->peak)
136  {
138  }
139 
140  // Memory allocated
141  return newblock->address;
142 }
143 
144 void RemoveMemSafe(void* block, bool deallocate)
145 {
146  struct MemoryBlock *current, *previous;
147 
148  if (list == nullptr || block == nullptr)
149  {
150  dealloc_error("list", 0);
151  return;
152  }
153 
154  if (block == nullptr)
155  {
156  dealloc_error("memory", 0);
157  return;
158  }
159 
160  previous = nullptr;
161  current = list->first;
162  while (current != nullptr && current->address != block)
163  {
164  previous = current;
165  current = current->next;
166  }
167 
168  if (current == nullptr)
169  {
170  dealloc_error("address not found", block);
171  return;
172  }
173 
174  if (previous == nullptr)
175  {
176  list->first = current->next;
177  }
178  else
179  {
180  previous->next = current->next;
181  }
182 
183  list->size -= current->size;
184  list->count--;
185 
186  if (deallocate)
187  {
188  FREE_MEM(current->address);
189  }
190 
191  current->address = nullptr;
192  current->next = nullptr;
193  current->size = 0;
194  FREE_MEM(current);
195 }
196 
197 /**
198  * @brief Deallocate memory from the global memory list.
199  */
200 void FreeMemSafe(void* block)
201 {
202  RemoveMemSafe(block, true);
203 }
204 
205 /**
206  * @brief Detach an allocated memory from the global memory list.
207  * @details The memory block is only detached, not deallocated.
208  */
209 void DetachMemSafe(void* block)
210 {
211  RemoveMemSafe(block, false);
212 }
213 
214 /**
215  * @brief Deallocate all memory in the global memory list.
216  */
218 {
219  struct MemoryBlock *current, *next;
220 
221  if (list == nullptr)
222  {
223  return;
224  }
225 
226  current = list->first;
227  while (current != nullptr)
228  {
229  next = current->next;
230  FREE_MEM(current->address);
231  FREE_MEM(current);
232  current = next;
233  }
234 
235  FREE_MEM(list);
236  list = nullptr;
237 }
238 
239 /**
240  * @brief Get memory usage in the global memory list.
241  */
242 void MemUsage(long* blocks, long* size, long* peak)
243 {
244  *blocks = list->count;
245  *size = (long)list->size;
246  *peak = (long)list->peak;;
247 }
248 
249 /**
250  * @brief Log a memory allocation error
251  */
252 void alloc_error(char* descr, size_t size)
253 {
254  Debug("Memory allocation error (%s) with size (%d)\n", descr, size);
255  //if (size == 0)
256  // exit(10);
257 }
258 
259 /**
260  * @brief Log a memory deallocation error
261  */
262 void dealloc_error(char* descr, void* p)
263 {
264  Debug("Memory deallocation error (%s) address (%x)\n", descr, p);
265 }
struct MemoryBlock * first
Definition: mem.c:69
size_t peak
Definition: mem.c:70
long count
Definition: mem.c:72
#define Debug(x, y, z)
Definition: mem.c:45
void alloc_error(char *, size_t)
Log a memory allocation error.
Definition: mem.c:252
size_t size
Definition: mem.c:71
struct MemoryBlock * next
Definition: mem.c:59
Block of allocated memory.
Definition: mem.c:57
void * address
Definition: mem.c:61
#define ALLOC_MEM(x)
Definition: mem.c:43
void MemUsage(long *blocks, long *size, long *peak)
Get memory usage in the global memory list.
Definition: mem.c:242
struct MemoryList * list
Global list of allocated memory.
Definition: mem.c:78
void RemoveMemSafe(void *block, bool deallocate)
Definition: mem.c:144
void * AllocMemSafe(size_t size)
Allocate memory and add it to the global memory list.
Definition: mem.c:86
size_t size
Definition: mem.c:60
void FreeMemSafe(void *block)
Deallocate memory from the global memory list.
Definition: mem.c:200
void dealloc_error(char *, void *)
Log a memory deallocation error.
Definition: mem.c:262
#define FREE_MEM(x)
Definition: mem.c:44
void FreeAllSafe()
Deallocate all memory in the global memory list.
Definition: mem.c:217
List of allocated memory. Uses the LIFO principle.
Definition: mem.c:67
void DetachMemSafe(void *block)
Detach an allocated memory from the global memory list.
Definition: mem.c:209