chiark / gitweb /
*** empty log message ***
[mLib] / track.c
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
59 typedef 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
74 static unsigned int track__used = 0;    /* Count of bytes occupied */
75 static track__block *track__list;       /* List of allocated blocks */
76
77 /* --- Trace level for verbose messages --- */
78
79 static unsigned int track__vLevel = 0;
80
81 /* --- Context tracking --- */
82
83 static track_ctx track__baseContext = {
84   0, "[unknown context]"
85 };
86
87 static 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
100 void 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
114 void 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
129 void 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
143 void *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
173 void 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
206 void *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
255 unsigned 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
273 void 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 -------------------------------------------------*/