]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.cc
Summary: Merge in 6th set of windows changes from Guido
[thirdparty/squid.git] / src / cbdata.cc
CommitLineData
365e5b34 1
e1ac4723 2/*
a46d2c0e 3 * $Id: cbdata.cc,v 1.55 2003/03/04 01:40:25 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
62e76326 61
62class CBDataCall
63{
64
e48ed433 65public:
66 CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine){}
62e76326 67
e48ed433 68 char const *label;
69 char const *file;
70 int line;
71};
62e76326 72
e48ed433 73#endif
74
62e76326 75typedef struct _cbdata
76{
e48ed433 77#if CBDATA_DEBUG
78 void dump(StoreEntry *)const;
79#endif
62e76326 80
e48ed433 81 void deleteSelf();
3015e83a 82 int valid;
83 int locks;
72711e31 84 int type;
4e3f712d 85#if CBDATA_DEBUG
62e76326 86
e48ed433 87 void addHistory(char const *label, char const *file, int line) const
62e76326 88 {
89 if (calls->count > 100)
90 return;
91
e48ed433 92 stackPush (calls, new CBDataCall(label, file, line));
62e76326 93 }
94
fa80a8ef 95 dlink_node link;
4e3f712d 96 const char *file;
97 int line;
e48ed433 98 Stack *calls;
4e3f712d 99#endif
62e76326 100
fa80a8ef 101 long y; /* cookie used while debugging */
28c60158 102 union {
62e76326 103 void *pointer;
104 double double_float;
105 int integer;
28c60158 106 } data;
62e76326 107}
108
109cbdata;
a2172245 110
db1cd23c 111static OBJH cbdataDump;
e48ed433 112#ifdef CBDATA_DEBUG
113static OBJH cbdataDumpHistory;
114#endif
a2172245 115
62e76326 116struct CBDataIndex
117{
72711e31 118 MemPool *pool;
119 FREE *free_func;
62e76326 120}
121
122*cbdata_index = NULL;
28c60158 123int cbdata_types = 0;
124
125#define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
e6ccf245 126#define CBDATA_COOKIE (long)0xDEADBEEF
fa80a8ef 127#define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
28c60158 128
e48ed433 129void
130_cbdata::deleteSelf()
131{
132#if CBDATA_DEBUG
133 CBDataCall *aCall;
62e76326 134
e48ed433 135 while ((aCall = (CBDataCall *)stackPop(calls)))
62e76326 136 delete aCall;
137
e48ed433 138 stackDestroy(calls);
62e76326 139
e48ed433 140#endif
62e76326 141
e48ed433 142 FREE *free_func = cbdata_index[type].free_func;
62e76326 143
e48ed433 144 if (free_func)
62e76326 145 free_func(&data);
146
e48ed433 147 memPoolFree(cbdata_index[type].pool, this);
148}
149
fa80a8ef 150static void
151cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 152{
28c60158 153 char *label;
62e76326 154
28c60158 155 if (type >= cbdata_types) {
62e76326 156 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
157 memset(&cbdata_index[cbdata_types], 0,
158 (type + 1 - cbdata_types) * sizeof(*cbdata_index));
159 cbdata_types = type + 1;
28c60158 160 }
62e76326 161
72711e31 162 if (cbdata_index[type].pool)
62e76326 163 return;
164
e6ccf245 165 label = (char *)xmalloc(strlen(name) + 20);
62e76326 166
28c60158 167 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
62e76326 168
28c60158 169 assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data)));
62e76326 170
72711e31 171 cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data));
62e76326 172
72711e31 173 cbdata_index[type].free_func = free_func;
a2172245 174}
175
28c60158 176cbdata_type
fa80a8ef 177cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 178{
28c60158 179 if (type)
62e76326 180 return type;
181
e6ccf245 182 type = (cbdata_type)cbdata_types;
62e76326 183
fa80a8ef 184 cbdataInternalInitType(type, name, size, free_func);
62e76326 185
28c60158 186 return type;
a2172245 187}
188
a2172245 189void
190cbdataInit(void)
191{
3015e83a 192 debug(45, 3) ("cbdataInit\n");
22f3fd98 193 cachemgrRegister("cbdata",
62e76326 194 "Callback Data Registry Contents",
195 cbdataDump, 0, 1);
e48ed433 196#if CBDATA_DEBUG
62e76326 197
198 cachemgrRegister("cbdatahistory",
199 "Detailed call history for all current cbdata contents",
200 cbdataDumpHistory, 0, 1);
e48ed433 201#endif
fa80a8ef 202#define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
203#define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
204 /* XXX
205 * most of these should be moved out to their respective module.
206 */
28c60158 207 CREATE_CBDATA(ErrorState);
208 CREATE_CBDATA(FwdState);
209 CREATE_CBDATA(generic_cbdata);
210 CREATE_CBDATA(helper);
211 CREATE_CBDATA(helper_server);
94439e4e 212 CREATE_CBDATA(statefulhelper);
213 CREATE_CBDATA(helper_stateful_server);
72711e31 214 CREATE_CBDATA_FREE(peer, peerDestroy);
28c60158 215 CREATE_CBDATA(ps_state);
216 CREATE_CBDATA(RemovalPolicy);
217 CREATE_CBDATA(RemovalPolicyWalker);
218 CREATE_CBDATA(RemovalPurgeWalker);
a2172245 219}
220
28c60158 221void *
4e3f712d 222#if CBDATA_DEBUG
72711e31 223cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
4e3f712d 224#else
72711e31 225cbdataInternalAlloc(cbdata_type type)
4e3f712d 226#endif
a2172245 227{
28c60158 228 cbdata *p;
229 assert(type > 0 && type < cbdata_types);
e6ccf245 230 p = (cbdata *)memPoolAlloc(cbdata_index[type].pool);
28c60158 231 p->type = type;
28c60158 232 p->valid = 1;
233 p->locks = 0;
fa80a8ef 234 p->y = (long) p ^ CBDATA_COOKIE;
8b9a2d90 235 cbdataCount++;
fa80a8ef 236#if CBDATA_DEBUG
62e76326 237
e48ed433 238 p->file = file;
239 p->line = line;
240 p->calls = stackCreate();
241 p->addHistory("Alloc", file, line);
fa80a8ef 242 dlinkAdd(p, &p->link, &cbdataEntries);
159be25d 243 debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p->data, file, line);
fa80a8ef 244#endif
62e76326 245
28c60158 246 return (void *) &p->data;
b8a2718d 247}
248
c29316a4 249void *
fa80a8ef 250#if CBDATA_DEBUG
251cbdataInternalFreeDbg(void *p, const char *file, int line)
252#else
72711e31 253cbdataInternalFree(void *p)
fa80a8ef 254#endif
a2172245 255{
28c60158 256 cbdata *c;
159be25d 257 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
fa80a8ef 258#if CBDATA_DEBUG
62e76326 259
fa80a8ef 260 debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
261#else
62e76326 262
3015e83a 263 debug(45, 3) ("cbdataFree: %p\n", p);
fa80a8ef 264#endif
62e76326 265
fa80a8ef 266 CBDATA_CHECK(c);
3015e83a 267 c->valid = 0;
e48ed433 268#if CBDATA_DEBUG
62e76326 269
e48ed433 270 c->addHistory("Free", file, line);
271#endif
62e76326 272
3015e83a 273 if (c->locks) {
62e76326 274 debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
275 p, c->locks);
276 return NULL;
3015e83a 277 }
62e76326 278
28c60158 279 cbdataCount--;
280 debug(45, 3) ("cbdataFree: Freeing %p\n", p);
fa80a8ef 281#if CBDATA_DEBUG
62e76326 282
fa80a8ef 283 dlinkDelete(&c->link, &cbdataEntries);
284#endif
62e76326 285
e48ed433 286 c->deleteSelf();
c29316a4 287 return NULL;
72711e31 288}
289
a2172245 290void
b7e6c377 291#if CBDATA_DEBUG
fa80a8ef 292cbdataInternalLockDbg(const void *p, const char *file, int line)
b7e6c377 293#else
fa80a8ef 294cbdataInternalLock(const void *p)
b7e6c377 295#endif
a2172245 296{
3015e83a 297 cbdata *c;
62e76326 298
3015e83a 299 if (p == NULL)
62e76326 300 return;
301
28c60158 302 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
62e76326 303
b7e6c377 304#if CBDATA_DEBUG
62e76326 305
fa80a8ef 306 debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
62e76326 307
e48ed433 308 c->addHistory("Reference", file, line);
62e76326 309
fa80a8ef 310#else
62e76326 311
fa80a8ef 312 debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
62e76326 313
b7e6c377 314#endif
62e76326 315
fa80a8ef 316 CBDATA_CHECK(c);
62e76326 317
59e12f93 318 assert(c->locks < 65535);
62e76326 319
fa80a8ef 320 c->locks++;
a2172245 321}
322
323void
b7e6c377 324#if CBDATA_DEBUG
fa80a8ef 325cbdataInternalUnlockDbg(const void *p, const char *file, int line)
b7e6c377 326#else
fa80a8ef 327cbdataInternalUnlock(const void *p)
b7e6c377 328#endif
a2172245 329{
3015e83a 330 cbdata *c;
62e76326 331
3015e83a 332 if (p == NULL)
62e76326 333 return;
334
28c60158 335 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
62e76326 336
fa80a8ef 337#if CBDATA_DEBUG
62e76326 338
fa80a8ef 339 debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
62e76326 340
e48ed433 341 c->addHistory("Dereference", file, line);
62e76326 342
fa80a8ef 343#else
62e76326 344
fa80a8ef 345 debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
62e76326 346
fa80a8ef 347#endif
62e76326 348
fa80a8ef 349 CBDATA_CHECK(c);
62e76326 350
3015e83a 351 assert(c != NULL);
62e76326 352
3015e83a 353 assert(c->locks > 0);
62e76326 354
3015e83a 355 c->locks--;
62e76326 356
aab9676e 357 if (c->valid || c->locks)
62e76326 358 return;
359
28c60158 360 cbdataCount--;
62e76326 361
28c60158 362 debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
62e76326 363
fa80a8ef 364#if CBDATA_DEBUG
62e76326 365
fa80a8ef 366 dlinkDelete(&c->link, &cbdataEntries);
62e76326 367
fa80a8ef 368#endif
62e76326 369
e48ed433 370 c->deleteSelf();
a2172245 371}
372
373int
fa80a8ef 374cbdataReferenceValid(const void *p)
a2172245 375{
3015e83a 376 cbdata *c;
62e76326 377
3015e83a 378 if (p == NULL)
62e76326 379 return 1; /* A NULL pointer cannot become invalid */
380
fa80a8ef 381 debug(45, 3) ("cbdataReferenceValid: %p\n", p);
62e76326 382
28c60158 383 c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
62e76326 384
fa80a8ef 385 CBDATA_CHECK(c);
62e76326 386
3015e83a 387 assert(c->locks > 0);
62e76326 388
3015e83a 389 return c->valid;
a2172245 390}
391
fa80a8ef 392int
393#if CBDATA_DEBUG
394cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
395#else
396cbdataInternalReferenceDoneValid(void **pp, void **tp)
397#endif
398{
399 void *p = (void *) *pp;
400 int valid = cbdataReferenceValid(p);
401 *pp = NULL;
402#if CBDATA_DEBUG
62e76326 403
fa80a8ef 404 cbdataInternalUnlockDbg(p, file, line);
405#else
62e76326 406
fa80a8ef 407 cbdataInternalUnlock(p);
408#endif
62e76326 409
fa80a8ef 410 if (valid) {
62e76326 411 *tp = p;
412 return 1;
fa80a8ef 413 } else {
62e76326 414 *tp = NULL;
415 return 0;
fa80a8ef 416 }
417}
418
e48ed433 419#if CBDATA_DEBUG
420void
421_cbdata::dump(StoreEntry *sentry) const
422{
423 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
62e76326 424 '!', &data, type, locks, file, line);
e48ed433 425}
426
427struct CBDataDumper : public unary_function<_cbdata, void>
428{
429 CBDataDumper(StoreEntry *anEntry):where(anEntry){}
62e76326 430
431 void operator()(_cbdata const &x)
432 {
433 x.dump(where);
e48ed433 434 }
62e76326 435
e48ed433 436 StoreEntry *where;
437};
62e76326 438
e48ed433 439#endif
fa80a8ef 440
db1cd23c 441static void
3015e83a 442cbdataDump(StoreEntry * sentry)
a2172245 443{
8b9a2d90 444 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
fa80a8ef 445#if CBDATA_DEBUG
62e76326 446
fa80a8ef 447 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
e48ed433 448 CBDataDumper dumper(sentry);
449 for_each (cbdataEntries, dumper);
fa80a8ef 450 storeAppendPrintf(sentry, "\n");
451 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
62e76326 452
e48ed433 453 for (int i = 1; i < cbdata_types; i++) {
62e76326 454 MemPool *pool = cbdata_index[i].pool;
455
456 if (pool) {
457 int obj_size = pool->obj_size - OFFSET_OF(cbdata, data);
458 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);
459 }
fa80a8ef 460 }
62e76326 461
fa80a8ef 462#else
463 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
62e76326 464
fa80a8ef 465#endif
62e76326 466
fa80a8ef 467 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
a2172245 468}
e48ed433 469
470#if CBDATA_DEBUG
471
472template <class T>
473T& for_each(Stack const &collection, T& visitor)
474{
732735ed 475 for (size_t index = 0; index < collection.count; ++index)
62e76326 476 visitor(*(typename T::argument_type const *)collection.items[index]);
477
e48ed433 478 return visitor;
479};
480
481struct CBDataCallDumper : public unary_function<CBDataCall, void>
482{
483 CBDataCallDumper (StoreEntry *anEntry):where(anEntry){}
62e76326 484
485 void operator()(CBDataCall const &x)
486 {
487 storeAppendPrintf(where, "%s\t%s\t%d\n", x.label, x.file, x.line);
e48ed433 488 }
62e76326 489
e48ed433 490 StoreEntry *where;
491};
492
493struct CBDataHistoryDumper : public CBDataDumper
494{
495 CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry){}
62e76326 496
497 void operator()(_cbdata const &x)
498 {
499 CBDataDumper::operator()(x);
500 storeAppendPrintf(where, "\n");
501 storeAppendPrintf(where, "Action\tFile\tLine\n");
502 for_each (*x.calls,callDumper);
503 storeAppendPrintf(where, "\n");
e48ed433 504 }
62e76326 505
e48ed433 506 StoreEntry *where;
507 CBDataCallDumper callDumper;
508};
509
510void
511cbdataDumpHistory(StoreEntry *sentry)
512{
513 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
514 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
515 CBDataHistoryDumper dumper(sentry);
516 for_each (cbdataEntries, dumper);
517}
62e76326 518
e48ed433 519#endif