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