]>
Commit | Line | Data |
---|---|---|
365e5b34 | 1 | |
e1ac4723 | 2 | /* |
e1ac4723 | 3 | * DEBUG: section 45 Callback Data Registry |
28c60158 | 4 | * ORIGINAL AUTHOR: Duane Wessels |
5 | * Modified by Moez Mahfoudh (08/12/2000) | |
e48ed433 | 6 | * History added by Robert Collins (2002-10-25) |
e1ac4723 | 7 | * |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
e1ac4723 | 10 | * |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
e1ac4723 | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
26ac0430 | 24 | * |
e1ac4723 | 25 | * This program is distributed in the hope that it will be useful, |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
26ac0430 | 29 | * |
e1ac4723 | 30 | * You should have received a copy of the GNU General Public License |
31 | * along with this program; if not, write to the Free Software | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
e1ac4723 | 34 | */ |
35 | ||
63be0a78 | 36 | /** |
37 | \defgroup CBDATAInternal Callback Data Allocator Internals | |
38 | \ingroup CBDATAAPI | |
39 | * | |
e1ac4723 | 40 | * These routines manage a set of registered callback data pointers. |
63be0a78 | 41 | * One of the easiest ways to make Squid coredump is to issue a |
e1ac4723 | 42 | * callback to for some data structure which has previously been |
43 | * freed. With these routines, we register (add) callback data | |
44 | * pointers, lock them just before registering the callback function, | |
45 | * validate them before issuing the callback, and then free them | |
46 | * when finished. | |
e1ac4723 | 47 | */ |
a2172245 | 48 | |
f7f3304a | 49 | #include "squid.h" |
aa839030 | 50 | #include "cbdata.h" |
e2849af8 | 51 | #include "Generic.h" |
8822ebee | 52 | #include "mgr/Registration.h" |
e6ccf245 | 53 | #include "Store.h" |
a2172245 | 54 | |
074d6a40 | 55 | #include <climits> |
85b067e3 | 56 | #if USE_CBDATA_DEBUG |
85b067e3 | 57 | #include <algorithm> |
074d6a40 | 58 | #include <vector> |
85b067e3 | 59 | #endif |
582c2af2 | 60 | |
b4bab919 | 61 | #if WITH_VALGRIND |
62 | #define HASHED_CBDATA 1 | |
63 | #endif | |
64 | ||
8b9a2d90 | 65 | static int cbdataCount = 0; |
9a0a18de | 66 | #if USE_CBDATA_DEBUG |
fa80a8ef | 67 | dlink_list cbdataEntries; |
68 | #endif | |
8b9a2d90 | 69 | |
9a0a18de | 70 | #if USE_CBDATA_DEBUG |
62e76326 | 71 | |
72 | class CBDataCall | |
73 | { | |
74 | ||
e48ed433 | 75 | public: |
26ac0430 | 76 | CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine) {} |
62e76326 | 77 | |
e48ed433 | 78 | char const *label; |
79 | char const *file; | |
80 | int line; | |
81 | }; | |
62e76326 | 82 | |
e48ed433 | 83 | #endif |
84 | ||
63be0a78 | 85 | /// \ingroup CBDATAInternal |
43ae1d95 | 86 | #define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER)) |
87 | ||
63be0a78 | 88 | /// \ingroup CBDATAInternal |
43ae1d95 | 89 | class cbdata |
62e76326 | 90 | { |
63be0a78 | 91 | /** \todo examine making cbdata templated on this - so we get type |
b4bab919 | 92 | * safe access to data - RBC 20030902 */ |
43ae1d95 | 93 | public: |
b4bab919 | 94 | #if HASHED_CBDATA |
95 | hash_link hash; // Must be first | |
96 | #endif | |
97 | ||
9a0a18de | 98 | #if USE_CBDATA_DEBUG |
43ae1d95 | 99 | |
e48ed433 | 100 | void dump(StoreEntry *)const; |
101 | #endif | |
62e76326 | 102 | |
b4bab919 | 103 | #if !HASHED_CBDATA |
f668fcda | 104 | void *operator new(size_t size, void *where); |
e13b11a5 | 105 | void operator delete(void *where, void *where2); |
b4bab919 | 106 | #else |
107 | MEMPROXY_CLASS(cndata); | |
108 | #endif | |
f668fcda | 109 | |
110 | ~cbdata(); | |
3015e83a | 111 | int valid; |
3ad2eed0 | 112 | int32_t locks; |
f668fcda | 113 | cbdata_type type; |
9a0a18de | 114 | #if USE_CBDATA_DEBUG |
62e76326 | 115 | |
7ddfeb80 | 116 | void addHistory(char const *label, char const *aFile, int aLine) { |
91caca83 | 117 | if (calls.size() > 1000) |
62e76326 | 118 | return; |
119 | ||
85b067e3 | 120 | calls.push_back(new CBDataCall(label, aFile, aLine)); |
62e76326 | 121 | } |
122 | ||
fa80a8ef | 123 | dlink_node link; |
4e3f712d | 124 | const char *file; |
125 | int line; | |
85b067e3 | 126 | std::vector<CBDataCall*> calls; // used as a stack with random access operator |
4e3f712d | 127 | #endif |
62e76326 | 128 | |
43ae1d95 | 129 | /* cookie used while debugging */ |
130 | long cookie; | |
7ddfeb80 | 131 | void check(int aLine) const {assert(cookie == ((long)this ^ Cookie));} |
b4bab919 | 132 | static const long Cookie; |
43ae1d95 | 133 | |
b4bab919 | 134 | #if !HASHED_CBDATA |
43ae1d95 | 135 | size_t dataSize() const { return sizeof(data);} |
43ae1d95 | 136 | static long MakeOffset(); |
137 | static const long Offset; | |
b4bab919 | 138 | /* MUST be the last per-instance member */ |
139 | void *data; | |
140 | #endif | |
141 | ||
43ae1d95 | 142 | }; |
143 | ||
bf5113eb | 144 | const long cbdata::Cookie((long)0xDEADBEEF); |
b4bab919 | 145 | #if !HASHED_CBDATA |
43ae1d95 | 146 | const long cbdata::Offset(MakeOffset()); |
147 | ||
f668fcda | 148 | void * |
149 | cbdata::operator new(size_t size, void *where) | |
150 | { | |
151 | // assert (size == sizeof(cbdata)); | |
152 | return where; | |
153 | } | |
154 | ||
63be0a78 | 155 | /** |
156 | * Only ever invoked when placement new throws | |
157 | * an exception. Used to prevent an incorrect | |
158 | * free. | |
159 | */ | |
f668fcda | 160 | void |
161 | cbdata::operator delete(void *where, void *where2) | |
cfdb8f88 AJ |
162 | { |
163 | ; // empty. | |
f668fcda | 164 | } |
165 | ||
43ae1d95 | 166 | long |
167 | cbdata::MakeOffset() | |
168 | { | |
169 | cbdata *zero = (cbdata *)0L; | |
170 | void **dataOffset = &zero->data; | |
171 | return (long)dataOffset; | |
172 | } | |
b4bab919 | 173 | #else |
cfdb8f88 | 174 | MEMPROXY_CLASS_INLINE(cbdata); |
b4bab919 | 175 | #endif |
a2172245 | 176 | |
db1cd23c | 177 | static OBJH cbdataDump; |
9a0a18de | 178 | #if USE_CBDATA_DEBUG |
e48ed433 | 179 | static OBJH cbdataDumpHistory; |
180 | #endif | |
a2172245 | 181 | |
63be0a78 | 182 | /// \ingroup CBDATAInternal |
26ac0430 | 183 | struct CBDataIndex { |
b4bab919 | 184 | MemAllocator *pool; |
72711e31 | 185 | FREE *free_func; |
62e76326 | 186 | } |
62e76326 | 187 | *cbdata_index = NULL; |
63be0a78 | 188 | |
189 | /// \ingroup CBDATAInternal | |
28c60158 | 190 | int cbdata_types = 0; |
191 | ||
b4bab919 | 192 | #if HASHED_CBDATA |
193 | static hash_table *cbdata_htable = NULL; | |
194 | ||
195 | static int | |
196 | cbdata_cmp(const void *p1, const void *p2) | |
197 | { | |
198 | return (char *) p1 - (char *) p2; | |
199 | } | |
200 | ||
201 | static unsigned int | |
202 | cbdata_hash(const void *p, unsigned int mod) | |
203 | { | |
204 | return ((unsigned long) p >> 8) % mod; | |
205 | } | |
206 | #endif | |
207 | ||
f668fcda | 208 | cbdata::~cbdata() |
e48ed433 | 209 | { |
9a0a18de | 210 | #if USE_CBDATA_DEBUG |
62e76326 | 211 | |
3aa53107 | 212 | while (!calls.empty()) { |
85b067e3 FC |
213 | delete calls.back(); |
214 | calls.pop_back(); | |
3aa53107 | 215 | } |
62e76326 | 216 | |
e48ed433 | 217 | #endif |
62e76326 | 218 | |
e48ed433 | 219 | FREE *free_func = cbdata_index[type].free_func; |
62e76326 | 220 | |
b4bab919 | 221 | #if HASHED_CBDATA |
222 | void *p = hash.key; | |
223 | #else | |
224 | void *p = &data; | |
225 | #endif | |
226 | ||
e48ed433 | 227 | if (free_func) |
b4bab919 | 228 | free_func(p); |
e48ed433 | 229 | } |
230 | ||
fa80a8ef | 231 | static void |
232 | cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func) | |
a2172245 | 233 | { |
28c60158 | 234 | char *label; |
aa839030 | 235 | assert (type == cbdata_types + 1); |
62e76326 | 236 | |
aa839030 | 237 | cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index)); |
238 | memset(&cbdata_index[type], 0, sizeof(*cbdata_index)); | |
239 | cbdata_types = type; | |
62e76326 | 240 | |
e6ccf245 | 241 | label = (char *)xmalloc(strlen(name) + 20); |
62e76326 | 242 | |
28c60158 | 243 | snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type); |
62e76326 | 244 | |
b4bab919 | 245 | #if !HASHED_CBDATA |
43ae1d95 | 246 | assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize())); |
b4bab919 | 247 | size += cbdata::Offset; |
248 | #endif | |
62e76326 | 249 | |
04eb0689 | 250 | cbdata_index[type].pool = memPoolCreate(label, size); |
62e76326 | 251 | |
72711e31 | 252 | cbdata_index[type].free_func = free_func; |
b4bab919 | 253 | |
254 | #if HASHED_CBDATA | |
255 | if (!cbdata_htable) | |
26ac0430 | 256 | cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash); |
b4bab919 | 257 | #endif |
a2172245 | 258 | } |
259 | ||
28c60158 | 260 | cbdata_type |
fa80a8ef | 261 | cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func) |
a2172245 | 262 | { |
28c60158 | 263 | if (type) |
62e76326 | 264 | return type; |
265 | ||
aa839030 | 266 | type = (cbdata_type)(cbdata_types + 1); |
62e76326 | 267 | |
fa80a8ef | 268 | cbdataInternalInitType(type, name, size, free_func); |
62e76326 | 269 | |
28c60158 | 270 | return type; |
a2172245 | 271 | } |
272 | ||
62ee09ca | 273 | void |
dbeed9ea | 274 | cbdataRegisterWithCacheManager(void) |
62ee09ca | 275 | { |
8822ebee | 276 | Mgr::RegisterAction("cbdata", |
d9fc6862 A |
277 | "Callback Data Registry Contents", |
278 | cbdataDump, 0, 1); | |
9a0a18de | 279 | #if USE_CBDATA_DEBUG |
62ee09ca | 280 | |
8822ebee | 281 | Mgr::RegisterAction("cbdatahistory", |
d9fc6862 A |
282 | "Detailed call history for all current cbdata contents", |
283 | cbdataDumpHistory, 0, 1); | |
62ee09ca | 284 | #endif |
285 | } | |
286 | ||
28c60158 | 287 | void * |
9a0a18de | 288 | #if USE_CBDATA_DEBUG |
72711e31 | 289 | cbdataInternalAllocDbg(cbdata_type type, const char *file, int line) |
4e3f712d | 290 | #else |
72711e31 | 291 | cbdataInternalAlloc(cbdata_type type) |
4e3f712d | 292 | #endif |
a2172245 | 293 | { |
b4bab919 | 294 | cbdata *c; |
295 | void *p; | |
aa839030 | 296 | assert(type > 0 && type <= cbdata_types); |
297 | /* placement new: the pool alloc gives us cbdata + user type memory space | |
298 | * and we init it with cbdata at the start of it | |
299 | */ | |
b4bab919 | 300 | #if HASHED_CBDATA |
301 | c = new cbdata; | |
302 | p = cbdata_index[type].pool->alloc(); | |
303 | c->hash.key = p; | |
304 | hash_join(cbdata_htable, &c->hash); | |
305 | #else | |
306 | c = new (cbdata_index[type].pool->alloc()) cbdata; | |
307 | p = (void *)&c->data; | |
308 | #endif | |
f668fcda | 309 | |
b4bab919 | 310 | c->type = type; |
311 | c->valid = 1; | |
312 | c->locks = 0; | |
313 | c->cookie = (long) c ^ cbdata::Cookie; | |
d7ae3534 | 314 | ++cbdataCount; |
9a0a18de | 315 | #if USE_CBDATA_DEBUG |
62e76326 | 316 | |
b4bab919 | 317 | c->file = file; |
318 | c->line = line; | |
85b067e3 | 319 | c->calls = std::vector<CBDataCall *> (); |
b4bab919 | 320 | c->addHistory("Alloc", file, line); |
321 | dlinkAdd(c, &c->link, &cbdataEntries); | |
bf8fe701 | 322 | debugs(45, 3, "cbdataAlloc: " << p << " " << file << ":" << line); |
c4eab974 AR |
323 | #else |
324 | debugs(45, 9, "cbdataAlloc: " << p); | |
fa80a8ef | 325 | #endif |
62e76326 | 326 | |
b4bab919 | 327 | return p; |
b8a2718d | 328 | } |
329 | ||
c29316a4 | 330 | void * |
9a0a18de | 331 | #if USE_CBDATA_DEBUG |
fa80a8ef | 332 | cbdataInternalFreeDbg(void *p, const char *file, int line) |
333 | #else | |
72711e31 | 334 | cbdataInternalFree(void *p) |
fa80a8ef | 335 | #endif |
a2172245 | 336 | { |
28c60158 | 337 | cbdata *c; |
b4bab919 | 338 | #if HASHED_CBDATA |
339 | c = (cbdata *) hash_lookup(cbdata_htable, p); | |
340 | #else | |
43ae1d95 | 341 | c = (cbdata *) (((char *) p) - cbdata::Offset); |
b4bab919 | 342 | #endif |
9a0a18de | 343 | #if USE_CBDATA_DEBUG |
62e76326 | 344 | |
bf8fe701 | 345 | debugs(45, 3, "cbdataFree: " << p << " " << file << ":" << line); |
fa80a8ef | 346 | #else |
62e76326 | 347 | |
bf8fe701 | 348 | debugs(45, 9, "cbdataFree: " << p); |
fa80a8ef | 349 | #endif |
62e76326 | 350 | |
06a5ae20 | 351 | c->check(__LINE__); |
a2fb868f | 352 | assert(c->valid); |
3015e83a | 353 | c->valid = 0; |
9a0a18de | 354 | #if USE_CBDATA_DEBUG |
62e76326 | 355 | |
e48ed433 | 356 | c->addHistory("Free", file, line); |
357 | #endif | |
62e76326 | 358 | |
3015e83a | 359 | if (c->locks) { |
bf8fe701 | 360 | debugs(45, 9, "cbdataFree: " << p << " has " << c->locks << " locks, not freeing"); |
62e76326 | 361 | return NULL; |
3015e83a | 362 | } |
62e76326 | 363 | |
5e263176 | 364 | --cbdataCount; |
bf8fe701 | 365 | debugs(45, 9, "cbdataFree: Freeing " << p); |
9a0a18de | 366 | #if USE_CBDATA_DEBUG |
62e76326 | 367 | |
fa80a8ef | 368 | dlinkDelete(&c->link, &cbdataEntries); |
369 | #endif | |
62e76326 | 370 | |
f668fcda | 371 | /* This is ugly. But: operator delete doesn't get |
26ac0430 | 372 | * the type parameter, so we can't use that |
f668fcda | 373 | * to free the memory. |
374 | * So, we free it ourselves. | |
26ac0430 | 375 | * Note that this means a non-placement |
f668fcda | 376 | * new would be a seriously bad idea. |
377 | * Lastly, if we where a templated class, | |
378 | * we could use the normal delete operator | |
379 | * and it would Just Work. RBC 20030902 | |
380 | */ | |
b4bab919 | 381 | cbdata_type theType = c->type; |
382 | #if HASHED_CBDATA | |
383 | hash_remove_link(cbdata_htable, &c->hash); | |
384 | delete c; | |
dc47f531 | 385 | cbdata_index[theType].pool->freeOne((void *)p); |
b4bab919 | 386 | #else |
387 | c->cbdata::~cbdata(); | |
dc47f531 | 388 | cbdata_index[theType].pool->freeOne(c); |
b4bab919 | 389 | #endif |
c29316a4 | 390 | return NULL; |
72711e31 | 391 | } |
392 | ||
a2172245 | 393 | void |
9a0a18de | 394 | #if USE_CBDATA_DEBUG |
fa80a8ef | 395 | cbdataInternalLockDbg(const void *p, const char *file, int line) |
b7e6c377 | 396 | #else |
fa80a8ef | 397 | cbdataInternalLock(const void *p) |
b7e6c377 | 398 | #endif |
a2172245 | 399 | { |
3015e83a | 400 | cbdata *c; |
62e76326 | 401 | |
3015e83a | 402 | if (p == NULL) |
62e76326 | 403 | return; |
404 | ||
b4bab919 | 405 | #if HASHED_CBDATA |
406 | c = (cbdata *) hash_lookup(cbdata_htable, p); | |
407 | #else | |
43ae1d95 | 408 | c = (cbdata *) (((char *) p) - cbdata::Offset); |
b4bab919 | 409 | #endif |
62e76326 | 410 | |
9a0a18de | 411 | #if USE_CBDATA_DEBUG |
62e76326 | 412 | |
bf8fe701 | 413 | debugs(45, 3, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1) << " " << file << ":" << line); |
62e76326 | 414 | |
e48ed433 | 415 | c->addHistory("Reference", file, line); |
62e76326 | 416 | |
fa80a8ef | 417 | #else |
62e76326 | 418 | |
bf8fe701 | 419 | debugs(45, 9, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1)); |
62e76326 | 420 | |
b7e6c377 | 421 | #endif |
62e76326 | 422 | |
06a5ae20 | 423 | c->check(__LINE__); |
62e76326 | 424 | |
3ad2eed0 | 425 | assert(c->locks < INT_MAX); |
62e76326 | 426 | |
d7ae3534 | 427 | ++ c->locks; |
a2172245 | 428 | } |
429 | ||
430 | void | |
9a0a18de | 431 | #if USE_CBDATA_DEBUG |
fa80a8ef | 432 | cbdataInternalUnlockDbg(const void *p, const char *file, int line) |
b7e6c377 | 433 | #else |
fa80a8ef | 434 | cbdataInternalUnlock(const void *p) |
b7e6c377 | 435 | #endif |
a2172245 | 436 | { |
3015e83a | 437 | cbdata *c; |
62e76326 | 438 | |
3015e83a | 439 | if (p == NULL) |
62e76326 | 440 | return; |
441 | ||
b4bab919 | 442 | #if HASHED_CBDATA |
443 | c = (cbdata *) hash_lookup(cbdata_htable, p); | |
444 | #else | |
43ae1d95 | 445 | c = (cbdata *) (((char *) p) - cbdata::Offset); |
b4bab919 | 446 | #endif |
62e76326 | 447 | |
9a0a18de | 448 | #if USE_CBDATA_DEBUG |
62e76326 | 449 | |
bf8fe701 | 450 | debugs(45, 3, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1) << " " << file << ":" << line); |
62e76326 | 451 | |
e48ed433 | 452 | c->addHistory("Dereference", file, line); |
62e76326 | 453 | |
fa80a8ef | 454 | #else |
62e76326 | 455 | |
bf8fe701 | 456 | debugs(45, 9, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1)); |
62e76326 | 457 | |
fa80a8ef | 458 | #endif |
62e76326 | 459 | |
06a5ae20 | 460 | c->check(__LINE__); |
62e76326 | 461 | |
3015e83a | 462 | assert(c != NULL); |
62e76326 | 463 | |
3015e83a | 464 | assert(c->locks > 0); |
62e76326 | 465 | |
5e263176 | 466 | -- c->locks; |
62e76326 | 467 | |
aab9676e | 468 | if (c->valid || c->locks) |
62e76326 | 469 | return; |
470 | ||
5e263176 | 471 | --cbdataCount; |
62e76326 | 472 | |
bf8fe701 | 473 | debugs(45, 9, "cbdataUnlock: Freeing " << p); |
62e76326 | 474 | |
9a0a18de | 475 | #if USE_CBDATA_DEBUG |
62e76326 | 476 | |
fa80a8ef | 477 | dlinkDelete(&c->link, &cbdataEntries); |
62e76326 | 478 | |
fa80a8ef | 479 | #endif |
62e76326 | 480 | |
f668fcda | 481 | /* This is ugly. But: operator delete doesn't get |
26ac0430 | 482 | * the type parameter, so we can't use that |
f668fcda | 483 | * to free the memory. |
484 | * So, we free it ourselves. | |
26ac0430 | 485 | * Note that this means a non-placement |
f668fcda | 486 | * new would be a seriously bad idea. |
487 | * Lastly, if we where a templated class, | |
488 | * we could use the normal delete operator | |
489 | * and it would Just Work. RBC 20030902 | |
490 | */ | |
b4bab919 | 491 | cbdata_type theType = c->type; |
492 | #if HASHED_CBDATA | |
493 | hash_remove_link(cbdata_htable, &c->hash); | |
494 | delete c; | |
dc47f531 | 495 | cbdata_index[theType].pool->freeOne((void *)p); |
b4bab919 | 496 | #else |
497 | c->cbdata::~cbdata(); | |
dc47f531 | 498 | cbdata_index[theType].pool->freeOne(c); |
b4bab919 | 499 | #endif |
a2172245 | 500 | } |
501 | ||
502 | int | |
fa80a8ef | 503 | cbdataReferenceValid(const void *p) |
a2172245 | 504 | { |
3015e83a | 505 | cbdata *c; |
62e76326 | 506 | |
3015e83a | 507 | if (p == NULL) |
62e76326 | 508 | return 1; /* A NULL pointer cannot become invalid */ |
509 | ||
bf8fe701 | 510 | debugs(45, 9, "cbdataReferenceValid: " << p); |
62e76326 | 511 | |
b4bab919 | 512 | #if HASHED_CBDATA |
513 | c = (cbdata *) hash_lookup(cbdata_htable, p); | |
514 | #else | |
43ae1d95 | 515 | c = (cbdata *) (((char *) p) - cbdata::Offset); |
b4bab919 | 516 | #endif |
62e76326 | 517 | |
06a5ae20 | 518 | c->check(__LINE__); |
62e76326 | 519 | |
3015e83a | 520 | assert(c->locks > 0); |
62e76326 | 521 | |
3015e83a | 522 | return c->valid; |
a2172245 | 523 | } |
524 | ||
fa80a8ef | 525 | int |
9a0a18de | 526 | #if USE_CBDATA_DEBUG |
fa80a8ef | 527 | cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line) |
528 | #else | |
529 | cbdataInternalReferenceDoneValid(void **pp, void **tp) | |
530 | #endif | |
531 | { | |
532 | void *p = (void *) *pp; | |
533 | int valid = cbdataReferenceValid(p); | |
534 | *pp = NULL; | |
9a0a18de | 535 | #if USE_CBDATA_DEBUG |
62e76326 | 536 | |
fa80a8ef | 537 | cbdataInternalUnlockDbg(p, file, line); |
538 | #else | |
62e76326 | 539 | |
fa80a8ef | 540 | cbdataInternalUnlock(p); |
541 | #endif | |
62e76326 | 542 | |
fa80a8ef | 543 | if (valid) { |
62e76326 | 544 | *tp = p; |
545 | return 1; | |
fa80a8ef | 546 | } else { |
62e76326 | 547 | *tp = NULL; |
548 | return 0; | |
fa80a8ef | 549 | } |
550 | } | |
551 | ||
9a0a18de | 552 | #if USE_CBDATA_DEBUG |
e48ed433 | 553 | void |
43ae1d95 | 554 | cbdata::dump(StoreEntry *sentry) const |
e48ed433 | 555 | { |
b4bab919 | 556 | #if HASHED_CBDATA |
c692f6b0 | 557 | void *p = (void *)hash.key; |
b4bab919 | 558 | #else |
c692f6b0 | 559 | void *p = (void *)&data; |
b4bab919 | 560 | #endif |
e48ed433 | 561 | storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' : |
b4bab919 | 562 | '!', p, type, locks, file, line); |
e48ed433 | 563 | } |
564 | ||
26ac0430 AJ |
565 | struct CBDataDumper : public unary_function<cbdata, void> { |
566 | CBDataDumper(StoreEntry *anEntry):where(anEntry) {} | |
62e76326 | 567 | |
26ac0430 | 568 | void operator()(cbdata const &x) { |
62e76326 | 569 | x.dump(where); |
e48ed433 | 570 | } |
62e76326 | 571 | |
e48ed433 | 572 | StoreEntry *where; |
573 | }; | |
62e76326 | 574 | |
e48ed433 | 575 | #endif |
fa80a8ef | 576 | |
db1cd23c | 577 | static void |
3015e83a | 578 | cbdataDump(StoreEntry * sentry) |
a2172245 | 579 | { |
8b9a2d90 | 580 | storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount); |
9a0a18de | 581 | #if USE_CBDATA_DEBUG |
62e76326 | 582 | |
fa80a8ef | 583 | storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n"); |
e48ed433 | 584 | CBDataDumper dumper(sentry); |
585 | for_each (cbdataEntries, dumper); | |
fa80a8ef | 586 | storeAppendPrintf(sentry, "\n"); |
587 | storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n"); | |
62e76326 | 588 | |
d7ae3534 | 589 | for (int i = 1; i < cbdata_types; ++i) { |
b4bab919 | 590 | MemAllocator *pool = cbdata_index[i].pool; |
62e76326 | 591 | |
592 | if (pool) { | |
b4bab919 | 593 | #if HASHED_CBDATA |
594 | int obj_size = pool->objectSize(); | |
595 | #else | |
b001e822 | 596 | int obj_size = pool->objectSize() - cbdata::Offset; |
b4bab919 | 597 | #endif |
06a0702b | 598 | storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.level, (long int)obj_size * pool->getMeter().inuse.level); |
62e76326 | 599 | } |
fa80a8ef | 600 | } |
62e76326 | 601 | |
fa80a8ef | 602 | #else |
9a0a18de | 603 | storeAppendPrintf(sentry, "detailed allocation information only available when compiled with --enable-debug-cbdata\n"); |
62e76326 | 604 | |
fa80a8ef | 605 | #endif |
62e76326 | 606 | |
fa80a8ef | 607 | storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n"); |
a2172245 | 608 | } |
e48ed433 | 609 | |
aa839030 | 610 | CBDATA_CLASS_INIT(generic_cbdata); |
611 | ||
9a0a18de | 612 | #if USE_CBDATA_DEBUG |
e48ed433 | 613 | |
26ac0430 AJ |
614 | struct CBDataCallDumper : public unary_function<CBDataCall, void> { |
615 | CBDataCallDumper (StoreEntry *anEntry):where(anEntry) {} | |
62e76326 | 616 | |
85b067e3 FC |
617 | void operator()(CBDataCall * const &x) { |
618 | storeAppendPrintf(where, "%s\t%s\t%d\n", x->label, x->file, x->line); | |
e48ed433 | 619 | } |
62e76326 | 620 | |
e48ed433 | 621 | StoreEntry *where; |
622 | }; | |
623 | ||
26ac0430 AJ |
624 | struct CBDataHistoryDumper : public CBDataDumper { |
625 | CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry) {} | |
62e76326 | 626 | |
26ac0430 | 627 | void operator()(cbdata const &x) { |
62e76326 | 628 | CBDataDumper::operator()(x); |
629 | storeAppendPrintf(where, "\n"); | |
630 | storeAppendPrintf(where, "Action\tFile\tLine\n"); | |
85b067e3 | 631 | std::for_each (x.calls.begin(), x.calls.end(), callDumper); |
62e76326 | 632 | storeAppendPrintf(where, "\n"); |
e48ed433 | 633 | } |
62e76326 | 634 | |
e48ed433 | 635 | StoreEntry *where; |
636 | CBDataCallDumper callDumper; | |
637 | }; | |
638 | ||
639 | void | |
640 | cbdataDumpHistory(StoreEntry *sentry) | |
641 | { | |
642 | storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount); | |
643 | storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n"); | |
644 | CBDataHistoryDumper dumper(sentry); | |
645 | for_each (cbdataEntries, dumper); | |
646 | } | |
62e76326 | 647 | |
e48ed433 | 648 | #endif |