]>
Commit | Line | Data |
---|---|---|
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 | 58 | static int cbdataCount = 0; |
fa80a8ef | 59 | #if CBDATA_DEBUG |
60 | dlink_list cbdataEntries; | |
61 | #endif | |
8b9a2d90 | 62 | |
e48ed433 | 63 | #if CBDATA_DEBUG |
62e76326 | 64 | |
65 | class CBDataCall | |
66 | { | |
67 | ||
e48ed433 | 68 | public: |
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 | ||
80 | class cbdata | |
62e76326 | 81 | { |
43ae1d95 | 82 | |
83 | public: | |
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 | 118 | void 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 | 127 | const long cbdata::Cookie((long)0xDEADBEEF); |
43ae1d95 | 128 | const long cbdata::Offset(MakeOffset()); |
129 | ||
f668fcda | 130 | void * |
131 | cbdata::operator new(size_t size, void *where) | |
132 | { | |
133 | // assert (size == sizeof(cbdata)); | |
134 | return where; | |
135 | } | |
136 | ||
137 | void | |
138 | cbdata::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 | 146 | long |
147 | cbdata::MakeOffset() | |
148 | { | |
149 | cbdata *zero = (cbdata *)0L; | |
150 | void **dataOffset = &zero->data; | |
151 | return (long)dataOffset; | |
152 | } | |
a2172245 | 153 | |
db1cd23c | 154 | static OBJH cbdataDump; |
e48ed433 | 155 | #ifdef CBDATA_DEBUG |
156 | static OBJH cbdataDumpHistory; | |
157 | #endif | |
a2172245 | 158 | |
62e76326 | 159 | struct CBDataIndex |
160 | { | |
b001e822 | 161 | MemAllocatorProxy *pool; |
72711e31 | 162 | FREE *free_func; |
62e76326 | 163 | } |
164 | ||
165 | *cbdata_index = NULL; | |
28c60158 | 166 | int cbdata_types = 0; |
167 | ||
f668fcda | 168 | cbdata::~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 | 184 | static void |
185 | cbdataInternalInitType(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 | 210 | cbdata_type |
fa80a8ef | 211 | cbdataInternalAddType(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 | 223 | void |
224 | cbdataInit(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 | 253 | void * |
4e3f712d | 254 | #if CBDATA_DEBUG |
72711e31 | 255 | cbdataInternalAllocDbg(cbdata_type type, const char *file, int line) |
4e3f712d | 256 | #else |
72711e31 | 257 | cbdataInternalAlloc(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 | 283 | void * |
fa80a8ef | 284 | #if CBDATA_DEBUG |
285 | cbdataInternalFreeDbg(void *p, const char *file, int line) | |
286 | #else | |
72711e31 | 287 | cbdataInternalFree(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 | 338 | void |
b7e6c377 | 339 | #if CBDATA_DEBUG |
fa80a8ef | 340 | cbdataInternalLockDbg(const void *p, const char *file, int line) |
b7e6c377 | 341 | #else |
fa80a8ef | 342 | cbdataInternalLock(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 | ||
371 | void | |
b7e6c377 | 372 | #if CBDATA_DEBUG |
fa80a8ef | 373 | cbdataInternalUnlockDbg(const void *p, const char *file, int line) |
b7e6c377 | 374 | #else |
fa80a8ef | 375 | cbdataInternalUnlock(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 | ||
435 | int | |
fa80a8ef | 436 | cbdataReferenceValid(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 | 454 | int |
455 | #if CBDATA_DEBUG | |
456 | cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line) | |
457 | #else | |
458 | cbdataInternalReferenceDoneValid(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 |
482 | void | |
43ae1d95 | 483 | cbdata::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 | 489 | struct 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 | 503 | static void |
3015e83a | 504 | cbdataDump(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 | 534 | struct 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 | ||
546 | struct 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 | ||
563 | void | |
564 | cbdataDumpHistory(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 |