chiark / gitweb /
Initial revision
[mLib] / track.c
CommitLineData
0875b58f 1/* -*-c-*-
2 *
3 * $Id: track.c,v 1.1 1998/06/17 23:44:42 mdw Exp $
4 *
5 * Tracing functions for debugging
6 *
7 * (c) 1998 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with mLib; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: track.c,v $
32 * Revision 1.1 1998/06/17 23:44:42 mdw
33 * Initial revision
34 *
35 */
36
37/*----- Header files ------------------------------------------------------*/
38
39/* --- ANSI headers --- */
40
41#include <ctype.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47/* --- Local headers --- */
48
49#include "trace.h"
50#include "track.h"
51
52/*----- Type definitions --------------------------------------------------*/
53
54/* --- A track block --- *
55 *
56 * This gets prefixed to every block I manage.
57 */
58
59typedef union track__block {
60 struct {
61 union track__block *next; /* Link to previous block */
62 union track__block *prev; /* Link to next block */
63 size_t sz; /* Size of the block */
64 const char *ctx; /* Pointer to allocating context */
65 } x; /* Main data area */
66 long double _ld; /* Long double for alignment */
67 void *_p; /* Void pointer for alignment */
68} track__block;
69
70/*----- Private state -----------------------------------------------------*/
71
72/* --- Tracking memory usage --- */
73
74static unsigned int track__used = 0; /* Count of bytes occupied */
75static track__block *track__list; /* List of allocated blocks */
76
77/* --- Trace level for verbose messages --- */
78
79static unsigned int track__vLevel = 0;
80
81/* --- Context tracking --- */
82
83static track_ctx track__baseContext = {
84 0, "[unknown context]"
85};
86
87static track_ctx *track__context = &track__baseContext;
88
89/*----- Functions provided ------------------------------------------------*/
90
91/* --- @track_setLevel@ --- *
92 *
93 * Arguments: @unsigned int l@ = tracing level for allocation messages
94 *
95 * Returns: ---
96 *
97 * Use: Sets the trace level for allocation messages.
98 */
99
100void track_setLevel(unsigned int l)
101{
102 track__vLevel = l;
103}
104
105/* --- @track_pushContext@ --- *
106 *
107 * Arguments: @track_ctx *ctx@ = context holder to push
108 *
109 * Returns: ---
110 *
111 * Use: Pushes the given context block onto the stack.
112 */
113
114void track_pushContext(track_ctx *ctx)
115{
116 ctx->next = track__context;
117 track__context = ctx;
118}
119
120/* --- @track_popContext@ --- *
121 *
122 * Arguments: @track_ctx *ctx@ = context holder to pop
123 *
124 * Returns: ---
125 *
126 * Use: Removes the given context block from the stack.
127 */
128
129void track_popContext(track_ctx *ctx)
130{
131 track__context = ctx->next;
132}
133
134/* --- @track_malloc@ --- *
135 *
136 * Arguments: @size_t sz@ = size requested
137 *
138 * Returns: Pointer to allocated space, or null
139 *
140 * Use: Allocates memory, and tracks how much is allocated.
141 */
142
143void *track_malloc(size_t sz)
144{
145 track__block *q = (malloc)(sz + sizeof(track__block));
146 if (q) {
147 track__used += sz;
148 if (track__vLevel) {
149 trace(track__vLevel, "(track) allocated %lu at %p in %s",
150 (unsigned long)sz, (void *)(q + 1), track__context->s);
151 }
152 q->x.sz = sz;
153 q->x.next = track__list;
154 q->x.prev = 0;
155 q->x.ctx = track__context->s;
156 if (q->x.next)
157 q->x.next->x.prev = q;
158 track__list = q;
159 return (q + 1);
160 }
161 return (0);
162}
163
164/* --- @track_free@ --- *
165 *
166 * Arguments: @void *p@ = pointer to an allocated block
167 *
168 * Returns: ---
169 *
170 * Use: Frees memory, and tracks how much is still allocated.
171 */
172
173void track_free(void *p)
174{
175 track__block *q;
176
177 if (!p)
178 return;
179 q = (track__block *)p - 1;
180 if (track__vLevel) {
181 trace(track__vLevel, "(track) freed %lu at %p for %s in %s",
182 (unsigned long)q->x.sz, (void *)(q + 1),
183 q->x.ctx, track__context->s);
184 }
185 if (q->x.next)
186 q->x.next->x.prev = q->x.prev;
187 if (q->x.prev)
188 q->x.prev->x.next = q->x.next;
189 else
190 track__list = q->x.next;
191 track__used -= q->x.sz;
192 (free)(q);
193}
194
195/* --- @track_realloc@ --- *
196 *
197 * Arguments: @void *p@ = pointer to an allocated block
198 * @size_t sz@ = how big it wants to be
199 *
200 * Returns: Pointer to the new block.
201 *
202 * Use: Reallocates a block, tracking how much memory is still
203 * available.
204 */
205
206void *track_realloc(void *p, size_t sz)
207{
208 size_t osz;
209 track__block *q, *qq;
210 if (p) {
211 q = (track__block *)p - 1;
212 osz = q->x.sz;
213 if (q->x.next)
214 q->x.next->x.prev = q->x.prev;
215 if (q->x.prev)
216 q->x.prev->x.next = q->x.next;
217 else
218 track__list = q->x.next;
219 } else {
220 q = 0;
221 osz = 0;
222 }
223 qq = (realloc)(q, sz + sizeof(track__block));
224 if (qq) {
225 if (track__vLevel) {
226 trace(track__vLevel,
227 "(track) reallocated %lu at %p to %lu for %s in %s",
228 (unsigned long)osz, (void *)(q + 1),
229 (unsigned long)sz, (void *)(qq + 1),
230 qq->x.ctx, track__context->s);
231 }
232 qq->x.sz = sz;
233 qq->x.next = track__list;
234 qq->x.prev = 0;
235 if (qq->x.next)
236 qq->x.next->x.prev = qq;
237 track__list = qq;
238 track__used += sz - osz;
239 qq->x.sz = sz;
240 return (qq + 1);
241 }
242 return (0);
243}
244
245/* --- @track_used@ --- *
246 *
247 * Arguments: ---
248 *
249 * Returns: A count of how much memory is used currently.
250 *
251 * Use: Returns the amount of memory which the @track_@-functions
252 * above have counted as being currently allocated.
253 */
254
255unsigned long track_used(void)
256{
257 return (track__used);
258}
259
260/* --- @track_list@ --- *
261 *
262 * Arguments: @unsigned int l@ = trace level to use
263 *
264 * Returns: ---
265 *
266 * Use: Traces a dump of the currently known blocks. Combined with
267 * a verbose dump of allocations and deallocations, and a
268 * good idea of which blocks were allocated where, this can
269 * be useful for locating memory leaks. It's not exactly a
270 * picnic, though.
271 */
272
273void track_list(unsigned int l)
274{
275 track__block *q = track__list;
276
277 if (!(tracing() & l))
278 return;
279
280 trace(l, "(track dump) Dumping all blocks. Stand well back...");
281 while (q) {
282 trace(l, "(track dump) %p: %lu in %s",
283 (void *)(q + 1), (unsigned long)q->x.sz, q->x.ctx);
284 q = q->x.next;
285 }
286}
287
288/*----- That's all, folks -------------------------------------------------*/