3 * $Id: cbdata.cc,v 1.49 2002/10/25 03:13:51 robertc Exp $
5 * DEBUG: section 45 Callback Data Registry
6 * ORIGINAL AUTHOR: Duane Wessels
7 * Modified by Moez Mahfoudh (08/12/2000)
8 * History added by Robert Collins (2002-10-25)
10 * SQUID Web Proxy Cache http://www.squid-cache.org/
11 * ----------------------------------------------------------
13 * Squid is the result of efforts by numerous individuals from
14 * the Internet community; see the CONTRIBUTORS file for full
15 * details. Many organizations have provided support for Squid's
16 * development; see the SPONSORS file for full details. Squid is
17 * Copyrighted (C) 2001 by the Regents of the University of
18 * California; see the COPYRIGHT file for full details. Squid
19 * incorporates software developed and/or copyrighted by other
20 * sources; see the CREDITS file for full details.
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 * These routines manage a set of registered callback data pointers.
40 * One of the easiest ways to make Squid coredump is to issue a
41 * callback to for some data structure which has previously been
42 * freed. With these routines, we register (add) callback data
43 * pointers, lock them just before registering the callback function,
44 * validate them before issuing the callback, and then free them
55 static int cbdataCount
= 0;
57 dlink_list cbdataEntries
;
63 CBDataCall (char const *callLabel
, char const *aFile
, int aLine
) : label(callLabel
), file(aFile
), line(aLine
){}
70 typedef struct _cbdata
{
72 void dump(StoreEntry
*)const;
79 void addHistory(char const *label
, char const *file
, int line
) const
81 if (calls
->count
> 100)
83 stackPush (calls
, new CBDataCall(label
, file
, line
));
90 long y
; /* cookie used while debugging */
98 static OBJH cbdataDump
;
100 static OBJH cbdataDumpHistory
;
106 } *cbdata_index
= NULL
;
107 int cbdata_types
= 0;
109 #define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
110 #define CBDATA_COOKIE (long)0xDEADBEEF
111 #define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
114 _cbdata::deleteSelf()
118 while ((aCall
= (CBDataCall
*)stackPop(calls
)))
122 FREE
*free_func
= cbdata_index
[type
].free_func
;
125 memPoolFree(cbdata_index
[type
].pool
, this);
129 cbdataInternalInitType(cbdata_type type
, const char *name
, int size
, FREE
* free_func
)
132 if (type
>= cbdata_types
) {
133 cbdata_index
= (CBDataIndex
*)xrealloc(cbdata_index
, (type
+ 1) * sizeof(*cbdata_index
));
134 memset(&cbdata_index
[cbdata_types
], 0,
135 (type
+ 1 - cbdata_types
) * sizeof(*cbdata_index
));
136 cbdata_types
= type
+ 1;
138 if (cbdata_index
[type
].pool
)
140 label
= (char *)xmalloc(strlen(name
) + 20);
141 snprintf(label
, strlen(name
) + 20, "cbdata %s (%d)", name
, (int) type
);
142 assert(OFFSET_OF(cbdata
, data
) == (sizeof(cbdata
) - sizeof(((cbdata
*) NULL
)->data
)));
143 cbdata_index
[type
].pool
= memPoolCreate(label
, size
+ OFFSET_OF(cbdata
, data
));
144 cbdata_index
[type
].free_func
= free_func
;
148 cbdataInternalAddType(cbdata_type type
, const char *name
, int size
, FREE
* free_func
)
152 type
= (cbdata_type
)cbdata_types
;
153 cbdataInternalInitType(type
, name
, size
, free_func
);
160 debug(45, 3) ("cbdataInit\n");
161 cachemgrRegister("cbdata",
162 "Callback Data Registry Contents",
165 cachemgrRegister("cbdatahistory",
166 "Detailed call history for all current cbdata contents",
167 cbdataDumpHistory
, 0, 1);
169 #define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
170 #define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
172 * most of these should be moved out to their respective module.
174 CREATE_CBDATA(acl_access
);
175 CREATE_CBDATA(aclCheck_t
);
176 CREATE_CBDATA(clientHttpRequest
);
177 CREATE_CBDATA(ConnStateData
);
178 CREATE_CBDATA(ErrorState
);
179 CREATE_CBDATA(FwdState
);
180 CREATE_CBDATA(generic_cbdata
);
181 CREATE_CBDATA(helper
);
182 CREATE_CBDATA(helper_server
);
183 CREATE_CBDATA(statefulhelper
);
184 CREATE_CBDATA(helper_stateful_server
);
185 CREATE_CBDATA_FREE(peer
, peerDestroy
);
186 CREATE_CBDATA(ps_state
);
187 CREATE_CBDATA(RemovalPolicy
);
188 CREATE_CBDATA(RemovalPolicyWalker
);
189 CREATE_CBDATA(RemovalPurgeWalker
);
194 cbdataInternalAllocDbg(cbdata_type type
, const char *file
, int line
)
196 cbdataInternalAlloc(cbdata_type type
)
200 assert(type
> 0 && type
< cbdata_types
);
201 p
= (cbdata
*)memPoolAlloc(cbdata_index
[type
].pool
);
205 p
->y
= (long) p
^ CBDATA_COOKIE
;
210 p
->calls
= stackCreate();
211 p
->addHistory("Alloc", file
, line
);
212 dlinkAdd(p
, &p
->link
, &cbdataEntries
);
213 debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p
->data
, file
, line
);
215 return (void *) &p
->data
;
220 cbdataInternalFreeDbg(void *p
, const char *file
, int line
)
222 cbdataInternalFree(void *p
)
226 c
= (cbdata
*) (((char *) p
) - OFFSET_OF(cbdata
, data
));
228 debug(45, 3) ("cbdataFree: %p %s:%d\n", p
, file
, line
);
230 debug(45, 3) ("cbdataFree: %p\n", p
);
235 c
->addHistory("Free", file
, line
);
238 debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
243 debug(45, 3) ("cbdataFree: Freeing %p\n", p
);
245 dlinkDelete(&c
->link
, &cbdataEntries
);
253 cbdataInternalLockDbg(const void *p
, const char *file
, int line
)
255 cbdataInternalLock(const void *p
)
261 c
= (cbdata
*) (((char *) p
) - OFFSET_OF(cbdata
, data
));
263 debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p
, c
? c
->locks
+ 1 : -1, file
, line
);
264 c
->addHistory("Reference", file
, line
);
266 debug(45, 3) ("cbdataLock: %p=%d\n", p
, c
? c
->locks
+ 1 : -1);
269 assert(c
->locks
< 65535);
275 cbdataInternalUnlockDbg(const void *p
, const char *file
, int line
)
277 cbdataInternalUnlock(const void *p
)
283 c
= (cbdata
*) (((char *) p
) - OFFSET_OF(cbdata
, data
));
285 debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p
, c
? c
->locks
- 1 : -1, file
, line
);
286 c
->addHistory("Dereference", file
, line
);
288 debug(45, 3) ("cbdataUnlock: %p=%d\n", p
, c
? c
->locks
- 1 : -1);
292 assert(c
->locks
> 0);
294 if (c
->valid
|| c
->locks
)
297 debug(45, 3) ("cbdataUnlock: Freeing %p\n", p
);
299 dlinkDelete(&c
->link
, &cbdataEntries
);
305 cbdataReferenceValid(const void *p
)
309 return 1; /* A NULL pointer cannot become invalid */
310 debug(45, 3) ("cbdataReferenceValid: %p\n", p
);
311 c
= (cbdata
*) (((char *) p
) - OFFSET_OF(cbdata
, data
));
313 assert(c
->locks
> 0);
319 cbdataInternalReferenceDoneValidDbg(void **pp
, void **tp
, const char *file
, int line
)
321 cbdataInternalReferenceDoneValid(void **pp
, void **tp
)
324 void *p
= (void *) *pp
;
325 int valid
= cbdataReferenceValid(p
);
328 cbdataInternalUnlockDbg(p
, file
, line
);
330 cbdataInternalUnlock(p
);
343 _cbdata::dump(StoreEntry
*sentry
) const
345 storeAppendPrintf(sentry
, "%c%p\t%d\t%d\t%20s:%-5d\n", valid
? ' ' :
346 '!', &data
, type
, locks
, file
, line
);
349 struct CBDataDumper
: public unary_function
<_cbdata
, void>
351 CBDataDumper(StoreEntry
*anEntry
):where(anEntry
){}
352 void operator()(_cbdata
const &x
) {
360 cbdataDump(StoreEntry
* sentry
)
362 storeAppendPrintf(sentry
, "%d cbdata entries\n", cbdataCount
);
364 storeAppendPrintf(sentry
, "Pointer\tType\tLocks\tAllocated by\n");
365 CBDataDumper
dumper(sentry
);
366 for_each (cbdataEntries
, dumper
);
367 storeAppendPrintf(sentry
, "\n");
368 storeAppendPrintf(sentry
, "types\tsize\tallocated\ttotal\n");
369 for (int i
= 1; i
< cbdata_types
; i
++) {
370 MemPool
*pool
= cbdata_index
[i
].pool
;
372 int obj_size
= pool
->obj_size
- OFFSET_OF(cbdata
, data
);
373 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
);
377 storeAppendPrintf(sentry
, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
379 storeAppendPrintf(sentry
, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
385 T
& for_each(Stack
const &collection
, T
& visitor
)
387 for (int index
= 0; index
< collection
.count
; ++index
)
388 visitor(*(typename
T::argument_type
const *)collection
.items
[index
]);
392 struct CBDataCallDumper
: public unary_function
<CBDataCall
, void>
394 CBDataCallDumper (StoreEntry
*anEntry
):where(anEntry
){}
395 void operator()(CBDataCall
const &x
) {
396 storeAppendPrintf(where
, "%s\t%s\t%d\n", x
.label
, x
.file
, x
.line
);
401 struct CBDataHistoryDumper
: public CBDataDumper
403 CBDataHistoryDumper(StoreEntry
*anEntry
):CBDataDumper(anEntry
),where(anEntry
), callDumper(anEntry
){}
404 void operator()(_cbdata
const &x
) {
405 CBDataDumper::operator()(x
);
406 storeAppendPrintf(where
, "\n");
407 storeAppendPrintf(where
, "Action\tFile\tLine\n");
408 for_each (*x
.calls
,callDumper
);
409 storeAppendPrintf(where
, "\n");
412 CBDataCallDumper callDumper
;
416 cbdataDumpHistory(StoreEntry
*sentry
)
418 storeAppendPrintf(sentry
, "%d cbdata entries\n", cbdataCount
);
419 storeAppendPrintf(sentry
, "Pointer\tType\tLocks\tAllocated by\n");
420 CBDataHistoryDumper
dumper(sentry
);
421 for_each (cbdataEntries
, dumper
);