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