1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5 
6 This file is part of Tremulous.
7 
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 /*****************************************************************************
25  * name:		l_memory.c
26  *
27  * desc:		memory allocation
28  *
29  * $Archive: /MissionPack/code/botlib/l_memory.c $
30  *
31  *****************************************************************************/
32 
33 #include "../qcommon/q_shared.h"
34 #include "botlib.h"
35 #include "l_log.h"
36 #include "be_interface.h"
37 
38 //#define MEMDEBUG
39 //#define MEMORYMANEGER
40 
41 #define MEM_ID		0x12345678l
42 #define HUNK_ID		0x87654321l
43 
44 int allocatedmemory;
45 int totalmemorysize;
46 int numblocks;
47 
48 #ifdef MEMORYMANEGER
49 
50 typedef struct memoryblock_s
51 {
52 	unsigned long int id;
53 	void *ptr;
54 	int size;
55 #ifdef MEMDEBUG
56 	char *label;
57 	char *file;
58 	int line;
59 #endif //MEMDEBUG
60 	struct memoryblock_s *prev, *next;
61 } memoryblock_t;
62 
63 memoryblock_t *memory;
64 
65 //===========================================================================
66 //
67 // Parameter:			-
68 // Returns:				-
69 // Changes Globals:		-
70 //===========================================================================
LinkMemoryBlock(memoryblock_t * block)71 void LinkMemoryBlock(memoryblock_t *block)
72 {
73 	block->prev = NULL;
74 	block->next = memory;
75 	if (memory) memory->prev = block;
76 	memory = block;
77 } //end of the function LinkMemoryBlock
78 //===========================================================================
79 //
80 // Parameter:			-
81 // Returns:				-
82 // Changes Globals:		-
83 //===========================================================================
UnlinkMemoryBlock(memoryblock_t * block)84 void UnlinkMemoryBlock(memoryblock_t *block)
85 {
86 	if (block->prev) block->prev->next = block->next;
87 	else memory = block->next;
88 	if (block->next) block->next->prev = block->prev;
89 } //end of the function UnlinkMemoryBlock
90 //===========================================================================
91 //
92 // Parameter:			-
93 // Returns:				-
94 // Changes Globals:		-
95 //===========================================================================
96 #ifdef MEMDEBUG
GetMemoryDebug(unsigned long size,char * label,char * file,int line)97 void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
98 #else
99 void *GetMemory(unsigned long size)
100 #endif //MEMDEBUG
101 {
102 	void *ptr;
103 	memoryblock_t *block;
104   assert(botimport.GetMemory); // bk001129 - was NULL'ed
105 	ptr = botimport.GetMemory(size + sizeof(memoryblock_t));
106 	block = (memoryblock_t *) ptr;
107 	block->id = MEM_ID;
108 	block->ptr = (char *) ptr + sizeof(memoryblock_t);
109 	block->size = size + sizeof(memoryblock_t);
110 #ifdef MEMDEBUG
111 	block->label = label;
112 	block->file = file;
113 	block->line = line;
114 #endif //MEMDEBUG
115 	LinkMemoryBlock(block);
116 	allocatedmemory += block->size;
117 	totalmemorysize += block->size + sizeof(memoryblock_t);
118 	numblocks++;
119 	return block->ptr;
120 } //end of the function GetMemoryDebug
121 //===========================================================================
122 //
123 // Parameter:			-
124 // Returns:				-
125 // Changes Globals:		-
126 //===========================================================================
127 #ifdef MEMDEBUG
GetClearedMemoryDebug(unsigned long size,char * label,char * file,int line)128 void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
129 #else
130 void *GetClearedMemory(unsigned long size)
131 #endif //MEMDEBUG
132 {
133 	void *ptr;
134 #ifdef MEMDEBUG
135 	ptr = GetMemoryDebug(size, label, file, line);
136 #else
137 	ptr = GetMemory(size);
138 #endif //MEMDEBUG
139 	Com_Memset(ptr, 0, size);
140 	return ptr;
141 } //end of the function GetClearedMemory
142 //===========================================================================
143 //
144 // Parameter:			-
145 // Returns:				-
146 // Changes Globals:		-
147 //===========================================================================
148 #ifdef MEMDEBUG
GetHunkMemoryDebug(unsigned long size,char * label,char * file,int line)149 void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
150 #else
151 void *GetHunkMemory(unsigned long size)
152 #endif //MEMDEBUG
153 {
154 	void *ptr;
155 	memoryblock_t *block;
156 
157 	ptr = botimport.HunkAlloc(size + sizeof(memoryblock_t));
158 	block = (memoryblock_t *) ptr;
159 	block->id = HUNK_ID;
160 	block->ptr = (char *) ptr + sizeof(memoryblock_t);
161 	block->size = size + sizeof(memoryblock_t);
162 #ifdef MEMDEBUG
163 	block->label = label;
164 	block->file = file;
165 	block->line = line;
166 #endif //MEMDEBUG
167 	LinkMemoryBlock(block);
168 	allocatedmemory += block->size;
169 	totalmemorysize += block->size + sizeof(memoryblock_t);
170 	numblocks++;
171 	return block->ptr;
172 } //end of the function GetHunkMemoryDebug
173 //===========================================================================
174 //
175 // Parameter:			-
176 // Returns:				-
177 // Changes Globals:		-
178 //===========================================================================
179 #ifdef MEMDEBUG
GetClearedHunkMemoryDebug(unsigned long size,char * label,char * file,int line)180 void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
181 #else
182 void *GetClearedHunkMemory(unsigned long size)
183 #endif //MEMDEBUG
184 {
185 	void *ptr;
186 #ifdef MEMDEBUG
187 	ptr = GetHunkMemoryDebug(size, label, file, line);
188 #else
189 	ptr = GetHunkMemory(size);
190 #endif //MEMDEBUG
191 	Com_Memset(ptr, 0, size);
192 	return ptr;
193 } //end of the function GetClearedHunkMemory
194 //===========================================================================
195 //
196 // Parameter:			-
197 // Returns:				-
198 // Changes Globals:		-
199 //===========================================================================
BlockFromPointer(void * ptr,char * str)200 memoryblock_t *BlockFromPointer(void *ptr, char *str)
201 {
202 	memoryblock_t *block;
203 
204 	if (!ptr)
205 	{
206 #ifdef MEMDEBUG
207 		//char *crash = (char *) NULL;
208 		//crash[0] = 1;
209 		botimport.Print(PRT_FATAL, "%s: NULL pointer\n", str);
210 #endif // MEMDEBUG
211 		return NULL;
212 	} //end if
213 	block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t));
214 	if (block->id != MEM_ID && block->id != HUNK_ID)
215 	{
216 		botimport.Print(PRT_FATAL, "%s: invalid memory block\n", str);
217 		return NULL;
218 	} //end if
219 	if (block->ptr != ptr)
220 	{
221 		botimport.Print(PRT_FATAL, "%s: memory block pointer invalid\n", str);
222 		return NULL;
223 	} //end if
224 	return block;
225 } //end of the function BlockFromPointer
226 //===========================================================================
227 //
228 // Parameter:			-
229 // Returns:				-
230 // Changes Globals:		-
231 //===========================================================================
FreeMemory(void * ptr)232 void FreeMemory(void *ptr)
233 {
234 	memoryblock_t *block;
235 
236 	block = BlockFromPointer(ptr, "FreeMemory");
237 	if (!block) return;
238 	UnlinkMemoryBlock(block);
239 	allocatedmemory -= block->size;
240 	totalmemorysize -= block->size + sizeof(memoryblock_t);
241 	numblocks--;
242 	//
243 	if (block->id == MEM_ID)
244 	{
245 		botimport.FreeMemory(block);
246 	} //end if
247 } //end of the function FreeMemory
248 //===========================================================================
249 //
250 // Parameter:			-
251 // Returns:				-
252 // Changes Globals:		-
253 //===========================================================================
AvailableMemory(void)254 int AvailableMemory(void)
255 {
256 	return botimport.AvailableMemory();
257 } //end of the function AvailableMemory
258 //===========================================================================
259 //
260 // Parameter:			-
261 // Returns:				-
262 // Changes Globals:		-
263 //===========================================================================
MemoryByteSize(void * ptr)264 int MemoryByteSize(void *ptr)
265 {
266 	memoryblock_t *block;
267 
268 	block = BlockFromPointer(ptr, "MemoryByteSize");
269 	if (!block) return 0;
270 	return block->size;
271 } //end of the function MemoryByteSize
272 //===========================================================================
273 //
274 // Parameter:			-
275 // Returns:				-
276 // Changes Globals:		-
277 //===========================================================================
PrintUsedMemorySize(void)278 void PrintUsedMemorySize(void)
279 {
280 	botimport.Print(PRT_MESSAGE, "total allocated memory: %d KB\n", allocatedmemory >> 10);
281 	botimport.Print(PRT_MESSAGE, "total botlib memory: %d KB\n", totalmemorysize >> 10);
282 	botimport.Print(PRT_MESSAGE, "total memory blocks: %d\n", numblocks);
283 } //end of the function PrintUsedMemorySize
284 //===========================================================================
285 //
286 // Parameter:			-
287 // Returns:				-
288 // Changes Globals:		-
289 //===========================================================================
PrintMemoryLabels(void)290 void PrintMemoryLabels(void)
291 {
292 	memoryblock_t *block;
293 	int i;
294 
295 	PrintUsedMemorySize();
296 	i = 0;
297 	Log_Write("============= Botlib memory log ==============\r\n");
298 	Log_Write("\r\n");
299 	for (block = memory; block; block = block->next)
300 	{
301 #ifdef MEMDEBUG
302 		if (block->id == HUNK_ID)
303 		{
304 			Log_Write("%6d, hunk %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label);
305 		} //end if
306 		else
307 		{
308 			Log_Write("%6d,      %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label);
309 		} //end else
310 #endif //MEMDEBUG
311 		i++;
312 	} //end for
313 } //end of the function PrintMemoryLabels
314 //===========================================================================
315 //
316 // Parameter:			-
317 // Returns:				-
318 // Changes Globals:		-
319 //===========================================================================
DumpMemory(void)320 void DumpMemory(void)
321 {
322 	memoryblock_t *block;
323 
324 	for (block = memory; block; block = memory)
325 	{
326 		FreeMemory(block->ptr);
327 	} //end for
328 	totalmemorysize = 0;
329 	allocatedmemory = 0;
330 } //end of the function DumpMemory
331 
332 #else
333 
334 //===========================================================================
335 //
336 // Parameter:			-
337 // Returns:				-
338 // Changes Globals:		-
339 //===========================================================================
340 #ifdef MEMDEBUG
GetMemoryDebug(unsigned long size,char * label,char * file,int line)341 void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
342 #else
343 void *GetMemory(unsigned long size)
344 #endif //MEMDEBUG
345 {
346 	void *ptr;
347 	unsigned long int *memid;
348 
349 	ptr = botimport.GetMemory(size + sizeof(unsigned long int));
350 	if (!ptr) return NULL;
351 	memid = (unsigned long int *) ptr;
352 	*memid = MEM_ID;
353 	return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));
354 } //end of the function GetMemory
355 //===========================================================================
356 //
357 // Parameter:			-
358 // Returns:				-
359 // Changes Globals:		-
360 //===========================================================================
361 #ifdef MEMDEBUG
GetClearedMemoryDebug(unsigned long size,char * label,char * file,int line)362 void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
363 #else
364 void *GetClearedMemory(unsigned long size)
365 #endif //MEMDEBUG
366 {
367 	void *ptr;
368 #ifdef MEMDEBUG
369 	ptr = GetMemoryDebug(size, label, file, line);
370 #else
371 	ptr = GetMemory(size);
372 #endif //MEMDEBUG
373 	Com_Memset(ptr, 0, size);
374 	return ptr;
375 } //end of the function GetClearedMemory
376 //===========================================================================
377 //
378 // Parameter:			-
379 // Returns:				-
380 // Changes Globals:		-
381 //===========================================================================
382 #ifdef MEMDEBUG
GetHunkMemoryDebug(unsigned long size,char * label,char * file,int line)383 void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
384 #else
385 void *GetHunkMemory(unsigned long size)
386 #endif //MEMDEBUG
387 {
388 	void *ptr;
389 	unsigned long int *memid;
390 
391 	ptr = botimport.HunkAlloc(size + sizeof(unsigned long int));
392 	if (!ptr) return NULL;
393 	memid = (unsigned long int *) ptr;
394 	*memid = HUNK_ID;
395 	return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));
396 } //end of the function GetHunkMemory
397 //===========================================================================
398 //
399 // Parameter:			-
400 // Returns:				-
401 // Changes Globals:		-
402 //===========================================================================
403 #ifdef MEMDEBUG
GetClearedHunkMemoryDebug(unsigned long size,char * label,char * file,int line)404 void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
405 #else
406 void *GetClearedHunkMemory(unsigned long size)
407 #endif //MEMDEBUG
408 {
409 	void *ptr;
410 #ifdef MEMDEBUG
411 	ptr = GetHunkMemoryDebug(size, label, file, line);
412 #else
413 	ptr = GetHunkMemory(size);
414 #endif //MEMDEBUG
415 	Com_Memset(ptr, 0, size);
416 	return ptr;
417 } //end of the function GetClearedHunkMemory
418 //===========================================================================
419 //
420 // Parameter:			-
421 // Returns:				-
422 // Changes Globals:		-
423 //===========================================================================
FreeMemory(void * ptr)424 void FreeMemory(void *ptr)
425 {
426 	unsigned long int *memid;
427 
428 	memid = (unsigned long int *) ((char *) ptr - sizeof(unsigned long int));
429 
430 	if (*memid == MEM_ID)
431 	{
432 		botimport.FreeMemory(memid);
433 	} //end if
434 } //end of the function FreeMemory
435 //===========================================================================
436 //
437 // Parameter:			-
438 // Returns:				-
439 // Changes Globals:		-
440 //===========================================================================
AvailableMemory(void)441 int AvailableMemory(void)
442 {
443 	return botimport.AvailableMemory();
444 } //end of the function AvailableMemory
445 //===========================================================================
446 //
447 // Parameter:			-
448 // Returns:				-
449 // Changes Globals:		-
450 //===========================================================================
PrintUsedMemorySize(void)451 void PrintUsedMemorySize(void)
452 {
453 } //end of the function PrintUsedMemorySize
454 //===========================================================================
455 //
456 // Parameter:			-
457 // Returns:				-
458 // Changes Globals:		-
459 //===========================================================================
PrintMemoryLabels(void)460 void PrintMemoryLabels(void)
461 {
462 } //end of the function PrintMemoryLabels
463 
464 #endif
465