1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * 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 this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 
24 #include "sword1/memman.h"
25 #include "common/textconsole.h"
26 #include "common/util.h"
27 
28 namespace Sword1 {
29 
MemMan()30 MemMan::MemMan() {
31 	_alloced = 0;
32 	_memListFree = _memListFreeEnd = NULL;
33 }
34 
~MemMan()35 MemMan::~MemMan() {
36 	flush();
37 	if (_alloced)
38 		warning("deleting MemMan, still %d bytes alloced", _alloced);
39 }
40 
alloc(MemHandle * bsMem,uint32 pSize,uint16 pCond)41 void MemMan::alloc(MemHandle *bsMem, uint32 pSize, uint16 pCond) {
42 	_alloced += pSize;
43 	bsMem->data = (void *)malloc(pSize);
44 	if (!bsMem->data)
45 		error("MemMan::alloc(): Can't alloc %d bytes of memory.", pSize);
46 	bsMem->cond = pCond;
47 	bsMem->size = pSize;
48 	if (pCond == MEM_CAN_FREE) {
49 		warning("%d Bytes alloced as FREEABLE.", pSize); // why should one want to alloc mem if it can be freed?
50 		addToFreeList(bsMem);
51 	} else if (bsMem->next || bsMem->prev) // it's in our _freeAble list, remove it from there
52 		removeFromFreeList(bsMem);
53 	checkMemoryUsage();
54 }
55 
freeNow(MemHandle * bsMem)56 void MemMan::freeNow(MemHandle *bsMem) {
57 	if (bsMem->cond != MEM_FREED) {
58 		_alloced -= bsMem->size;
59 		removeFromFreeList(bsMem);
60 		free(bsMem->data);
61 		bsMem->cond = MEM_FREED;
62 	}
63 }
64 
setCondition(MemHandle * bsMem,uint16 pCond)65 void MemMan::setCondition(MemHandle *bsMem, uint16 pCond) {
66 	if ((pCond == MEM_FREED) || (pCond > MEM_DONT_FREE))
67 		error("MemMan::setCondition: program tried to set illegal memory condition");
68 	if (bsMem->cond != pCond) {
69 		bsMem->cond = pCond;
70 		if (pCond == MEM_DONT_FREE)
71 			removeFromFreeList(bsMem);
72 		else if (pCond == MEM_CAN_FREE)
73 			addToFreeList(bsMem);
74 	}
75 }
76 
flush()77 void MemMan::flush() {
78 	while (_memListFree) {
79 		free(_memListFreeEnd->data);
80 		_memListFreeEnd->data = NULL;
81 		_memListFreeEnd->cond = MEM_FREED;
82 		_alloced -= _memListFreeEnd->size;
83 		removeFromFreeList(_memListFreeEnd);
84 	}
85 	if (_alloced)
86 		warning("MemMan::flush: Something's wrong: still %d bytes alloced", _alloced);
87 }
88 
checkMemoryUsage()89 void MemMan::checkMemoryUsage() {
90 	while ((_alloced > MAX_ALLOC) && _memListFree) {
91 		free(_memListFreeEnd->data);
92 		_memListFreeEnd->data = NULL;
93 		_memListFreeEnd->cond = MEM_FREED;
94 		_alloced -= _memListFreeEnd->size;
95 		removeFromFreeList(_memListFreeEnd);
96 	}
97 }
98 
addToFreeList(MemHandle * bsMem)99 void MemMan::addToFreeList(MemHandle *bsMem) {
100 	if (bsMem->next || bsMem->prev) {
101 		warning("addToFreeList: mem block is already in freeList");
102 		return;
103 	}
104 	bsMem->prev = NULL;
105 	bsMem->next = _memListFree;
106 	if (bsMem->next)
107 		bsMem->next->prev = bsMem;
108 	_memListFree = bsMem;
109 	if (!_memListFreeEnd)
110 		_memListFreeEnd = _memListFree;
111 }
112 
removeFromFreeList(MemHandle * bsMem)113 void MemMan::removeFromFreeList(MemHandle *bsMem) {
114 	if (_memListFree == bsMem)
115 		_memListFree = bsMem->next;
116 	if (_memListFreeEnd == bsMem)
117 		_memListFreeEnd = bsMem->prev;
118 
119 	if (bsMem->next)
120 		bsMem->next->prev = bsMem->prev;
121 	if (bsMem->prev)
122 		bsMem->prev->next = bsMem->next;
123 	bsMem->next = bsMem->prev = NULL;
124 }
125 
initHandle(MemHandle * bsMem)126 void MemMan::initHandle(MemHandle *bsMem) {
127 	memset(bsMem, 0, sizeof(MemHandle));
128 }
129 
130 } // End of namespace Sword1
131