]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.cc
Workaround for newer OpenLDAP libraries requiring LDAP_DEPRECATED in order
[thirdparty/squid.git] / src / cbdata.cc
CommitLineData
365e5b34 1
e1ac4723 2/*
b6b6f466 3 * $Id: cbdata.cc,v 1.68 2006/01/03 17:22:30 wessels 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
b24880fe 55/* XXX Remove me */
56#include "PeerSelectState.h"
57
8b9a2d90 58static int cbdataCount = 0;
fa80a8ef 59#if CBDATA_DEBUG
60dlink_list cbdataEntries;
61#endif
8b9a2d90 62
e48ed433 63#if CBDATA_DEBUG
62e76326 64
65class CBDataCall
66{
67
e48ed433 68public:
69 CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine){}
62e76326 70
e48ed433 71 char const *label;
72 char const *file;
73 int line;
74};
62e76326 75
e48ed433 76#endif
77
43ae1d95 78#define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER))
79
80class cbdata
62e76326 81{
43ae1d95 82
83public:
e48ed433 84#if CBDATA_DEBUG
43ae1d95 85
e48ed433 86 void dump(StoreEntry *)const;
87#endif
62e76326 88
f668fcda 89 void *operator new(size_t size, void *where);
e13b11a5 90 void operator delete(void *where, void *where2);
f668fcda 91
92 ~cbdata();
3015e83a 93 int valid;
94 int locks;
f668fcda 95 cbdata_type type;
4e3f712d 96#if CBDATA_DEBUG
62e76326 97
91caca83 98 void addHistory(char const *label, char const *file, int line)
62e76326 99 {
91caca83 100 if (calls.size() > 1000)
62e76326 101 return;
102
91caca83 103 calls.push_back(new CBDataCall(label, file, line));
62e76326 104 }
105
fa80a8ef 106 dlink_node link;
4e3f712d 107 const char *file;
108 int line;
91caca83 109 Stack<CBDataCall*> calls;
4e3f712d 110#endif
62e76326 111
43ae1d95 112 /* cookie used while debugging */
113 long cookie;
114 /* MUST be the last per-instance member */
f668fcda 115 /* TODO: examine making cbdata templated on this - so we get type
116 * safe access to data - RBC 20030902 */
43ae1d95 117 void *data;
06a5ae20 118void check(int line) const {assert(cookie == ((long)this ^ Cookie));}
43ae1d95 119
120 size_t dataSize() const { return sizeof(data);}
62e76326 121
bf5113eb 122 static const long Cookie;
43ae1d95 123 static long MakeOffset();
124 static const long Offset;
125};
126
bf5113eb 127const long cbdata::Cookie((long)0xDEADBEEF);
43ae1d95 128const long cbdata::Offset(MakeOffset());
129
f668fcda 130void *
131cbdata::operator new(size_t size, void *where)
132{
133 // assert (size == sizeof(cbdata));
134 return where;
135}
136
137void
138cbdata::operator delete(void *where, void *where2)
139{
140 /* Only ever invoked when placement new throws
141 * an exception. Used to prevent an incorrect
142 * free.
143 */
144}
145
43ae1d95 146long
147cbdata::MakeOffset()
148{
149 cbdata *zero = (cbdata *)0L;
150 void **dataOffset = &zero->data;
151 return (long)dataOffset;
152}
a2172245 153
db1cd23c 154static OBJH cbdataDump;
e48ed433 155#ifdef CBDATA_DEBUG
156static OBJH cbdataDumpHistory;
157#endif
a2172245 158
62e76326 159struct CBDataIndex
160{
b001e822 161 MemAllocatorProxy *pool;
72711e31 162 FREE *free_func;
62e76326 163}
164
165*cbdata_index = NULL;
28c60158 166int cbdata_types = 0;
167
f668fcda 168cbdata::~cbdata()
e48ed433 169{
170#if CBDATA_DEBUG
171 CBDataCall *aCall;
62e76326 172
91caca83 173 while ((aCall = calls.pop()))
62e76326 174 delete aCall;
175
e48ed433 176#endif
62e76326 177
e48ed433 178 FREE *free_func = cbdata_index[type].free_func;
62e76326 179
e48ed433 180 if (free_func)
62e76326 181 free_func(&data);
e48ed433 182}
183
fa80a8ef 184static void
185cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 186{
28c60158 187 char *label;
62e76326 188
28c60158 189 if (type >= cbdata_types) {
62e76326 190 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
191 memset(&cbdata_index[cbdata_types], 0,
192 (type + 1 - cbdata_types) * sizeof(*cbdata_index));
193 cbdata_types = type + 1;
28c60158 194 }
62e76326 195
72711e31 196 if (cbdata_index[type].pool)
62e76326 197 return;
198
e6ccf245 199 label = (char *)xmalloc(strlen(name) + 20);
62e76326 200
28c60158 201 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
62e76326 202
43ae1d95 203 assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize()));
62e76326 204
b001e822 205 cbdata_index[type].pool = new MemAllocatorProxy(label, size + cbdata::Offset);
62e76326 206
72711e31 207 cbdata_index[type].free_func = free_func;
a2172245 208}
209
28c60158 210cbdata_type
fa80a8ef 211cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 212{
28c60158 213 if (type)
62e76326 214 return type;
215
e6ccf245 216 type = (cbdata_type)cbdata_types;
62e76326 217
fa80a8ef 218 cbdataInternalInitType(type, name, size, free_func);
62e76326 219
28c60158 220 return type;
a2172245 221}
222
a2172245 223void
224cbdataInit(void)
225{
3015e83a 226 debug(45, 3) ("cbdataInit\n");
22f3fd98 227 cachemgrRegister("cbdata",
62e76326 228 "Callback Data Registry Contents",
229 cbdataDump, 0, 1);
e48ed433 230#if CBDATA_DEBUG
62e76326 231
232 cachemgrRegister("cbdatahistory",
233 "Detailed call history for all current cbdata contents",
234 cbdataDumpHistory, 0, 1);
e48ed433 235#endif
fa80a8ef 236#define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
237#define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
238 /* XXX
239 * most of these should be moved out to their respective module.
240 */
28c60158 241 CREATE_CBDATA(ErrorState);
28c60158 242 CREATE_CBDATA(generic_cbdata);
243 CREATE_CBDATA(helper);
244 CREATE_CBDATA(helper_server);
94439e4e 245 CREATE_CBDATA(statefulhelper);
246 CREATE_CBDATA(helper_stateful_server);
28c60158 247 CREATE_CBDATA(ps_state);
248 CREATE_CBDATA(RemovalPolicy);
249 CREATE_CBDATA(RemovalPolicyWalker);
250 CREATE_CBDATA(RemovalPurgeWalker);
a2172245 251}
252
28c60158 253void *
4e3f712d 254#if CBDATA_DEBUG
72711e31 255cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
4e3f712d 256#else
72711e31 257cbdataInternalAlloc(cbdata_type type)
4e3f712d 258#endif
a2172245 259{
28c60158 260 cbdata *p;
261 assert(type > 0 && type < cbdata_types);
b001e822 262 p = new (cbdata_index[type].pool->alloc()) cbdata;
263 // p = (cbdata *)cbdata_index[type].pool->alloc();
f668fcda 264
28c60158 265 p->type = type;
28c60158 266 p->valid = 1;
267 p->locks = 0;
43ae1d95 268 p->cookie = (long) p ^ cbdata::Cookie;
8b9a2d90 269 cbdataCount++;
fa80a8ef 270#if CBDATA_DEBUG
62e76326 271
e48ed433 272 p->file = file;
273 p->line = line;
91caca83 274 p->calls = Stack<CBDataCall *> ();
e48ed433 275 p->addHistory("Alloc", file, line);
fa80a8ef 276 dlinkAdd(p, &p->link, &cbdataEntries);
159be25d 277 debug(45, 3) ("cbdataAlloc: %p %s:%d\n", &p->data, file, line);
fa80a8ef 278#endif
62e76326 279
28c60158 280 return (void *) &p->data;
b8a2718d 281}
282
c29316a4 283void *
fa80a8ef 284#if CBDATA_DEBUG
285cbdataInternalFreeDbg(void *p, const char *file, int line)
286#else
72711e31 287cbdataInternalFree(void *p)
fa80a8ef 288#endif
a2172245 289{
28c60158 290 cbdata *c;
43ae1d95 291 c = (cbdata *) (((char *) p) - cbdata::Offset);
fa80a8ef 292#if CBDATA_DEBUG
62e76326 293
fa80a8ef 294 debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
295#else
62e76326 296
3015e83a 297 debug(45, 3) ("cbdataFree: %p\n", p);
fa80a8ef 298#endif
62e76326 299
06a5ae20 300 c->check(__LINE__);
a2fb868f 301 assert(c->valid);
3015e83a 302 c->valid = 0;
e48ed433 303#if CBDATA_DEBUG
62e76326 304
e48ed433 305 c->addHistory("Free", file, line);
306#endif
62e76326 307
3015e83a 308 if (c->locks) {
62e76326 309 debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
310 p, c->locks);
311 return NULL;
3015e83a 312 }
62e76326 313
28c60158 314 cbdataCount--;
315 debug(45, 3) ("cbdataFree: Freeing %p\n", p);
fa80a8ef 316#if CBDATA_DEBUG
62e76326 317
fa80a8ef 318 dlinkDelete(&c->link, &cbdataEntries);
319#endif
62e76326 320
f668fcda 321 cbdata_type theType = c->type;
322 c->cbdata::~cbdata();
323
324 /* This is ugly. But: operator delete doesn't get
325 * the type parameter, so we can't use that
326 * to free the memory.
327 * So, we free it ourselves.
328 * Note that this means a non-placement
329 * new would be a seriously bad idea.
330 * Lastly, if we where a templated class,
331 * we could use the normal delete operator
332 * and it would Just Work. RBC 20030902
333 */
b001e822 334 cbdata_index[theType].pool->free(c);
c29316a4 335 return NULL;
72711e31 336}
337
a2172245 338void
b7e6c377 339#if CBDATA_DEBUG
fa80a8ef 340cbdataInternalLockDbg(const void *p, const char *file, int line)
b7e6c377 341#else
fa80a8ef 342cbdataInternalLock(const void *p)
b7e6c377 343#endif
a2172245 344{
3015e83a 345 cbdata *c;
62e76326 346
3015e83a 347 if (p == NULL)
62e76326 348 return;
349
43ae1d95 350 c = (cbdata *) (((char *) p) - cbdata::Offset);
62e76326 351
b7e6c377 352#if CBDATA_DEBUG
62e76326 353
fa80a8ef 354 debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
62e76326 355
e48ed433 356 c->addHistory("Reference", file, line);
62e76326 357
fa80a8ef 358#else
62e76326 359
fa80a8ef 360 debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
62e76326 361
b7e6c377 362#endif
62e76326 363
06a5ae20 364 c->check(__LINE__);
62e76326 365
e5130cd3 366 assert(c->locks < 65535);
62e76326 367
fa80a8ef 368 c->locks++;
a2172245 369}
370
371void
b7e6c377 372#if CBDATA_DEBUG
fa80a8ef 373cbdataInternalUnlockDbg(const void *p, const char *file, int line)
b7e6c377 374#else
fa80a8ef 375cbdataInternalUnlock(const void *p)
b7e6c377 376#endif
a2172245 377{
3015e83a 378 cbdata *c;
62e76326 379
3015e83a 380 if (p == NULL)
62e76326 381 return;
382
43ae1d95 383 c = (cbdata *) (((char *) p) - cbdata::Offset);
62e76326 384
fa80a8ef 385#if CBDATA_DEBUG
62e76326 386
fa80a8ef 387 debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
62e76326 388
e48ed433 389 c->addHistory("Dereference", file, line);
62e76326 390
fa80a8ef 391#else
62e76326 392
fa80a8ef 393 debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
62e76326 394
fa80a8ef 395#endif
62e76326 396
06a5ae20 397 c->check(__LINE__);
62e76326 398
3015e83a 399 assert(c != NULL);
62e76326 400
3015e83a 401 assert(c->locks > 0);
62e76326 402
3015e83a 403 c->locks--;
62e76326 404
aab9676e 405 if (c->valid || c->locks)
62e76326 406 return;
407
28c60158 408 cbdataCount--;
62e76326 409
28c60158 410 debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
62e76326 411
fa80a8ef 412#if CBDATA_DEBUG
62e76326 413
fa80a8ef 414 dlinkDelete(&c->link, &cbdataEntries);
62e76326 415
fa80a8ef 416#endif
62e76326 417
f668fcda 418 cbdata_type theType = c->type;
419
420 c->cbdata::~cbdata();
421
422 /* This is ugly. But: operator delete doesn't get
423 * the type parameter, so we can't use that
424 * to free the memory.
425 * So, we free it ourselves.
426 * Note that this means a non-placement
427 * new would be a seriously bad idea.
428 * Lastly, if we where a templated class,
429 * we could use the normal delete operator
430 * and it would Just Work. RBC 20030902
431 */
b001e822 432 cbdata_index[theType].pool->free(c);
a2172245 433}
434
435int
fa80a8ef 436cbdataReferenceValid(const void *p)
a2172245 437{
3015e83a 438 cbdata *c;
62e76326 439
3015e83a 440 if (p == NULL)
62e76326 441 return 1; /* A NULL pointer cannot become invalid */
442
fa80a8ef 443 debug(45, 3) ("cbdataReferenceValid: %p\n", p);
62e76326 444
43ae1d95 445 c = (cbdata *) (((char *) p) - cbdata::Offset);
62e76326 446
06a5ae20 447 c->check(__LINE__);
62e76326 448
3015e83a 449 assert(c->locks > 0);
62e76326 450
3015e83a 451 return c->valid;
a2172245 452}
453
fa80a8ef 454int
455#if CBDATA_DEBUG
456cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
457#else
458cbdataInternalReferenceDoneValid(void **pp, void **tp)
459#endif
460{
461 void *p = (void *) *pp;
462 int valid = cbdataReferenceValid(p);
463 *pp = NULL;
464#if CBDATA_DEBUG
62e76326 465
fa80a8ef 466 cbdataInternalUnlockDbg(p, file, line);
467#else
62e76326 468
fa80a8ef 469 cbdataInternalUnlock(p);
470#endif
62e76326 471
fa80a8ef 472 if (valid) {
62e76326 473 *tp = p;
474 return 1;
fa80a8ef 475 } else {
62e76326 476 *tp = NULL;
477 return 0;
fa80a8ef 478 }
479}
480
e48ed433 481#if CBDATA_DEBUG
482void
43ae1d95 483cbdata::dump(StoreEntry *sentry) const
e48ed433 484{
485 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
62e76326 486 '!', &data, type, locks, file, line);
e48ed433 487}
488
43ae1d95 489struct CBDataDumper : public unary_function<cbdata, void>
e48ed433 490{
491 CBDataDumper(StoreEntry *anEntry):where(anEntry){}
62e76326 492
43ae1d95 493 void operator()(cbdata const &x)
62e76326 494 {
495 x.dump(where);
e48ed433 496 }
62e76326 497
e48ed433 498 StoreEntry *where;
499};
62e76326 500
e48ed433 501#endif
fa80a8ef 502
db1cd23c 503static void
3015e83a 504cbdataDump(StoreEntry * sentry)
a2172245 505{
8b9a2d90 506 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
fa80a8ef 507#if CBDATA_DEBUG
62e76326 508
fa80a8ef 509 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
e48ed433 510 CBDataDumper dumper(sentry);
511 for_each (cbdataEntries, dumper);
fa80a8ef 512 storeAppendPrintf(sentry, "\n");
513 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
62e76326 514
e48ed433 515 for (int i = 1; i < cbdata_types; i++) {
b001e822 516 MemAllocatorProxy *pool = cbdata_index[i].pool;
62e76326 517
518 if (pool) {
b001e822 519 int obj_size = pool->objectSize() - cbdata::Offset;
520 storeAppendPrintf(sentry, "%s\t%d\t%d\t%d\n", pool->objectType() + 7, obj_size, pool->getMeter().inuse.level, obj_size * pool->getMeter().inuse.level);
62e76326 521 }
fa80a8ef 522 }
62e76326 523
fa80a8ef 524#else
525 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
62e76326 526
fa80a8ef 527#endif
62e76326 528
fa80a8ef 529 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
a2172245 530}
e48ed433 531
532#if CBDATA_DEBUG
533
e48ed433 534struct CBDataCallDumper : public unary_function<CBDataCall, void>
535{
536 CBDataCallDumper (StoreEntry *anEntry):where(anEntry){}
62e76326 537
538 void operator()(CBDataCall const &x)
539 {
540 storeAppendPrintf(where, "%s\t%s\t%d\n", x.label, x.file, x.line);
e48ed433 541 }
62e76326 542
e48ed433 543 StoreEntry *where;
544};
545
546struct CBDataHistoryDumper : public CBDataDumper
547{
548 CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry){}
62e76326 549
43ae1d95 550 void operator()(cbdata const &x)
62e76326 551 {
552 CBDataDumper::operator()(x);
553 storeAppendPrintf(where, "\n");
554 storeAppendPrintf(where, "Action\tFile\tLine\n");
91caca83 555 for_each (x.calls,callDumper);
62e76326 556 storeAppendPrintf(where, "\n");
e48ed433 557 }
62e76326 558
e48ed433 559 StoreEntry *where;
560 CBDataCallDumper callDumper;
561};
562
563void
564cbdataDumpHistory(StoreEntry *sentry)
565{
566 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
567 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
568 CBDataHistoryDumper dumper(sentry);
569 for_each (cbdataEntries, dumper);
570}
62e76326 571
e48ed433 572#endif