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