1 /*
2 Copyright (C) 2003 Cedric Cellier, Dominique Lavault
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 */
18 #include "memspool.h"
19 #include "log.h"
20 #include "slist.h"
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 struct head {
27 	unsigned mark;
28 	unsigned size;
29 	unsigned ref_count;
30 	struct head *next, *prec;
31 	char const *caller_file;
32    size_t caller_line;
33 	char block[0];
34 };
35 
36 static unsigned size=0;
37 static unsigned used;
38 static struct head *first, *last;
39 
gltv_memspool_init(unsigned new_size)40 int gltv_memspool_init(unsigned new_size)
41 {
42 	assert(size==0);
43 	used = 0;
44 	size = new_size;
45 	first = last = NULL;
46 	return 1;
47 }
48 
gltv_memspool_end()49 void gltv_memspool_end()
50 {
51 	if (used) {
52 		struct head *ptr = first;
53 		gltv_log_warning(GLTV_LOG_MUSTSEE, "memspool_end: some memory left but asking to end !");
54 		while (ptr!=last) {
55 			gltv_log_warning(GLTV_LOG_MUSTSEE, "memspool_end: still %u at %p for %s:%u", ptr->size, ptr, ptr->caller_file, ptr->caller_line);
56 			ptr = ptr->next;
57 		};
58 		gltv_log_warning(GLTV_LOG_MUSTSEE, "memspool_end: still %u at %p for %s:%u", ptr->size, ptr, ptr->caller_file, ptr->caller_line);
59 	}
60 	size = 0;
61 }
62 
gltv_memspool_blocksize(void * mem)63 unsigned gltv_memspool_blocksize(void *mem)
64 {
65 	assert(mem && size);
66 	mem = (char*)mem - sizeof(struct head);
67 	return ((struct head*)mem)->size;
68 }
69 
gltv_memspool_refcount(void * mem)70 unsigned gltv_memspool_refcount(void *mem)
71 {
72 	assert(mem && size);
73 	mem = (char*)mem - sizeof(struct head);
74 	return ((struct head*)mem)->ref_count;
75 }
76 
gltv_memspool_isvalid(void * mem)77 char gltv_memspool_isvalid(void *mem)
78 {
79 	assert(mem && size);
80 	mem = (char*)mem - sizeof(struct head);
81 	return ((struct head*)mem)->mark==0x280176;
82 }
83 
gltv_memspool_alloc_d(unsigned requested_size,char const * file,size_t line)84 void *gltv_memspool_alloc_d(unsigned requested_size, char const *file, size_t line)
85 {
86 	char *mem;
87 	assert(size);
88 	mem = malloc(requested_size+sizeof(struct head));
89 	if (mem) {
90 		if (!first) {
91 			first = (struct head*)mem;
92 		} else {
93 			((struct head*)last)->next = (struct head*)mem;
94 		}
95 		((struct head*)mem)->mark = 0x280176;
96 		((struct head*)mem)->size = requested_size;
97 		((struct head*)mem)->ref_count = 1;
98 		((struct head*)mem)->prec = last;
99 		((struct head*)mem)->next = 0;
100 		((struct head*)mem)->caller_file = file;
101 		((struct head*)mem)->caller_line = line;
102 		last = (struct head*)mem;
103 		gltv_log_warning(GLTV_LOG_DEBUG, "memspool: alloc %d bytes at %p (used = %d) for %s:%u", requested_size, mem, used, file, line);
104 		mem += sizeof(struct head);
105 		used += requested_size;
106 	}
107 	return (void*)mem;
108 }
109 
gltv_memspool_realloc(void * mem,unsigned new_size)110 void *gltv_memspool_realloc(void *mem, unsigned new_size)
111 {
112 	char *ptr;
113 	struct head *p2;
114 	assert(size);
115 	if (!mem) {
116 		return gltv_memspool_alloc(new_size);
117 	}
118 	assert(gltv_memspool_isvalid(mem));
119 	mem = (char*)mem - sizeof(struct head);
120 	ptr = realloc(mem, new_size+sizeof(struct head));
121 	if (!ptr) return 0;
122 	used += (new_size - ((struct head*)ptr)->size);
123 	((struct head*)ptr)->size = new_size;
124 	if (mem!=first) {
125 		p2 = ((struct head*)ptr)->prec;
126 		assert(p2->mark==0x280176);
127 		p2->next = (struct head*)ptr;
128 	} else {
129 		first = (struct head*)ptr;
130 	}
131 	if (mem!=last) {
132 		p2 = ((struct head*)ptr)->next;
133 		assert(p2->mark==0x280176);
134 		p2->prec = (struct head*)ptr;
135 	} else {
136 		last = (struct head*)ptr;
137 	}
138 	gltv_log_warning(GLTV_LOG_DEBUG, "memspool: realloc %p at %p for %d bytes (used = %d)", mem, ptr, new_size, used);
139 	return ptr+sizeof(struct head);
140 }
141 
gltv_memspool_unregister(void * mem)142 void gltv_memspool_unregister(void *mem)
143 {
144 	struct head *p2;
145 	assert(size && mem);
146 	assert(gltv_memspool_isvalid(mem));
147 	mem = (char*)mem - sizeof(struct head);
148 	if (0 == --((struct head*)mem)->ref_count) {
149 		used -= ((struct head*)mem)->size;
150 		if (mem!=first) {
151 			p2 = ((struct head*)mem)->prec;
152 			assert(p2->mark==0x280176);
153 			p2->next = ((struct head*)mem)->next;
154 		} else {
155 			first = ((struct head*)mem)->next;
156 		}
157 		if (mem!=last) {
158 			p2 = ((struct head*)mem)->next;
159 			assert(p2->mark==0x280176);
160 			p2->prec = ((struct head*)mem)->prec;
161 		} else {
162 			last = ((struct head*)mem)->prec;
163 		}
164 		gltv_log_warning(GLTV_LOG_DEBUG, "memspool: free at %p (used = %d)", mem, used);
165 #ifndef NDEBUG
166 		memset(((struct head*)mem)->block, 0xce, ((struct head*)mem)->size);
167 #endif
168 		free(mem);
169 	}
170 }
171 
gltv_memspool_register(void * mem)172 int gltv_memspool_register(void *mem)
173 {
174 	/* mem MUST be the adress of the first byte of a block */
175 	assert(size && mem);
176 	assert(gltv_memspool_isvalid(mem));
177 	mem = (char*)mem - sizeof(struct head);
178 	((struct head*)mem)->ref_count++;
179 	return 1;
180 }
181 
gltv_memspool_consumption()182 int gltv_memspool_consumption()
183 {
184 	assert(size);
185 	return (100L*used)/size;
186 }
187 
gltv_memspool_print()188 void gltv_memspool_print()
189 {
190 	assert(size);
191 	if (!first) {
192 		gltv_log_warning(GLTV_LOG_MUSTSEE, "gltv_memspool_print: nothing");
193 	} else {
194 		struct head *ptr = first;
195 		do {
196 			assert(ptr->mark == 0x280176);
197 			gltv_log_warning(GLTV_LOG_MUSTSEE, "gltv_memspool_print : %u bytes at %p, created by %s:%u, referenced %u time(s)", ptr->size, ptr, ptr->caller_file, ptr->caller_line, ptr->ref_count);
198 			if (ptr==last) break;
199 			ptr = ptr->next;
200 		} while (1);
201 	}
202 }
203