]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.cc
Set an upper limit on lock counts (65535) - I'm sure we're about to trigger
[thirdparty/squid.git] / src / cbdata.cc
1
2 /*
3 * $Id: cbdata.cc,v 1.48 2002/10/24 22:59:29 adrian Exp $
4 *
5 * DEBUG: section 45 Callback Data Registry
6 * ORIGINAL AUTHOR: Duane Wessels
7 * Modified by Moez Mahfoudh (08/12/2000)
8 *
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37 /*
38 * These routines manage a set of registered callback data pointers.
39 * One of the easiest ways to make Squid coredump is to issue a
40 * callback to for some data structure which has previously been
41 * freed. With these routines, we register (add) callback data
42 * pointers, lock them just before registering the callback function,
43 * validate them before issuing the callback, and then free them
44 * when finished.
45 */
46
47 #include "squid.h"
48 #include "Store.h"
49
50 static int cbdataCount = 0;
51 #if CBDATA_DEBUG
52 dlink_list cbdataEntries;
53 #endif
54
55 typedef struct _cbdata {
56 int valid;
57 int locks;
58 int type;
59 #if CBDATA_DEBUG
60 dlink_node link;
61 const char *file;
62 int line;
63 #endif
64 long y; /* cookie used while debugging */
65 union {
66 void *pointer;
67 double double_float;
68 int integer;
69 } data;
70 } cbdata;
71
72 static OBJH cbdataDump;
73
74 struct CBDataIndex {
75 MemPool *pool;
76 FREE *free_func;
77 } *cbdata_index = NULL;
78 int cbdata_types = 0;
79
80 #define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
81 #define CBDATA_COOKIE (long)0xDEADBEEF
82 #define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
83
84 static void
85 cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
86 {
87 char *label;
88 if (type >= cbdata_types) {
89 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
90 memset(&cbdata_index[cbdata_types], 0,
91 (type + 1 - cbdata_types) * sizeof(*cbdata_index));
92 cbdata_types = type + 1;
93 }
94 if (cbdata_index[type].pool)
95 return;
96 label = (char *)xmalloc(strlen(name) + 20);
97 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
98 assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data)));
99 cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data));
100 cbdata_index[type].free_func = free_func;
101 }
102
103 cbdata_type
104 cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
105 {
106 if (type)
107 return type;
108 type = (cbdata_type)cbdata_types;
109 cbdataInternalInitType(type, name, size, free_func);
110 return type;
111 }
112
113 void
114 cbdataInit(void)
115 {
116 debug(45, 3) ("cbdataInit\n");
117 cachemgrRegister("cbdata",
118 "Callback Data Registry Contents",
119 cbdataDump, 0, 1);
120 #define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
121 #define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
122 /* XXX
123 * most of these should be moved out to their respective module.
124 */
125 CREATE_CBDATA(acl_access);
126 CREATE_CBDATA(aclCheck_t);
127 CREATE_CBDATA(clientHttpRequest);
128 CREATE_CBDATA(ConnStateData);
129 CREATE_CBDATA(ErrorState);
130 CREATE_CBDATA(FwdState);
131 CREATE_CBDATA(generic_cbdata);
132 CREATE_CBDATA(helper);
133 CREATE_CBDATA(helper_server);
134 CREATE_CBDATA(statefulhelper);
135 CREATE_CBDATA(helper_stateful_server);
136 CREATE_CBDATA_FREE(peer, peerDestroy);
137 CREATE_CBDATA(ps_state);
138 CREATE_CBDATA(RemovalPolicy);
139 CREATE_CBDATA(RemovalPolicyWalker);
140 CREATE_CBDATA(RemovalPurgeWalker);
141 }
142
143 void *
144 #if CBDATA_DEBUG
145 cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
146 #else
147 cbdataInternalAlloc(cbdata_type type)
148 #endif
149 {
150 cbdata *p;
151 assert(type > 0 && type < cbdata_types);
152 p = (cbdata *)memPoolAlloc(cbdata_index[type].pool);
153 p->type = type;
154 p->valid = 1;
155 p->locks = 0;
156 #if CBDATA_DEBUG
157 p->file = file;
158 p->line = line;
159 #endif
160 p->y = (long) p ^ CBDATA_COOKIE;
161 cbdataCount++;
162
163 #if CBDATA_DEBUG
164 dlinkAdd(p, &p->link, &cbdataEntries);
165 debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p->data, file, line);
166 #endif
167 return (void *) &p->data;
168 }
169
170 void *
171 #if CBDATA_DEBUG
172 cbdataInternalFreeDbg(void *p, const char *file, int line)
173 #else
174 cbdataInternalFree(void *p)
175 #endif
176 {
177 cbdata *c;
178 FREE *free_func;
179 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
180 #if CBDATA_DEBUG
181 debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
182 #else
183 debug(45, 3) ("cbdataFree: %p\n", p);
184 #endif
185 CBDATA_CHECK(c);
186 c->valid = 0;
187 if (c->locks) {
188 debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
189 p, c->locks);
190 return NULL;
191 }
192 cbdataCount--;
193 debug(45, 3) ("cbdataFree: Freeing %p\n", p);
194 #if CBDATA_DEBUG
195 dlinkDelete(&c->link, &cbdataEntries);
196 #endif
197 free_func = cbdata_index[c->type].free_func;
198 if (free_func)
199 free_func((void *) p);
200 memPoolFree(cbdata_index[c->type].pool, c);
201 return NULL;
202 }
203
204 void
205 #if CBDATA_DEBUG
206 cbdataInternalLockDbg(const void *p, const char *file, int line)
207 #else
208 cbdataInternalLock(const void *p)
209 #endif
210 {
211 cbdata *c;
212 if (p == NULL)
213 return;
214 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
215 #if CBDATA_DEBUG
216 debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
217 #else
218 debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
219 #endif
220 CBDATA_CHECK(c);
221 assert(c->locks < 65535);
222 c->locks++;
223 }
224
225 void
226 #if CBDATA_DEBUG
227 cbdataInternalUnlockDbg(const void *p, const char *file, int line)
228 #else
229 cbdataInternalUnlock(const void *p)
230 #endif
231 {
232 cbdata *c;
233 FREE *free_func;
234 if (p == NULL)
235 return;
236 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
237 #if CBDATA_DEBUG
238 debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
239 #else
240 debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
241 #endif
242 CBDATA_CHECK(c);
243 assert(c != NULL);
244 assert(c->locks > 0);
245 c->locks--;
246 if (c->valid || c->locks)
247 return;
248 cbdataCount--;
249 debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
250 #if CBDATA_DEBUG
251 dlinkDelete(&c->link, &cbdataEntries);
252 #endif
253 free_func = cbdata_index[c->type].free_func;
254 if (free_func)
255 free_func((void *) p);
256 memPoolFree(cbdata_index[c->type].pool, c);
257 }
258
259 int
260 cbdataReferenceValid(const void *p)
261 {
262 cbdata *c;
263 if (p == NULL)
264 return 1; /* A NULL pointer cannot become invalid */
265 debug(45, 3) ("cbdataReferenceValid: %p\n", p);
266 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
267 CBDATA_CHECK(c);
268 assert(c->locks > 0);
269 return c->valid;
270 }
271
272 int
273 #if CBDATA_DEBUG
274 cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
275 #else
276 cbdataInternalReferenceDoneValid(void **pp, void **tp)
277 #endif
278 {
279 void *p = (void *) *pp;
280 int valid = cbdataReferenceValid(p);
281 *pp = NULL;
282 #if CBDATA_DEBUG
283 cbdataInternalUnlockDbg(p, file, line);
284 #else
285 cbdataInternalUnlock(p);
286 #endif
287 if (valid) {
288 *tp = p;
289 return 1;
290 } else {
291 *tp = NULL;
292 return 0;
293 }
294 }
295
296
297 static void
298 cbdataDump(StoreEntry * sentry)
299 {
300 #if CBDATA_DEBUG
301 dlink_node *n;
302 cbdata *p;
303 int i;
304 #endif
305 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
306 #if CBDATA_DEBUG
307 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
308 for (n = cbdataEntries.head; n; n = n->next) {
309 p = (cbdata *)n->data;
310 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", p->valid ? ' ' : '!', &p->data, p->type, p->locks, p->file, p->line);
311 }
312 storeAppendPrintf(sentry, "\n");
313 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
314 for (i = 1; i < cbdata_types; i++) {
315 MemPool *pool = cbdata_index[i].pool;
316 if (pool) {
317 int obj_size = pool->obj_size - OFFSET_OF(cbdata, data);
318 storeAppendPrintf(sentry, "%s\t%d\t%d\t%d\n", pool->label + 7, obj_size, pool->meter.inuse.level, obj_size * pool->meter.inuse.level);
319 }
320 }
321 #else
322 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
323 #endif
324 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
325 }