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