]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.cc
Document the 'carp' cache_peer option
[thirdparty/squid.git] / src / cbdata.cc
CommitLineData
365e5b34 1
e1ac4723 2/*
8000a965 3 * $Id: cbdata.cc,v 1.53 2003/02/12 06:11:00 robertc Exp $
e1ac4723 4 *
5 * DEBUG: section 45 Callback Data Registry
28c60158 6 * ORIGINAL AUTHOR: Duane Wessels
7 * Modified by Moez Mahfoudh (08/12/2000)
e48ed433 8 * History added by Robert Collins (2002-10-25)
e1ac4723 9 *
2b6662ba 10 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 11 * ----------------------------------------------------------
e1ac4723 12 *
2b6662ba 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.
e1ac4723 21 *
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.
26 *
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.
31 *
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
cbdec147 34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 35 *
e1ac4723 36 */
37
38/*
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
45 * when finished.
e1ac4723 46 */
a2172245 47
48#include "squid.h"
e6ccf245 49#include "Store.h"
e48ed433 50#if CBDATA_DEBUG
51#include "Stack.h"
52#endif
53#include "Generic.h"
a2172245 54
8b9a2d90 55static int cbdataCount = 0;
fa80a8ef 56#if CBDATA_DEBUG
57dlink_list cbdataEntries;
58#endif
8b9a2d90 59
e48ed433 60#if CBDATA_DEBUG
61class CBDataCall {
62public:
63 CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine){}
64 char const *label;
65 char const *file;
66 int line;
67};
68#endif
69
a2172245 70typedef struct _cbdata {
e48ed433 71#if CBDATA_DEBUG
72 void dump(StoreEntry *)const;
73#endif
74 void deleteSelf();
3015e83a 75 int valid;
76 int locks;
72711e31 77 int type;
4e3f712d 78#if CBDATA_DEBUG
e48ed433 79 void addHistory(char const *label, char const *file, int line) const
80 {
81 if (calls->count > 100)
82 return;
83 stackPush (calls, new CBDataCall(label, file, line));
84 }
fa80a8ef 85 dlink_node link;
4e3f712d 86 const char *file;
87 int line;
e48ed433 88 Stack *calls;
4e3f712d 89#endif
fa80a8ef 90 long y; /* cookie used while debugging */
28c60158 91 union {
92 void *pointer;
93 double double_float;
94 int integer;
95 } data;
a2172245 96} cbdata;
97
db1cd23c 98static OBJH cbdataDump;
e48ed433 99#ifdef CBDATA_DEBUG
100static OBJH cbdataDumpHistory;
101#endif
a2172245 102
e6ccf245 103struct CBDataIndex {
72711e31 104 MemPool *pool;
105 FREE *free_func;
106} *cbdata_index = NULL;
28c60158 107int cbdata_types = 0;
108
109#define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
e6ccf245 110#define CBDATA_COOKIE (long)0xDEADBEEF
fa80a8ef 111#define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
28c60158 112
e48ed433 113void
114_cbdata::deleteSelf()
115{
116#if CBDATA_DEBUG
117 CBDataCall *aCall;
118 while ((aCall = (CBDataCall *)stackPop(calls)))
119 delete aCall;
120 stackDestroy(calls);
121#endif
122 FREE *free_func = cbdata_index[type].free_func;
123 if (free_func)
124 free_func(&data);
125 memPoolFree(cbdata_index[type].pool, this);
126}
127
fa80a8ef 128static void
129cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 130{
28c60158 131 char *label;
132 if (type >= cbdata_types) {
e6ccf245 133 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
72711e31 134 memset(&cbdata_index[cbdata_types], 0,
135 (type + 1 - cbdata_types) * sizeof(*cbdata_index));
28c60158 136 cbdata_types = type + 1;
137 }
72711e31 138 if (cbdata_index[type].pool)
28c60158 139 return;
e6ccf245 140 label = (char *)xmalloc(strlen(name) + 20);
28c60158 141 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
142 assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data)));
72711e31 143 cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data));
144 cbdata_index[type].free_func = free_func;
a2172245 145}
146
28c60158 147cbdata_type
fa80a8ef 148cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 149{
28c60158 150 if (type)
151 return type;
e6ccf245 152 type = (cbdata_type)cbdata_types;
fa80a8ef 153 cbdataInternalInitType(type, name, size, free_func);
28c60158 154 return type;
a2172245 155}
156
a2172245 157void
158cbdataInit(void)
159{
3015e83a 160 debug(45, 3) ("cbdataInit\n");
22f3fd98 161 cachemgrRegister("cbdata",
162 "Callback Data Registry Contents",
1da3b90b 163 cbdataDump, 0, 1);
e48ed433 164#if CBDATA_DEBUG
165 cachemgrRegister("cbdatahistory",
166 "Detailed call history for all current cbdata contents",
167 cbdataDumpHistory, 0, 1);
168#endif
fa80a8ef 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)
171 /* XXX
172 * most of these should be moved out to their respective module.
173 */
28c60158 174 CREATE_CBDATA(ConnStateData);
175 CREATE_CBDATA(ErrorState);
176 CREATE_CBDATA(FwdState);
177 CREATE_CBDATA(generic_cbdata);
178 CREATE_CBDATA(helper);
179 CREATE_CBDATA(helper_server);
94439e4e 180 CREATE_CBDATA(statefulhelper);
181 CREATE_CBDATA(helper_stateful_server);
72711e31 182 CREATE_CBDATA_FREE(peer, peerDestroy);
28c60158 183 CREATE_CBDATA(ps_state);
184 CREATE_CBDATA(RemovalPolicy);
185 CREATE_CBDATA(RemovalPolicyWalker);
186 CREATE_CBDATA(RemovalPurgeWalker);
a2172245 187}
188
28c60158 189void *
4e3f712d 190#if CBDATA_DEBUG
72711e31 191cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
4e3f712d 192#else
72711e31 193cbdataInternalAlloc(cbdata_type type)
4e3f712d 194#endif
a2172245 195{
28c60158 196 cbdata *p;
197 assert(type > 0 && type < cbdata_types);
e6ccf245 198 p = (cbdata *)memPoolAlloc(cbdata_index[type].pool);
28c60158 199 p->type = type;
28c60158 200 p->valid = 1;
201 p->locks = 0;
fa80a8ef 202 p->y = (long) p ^ CBDATA_COOKIE;
8b9a2d90 203 cbdataCount++;
fa80a8ef 204#if CBDATA_DEBUG
e48ed433 205 p->file = file;
206 p->line = line;
207 p->calls = stackCreate();
208 p->addHistory("Alloc", file, line);
fa80a8ef 209 dlinkAdd(p, &p->link, &cbdataEntries);
159be25d 210 debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p->data, file, line);
fa80a8ef 211#endif
28c60158 212 return (void *) &p->data;
b8a2718d 213}
214
c29316a4 215void *
fa80a8ef 216#if CBDATA_DEBUG
217cbdataInternalFreeDbg(void *p, const char *file, int line)
218#else
72711e31 219cbdataInternalFree(void *p)
fa80a8ef 220#endif
a2172245 221{
28c60158 222 cbdata *c;
159be25d 223 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
fa80a8ef 224#if CBDATA_DEBUG
225 debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
226#else
3015e83a 227 debug(45, 3) ("cbdataFree: %p\n", p);
fa80a8ef 228#endif
fa80a8ef 229 CBDATA_CHECK(c);
3015e83a 230 c->valid = 0;
e48ed433 231#if CBDATA_DEBUG
232 c->addHistory("Free", file, line);
233#endif
3015e83a 234 if (c->locks) {
aab9676e 235 debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
b716a8ad 236 p, c->locks);
c29316a4 237 return NULL;
3015e83a 238 }
28c60158 239 cbdataCount--;
240 debug(45, 3) ("cbdataFree: Freeing %p\n", p);
fa80a8ef 241#if CBDATA_DEBUG
242 dlinkDelete(&c->link, &cbdataEntries);
243#endif
e48ed433 244 c->deleteSelf();
c29316a4 245 return NULL;
72711e31 246}
247
a2172245 248void
b7e6c377 249#if CBDATA_DEBUG
fa80a8ef 250cbdataInternalLockDbg(const void *p, const char *file, int line)
b7e6c377 251#else
fa80a8ef 252cbdataInternalLock(const void *p)
b7e6c377 253#endif
a2172245 254{
3015e83a 255 cbdata *c;
256 if (p == NULL)
257 return;
28c60158 258 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
b7e6c377 259#if CBDATA_DEBUG
fa80a8ef 260 debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
e48ed433 261 c->addHistory("Reference", file, line);
fa80a8ef 262#else
263 debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
b7e6c377 264#endif
fa80a8ef 265 CBDATA_CHECK(c);
59e12f93 266 assert(c->locks < 65535);
fa80a8ef 267 c->locks++;
a2172245 268}
269
270void
b7e6c377 271#if CBDATA_DEBUG
fa80a8ef 272cbdataInternalUnlockDbg(const void *p, const char *file, int line)
b7e6c377 273#else
fa80a8ef 274cbdataInternalUnlock(const void *p)
b7e6c377 275#endif
a2172245 276{
3015e83a 277 cbdata *c;
278 if (p == NULL)
279 return;
28c60158 280 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
fa80a8ef 281#if CBDATA_DEBUG
282 debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
e48ed433 283 c->addHistory("Dereference", file, line);
fa80a8ef 284#else
285 debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
286#endif
287 CBDATA_CHECK(c);
3015e83a 288 assert(c != NULL);
289 assert(c->locks > 0);
290 c->locks--;
aab9676e 291 if (c->valid || c->locks)
3015e83a 292 return;
28c60158 293 cbdataCount--;
294 debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
fa80a8ef 295#if CBDATA_DEBUG
296 dlinkDelete(&c->link, &cbdataEntries);
297#endif
e48ed433 298 c->deleteSelf();
a2172245 299}
300
301int
fa80a8ef 302cbdataReferenceValid(const void *p)
a2172245 303{
3015e83a 304 cbdata *c;
305 if (p == NULL)
28c60158 306 return 1; /* A NULL pointer cannot become invalid */
fa80a8ef 307 debug(45, 3) ("cbdataReferenceValid: %p\n", p);
28c60158 308 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
fa80a8ef 309 CBDATA_CHECK(c);
3015e83a 310 assert(c->locks > 0);
311 return c->valid;
a2172245 312}
313
fa80a8ef 314int
315#if CBDATA_DEBUG
316cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
317#else
318cbdataInternalReferenceDoneValid(void **pp, void **tp)
319#endif
320{
321 void *p = (void *) *pp;
322 int valid = cbdataReferenceValid(p);
323 *pp = NULL;
324#if CBDATA_DEBUG
325 cbdataInternalUnlockDbg(p, file, line);
326#else
327 cbdataInternalUnlock(p);
328#endif
329 if (valid) {
330 *tp = p;
331 return 1;
332 } else {
333 *tp = NULL;
334 return 0;
335 }
336}
337
e48ed433 338#if CBDATA_DEBUG
339void
340_cbdata::dump(StoreEntry *sentry) const
341{
342 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
343 '!', &data, type, locks, file, line);
344}
345
346struct CBDataDumper : public unary_function<_cbdata, void>
347{
348 CBDataDumper(StoreEntry *anEntry):where(anEntry){}
349 void operator()(_cbdata const &x) {
350 x.dump(where);
351 }
352 StoreEntry *where;
353};
354#endif
fa80a8ef 355
db1cd23c 356static void
3015e83a 357cbdataDump(StoreEntry * sentry)
a2172245 358{
8b9a2d90 359 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
fa80a8ef 360#if CBDATA_DEBUG
361 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
e48ed433 362 CBDataDumper dumper(sentry);
363 for_each (cbdataEntries, dumper);
fa80a8ef 364 storeAppendPrintf(sentry, "\n");
365 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
e48ed433 366 for (int i = 1; i < cbdata_types; i++) {
fa80a8ef 367 MemPool *pool = cbdata_index[i].pool;
368 if (pool) {
369 int obj_size = pool->obj_size - OFFSET_OF(cbdata, data);
370 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);
371 }
372 }
373#else
374 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
375#endif
376 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
a2172245 377}
e48ed433 378
379#if CBDATA_DEBUG
380
381template <class T>
382T& for_each(Stack const &collection, T& visitor)
383{
732735ed 384 for (size_t index = 0; index < collection.count; ++index)
e48ed433 385 visitor(*(typename T::argument_type const *)collection.items[index]);
386 return visitor;
387};
388
389struct CBDataCallDumper : public unary_function<CBDataCall, void>
390{
391 CBDataCallDumper (StoreEntry *anEntry):where(anEntry){}
392 void operator()(CBDataCall const &x) {
393 storeAppendPrintf(where, "%s\t%s\t%d\n", x.label, x.file, x.line);
394 }
395 StoreEntry *where;
396};
397
398struct CBDataHistoryDumper : public CBDataDumper
399{
400 CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry){}
401 void operator()(_cbdata const &x) {
402 CBDataDumper::operator()(x);
403 storeAppendPrintf(where, "\n");
404 storeAppendPrintf(where, "Action\tFile\tLine\n");
405 for_each (*x.calls,callDumper);
406 storeAppendPrintf(where, "\n");
407 }
408 StoreEntry *where;
409 CBDataCallDumper callDumper;
410};
411
412void
413cbdataDumpHistory(StoreEntry *sentry)
414{
415 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
416 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
417 CBDataHistoryDumper dumper(sentry);
418 for_each (cbdataEntries, dumper);
419}
420#endif