cbdata.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 45 Callback Data Registry */
10
11#include "squid.h"
12#include "cbdata.h"
13#include "Generic.h"
14#include "mem/Pool.h"
15#include "mgr/Registration.h"
16#include "Store.h"
17
18#include <climits>
19#include <cstddef>
20
21#if USE_CBDATA_DEBUG
22#include <algorithm>
23#include <vector>
24#endif
25
26#if WITH_VALGRIND
27#include <map>
28#endif
29
30static int cbdataCount = 0;
31#if USE_CBDATA_DEBUG
32dlink_list cbdataEntries;
33#endif
34
35#if USE_CBDATA_DEBUG
36
37class CBDataCall
38{
39
40public:
41 CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine) {}
42
43 char const *label;
44 char const *file;
45 int line;
46};
47
48#endif
49
59class cbdata
60{
61#if !WITH_VALGRIND
62public:
63 void *operator new(size_t, void *where) {return where;}
68 void operator delete(void *, void *) {}
69#else
71#endif
72
73 /* TODO: examine making cbdata templated on this - so we get type
74 * safe access to data - RBC 20030902 */
75public:
76#if USE_CBDATA_DEBUG
77
78 void dump(StoreEntry *)const;
79#endif
81 valid(0),
82 locks(0),
84#if USE_CBDATA_DEBUG
85 file(nullptr),
86 line(0),
87#endif
88 cookie(0),
89 data(nullptr)
90 {}
91 ~cbdata();
92
93 static cbdata *FromUserData(const void *);
94
95 int valid;
96 int32_t locks;
98#if USE_CBDATA_DEBUG
99
100 void addHistory(char const *label, char const *aFile, int aLine) {
101 if (calls.size() > 1000)
102 return;
103
104 calls.push_back(new CBDataCall(label, aFile, aLine));
105 }
106
107 dlink_node link;
108 const char *file;
109 int line;
110 std::vector<CBDataCall*> calls; // used as a stack with random access operator
111#endif
112
113 /* cookie used while debugging */
114 long cookie;
115 void check(int) const {assert(cookie == ((long)this ^ Cookie));}
116 static const long Cookie;
117
118#if !WITH_VALGRIND
119 size_t dataSize() const { return sizeof(data);}
120#endif
121 /* MUST be the last per-instance member */
122 void *data;
123};
124
125static_assert(std::is_standard_layout<cbdata>::value, "the behavior of offsetof(cbdata) is defined");
126
127const long cbdata::Cookie((long)0xDEADBEEF);
128
130#if USE_CBDATA_DEBUG
131static OBJH cbdataDumpHistory;
132#endif
133
136}
137*cbdata_index = nullptr;
138
140
141#if WITH_VALGRIND
142static std::map<const void *, cbdata *> cbdata_htable;
143#endif
144
146{
147#if USE_CBDATA_DEBUG
148
149 while (!calls.empty()) {
150 delete calls.back();
151 calls.pop_back();
152 }
153
154#endif
155
156#if WITH_VALGRIND
157 void *p = data;
158#else
159 void *p = this;
160#endif
162}
163
164cbdata *
165cbdata::FromUserData(const void *p) {
166#if WITH_VALGRIND
167 return cbdata_htable.at(p);
168#else
169 const auto t = static_cast<const char *>(p) - offsetof(cbdata, data);
170 return reinterpret_cast<cbdata *>(const_cast<char *>(t));
171#endif
172}
173
174static void
176{
177 char *label;
178 assert (type == cbdata_types + 1);
179
180 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
181 memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
183
184 label = (char *)xmalloc(strlen(name) + 20);
185
186 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
187
188#if !WITH_VALGRIND
189 size += offsetof(cbdata, data);
190#endif
191
193}
194
197{
198 if (type)
199 return type;
200
204
205 return type;
206}
207
208void
210{
211 Mgr::RegisterAction("cbdata",
212 "Callback Data Registry Contents",
213 cbdataDump, 0, 1);
214#if USE_CBDATA_DEBUG
215
216 Mgr::RegisterAction("cbdatahistory",
217 "Detailed call history for all current cbdata contents",
218 cbdataDumpHistory, 0, 1);
219#endif
220}
221
222void *
223cbdataInternalAlloc(cbdata_type type, const char *file, int line)
224{
225 cbdata *c;
226 void *p;
227 assert(type > 0 && type <= cbdata_types);
228 /* placement new: the pool alloc gives us cbdata + user type memory space
229 * and we init it with cbdata at the start of it
230 */
231#if WITH_VALGRIND
232 c = new cbdata;
233 p = cbdata_index[type].pool->alloc();
234 c->data = p;
235 cbdata_htable.emplace(p,c);
236#else
237 c = new (cbdata_index[type].pool->alloc()) cbdata;
238 p = (void *)&c->data;
239#endif
240
241 c->type = type;
242 c->valid = 1;
243 c->locks = 0;
244 c->cookie = (long) c ^ cbdata::Cookie;
245 ++cbdataCount;
246#if USE_CBDATA_DEBUG
247
248 c->file = file;
249 c->line = line;
250 c->calls = std::vector<CBDataCall *> ();
251 c->addHistory("Alloc", file, line);
252 dlinkAdd(c, &c->link, &cbdataEntries);
253 debugs(45, 3, "Allocating " << p << " " << file << ":" << line);
254#else
255 (void)file;
256 (void)line;
257 debugs(45, 9, "Allocating " << p);
258#endif
259
260 return p;
261}
262
263static void
264cbdataRealFree(cbdata *c, const char *file, const int line)
265{
266#if WITH_VALGRIND
267 void *p = c->data;
268#else
269 void *p = (void *)&c->data;
270#endif
271
272 --cbdataCount;
273#if USE_CBDATA_DEBUG
274 debugs(45, 3, "Freeing " << p << ' ' << file << ':' << line);
275 dlinkDelete(&c->link, &cbdataEntries);
276#else
277 debugs(45, 9, "Freeing " << p);
278 (void)file;
279 (void)line;
280#endif
281
282#if WITH_VALGRIND
283 cbdata_htable.erase(p);
284 delete c;
285#else
286 /* This is ugly. But: operator delete doesn't get
287 * the type parameter, so we can't use that
288 * to free the memory.
289 * So, we free it ourselves.
290 * Note that this means a non-placement
291 * new would be a seriously bad idea.
292 * Lastly, if we where a templated class,
293 * we could use the normal delete operator
294 * and it would Just Work. RBC 20030902
295 */
296 c->cbdata::~cbdata();
297#endif
298}
299
300void *
301cbdataInternalFree(void *p, const char *file, int line)
302{
303 auto *c = cbdata::FromUserData(p);
304#if USE_CBDATA_DEBUG
305 debugs(45, 3, p << " " << file << ":" << line);
306#else
307 debugs(45, 9, p);
308#endif
309
310 c->check(__LINE__);
311 assert(c->valid);
312 c->valid = 0;
313#if USE_CBDATA_DEBUG
314
315 c->addHistory("Free", file, line);
316#endif
317
318 if (c->locks) {
319 debugs(45, 9, p << " has " << c->locks << " locks, not freeing");
320 return nullptr;
321 }
322
323 cbdataRealFree(c, file, line);
324 return nullptr;
325}
326
327void
328#if USE_CBDATA_DEBUG
329cbdataInternalLockDbg(const void *p, const char *file, int line)
330#else
331cbdataInternalLock(const void *p)
332#endif
333{
334 if (p == nullptr)
335 return;
336
337 auto *c = cbdata::FromUserData(p);
338
339#if USE_CBDATA_DEBUG
340 debugs(45, 3, p << "=" << (c ? c->locks + 1 : -1) << " " << file << ":" << line);
341 c->addHistory("Reference", file, line);
342#else
343 debugs(45, 9, p << "=" << (c ? c->locks + 1 : -1));
344#endif
345
346 c->check(__LINE__);
347
348 assert(c->locks < INT_MAX);
349
350 ++ c->locks;
351}
352
353void
354#if USE_CBDATA_DEBUG
355cbdataInternalUnlockDbg(const void *p, const char *file, int line)
356#else
358#endif
359{
360 if (p == nullptr)
361 return;
362
363 auto *c = cbdata::FromUserData(p);
364
365#if USE_CBDATA_DEBUG
366 debugs(45, 3, p << "=" << (c ? c->locks - 1 : -1) << " " << file << ":" << line);
367 c->addHistory("Dereference", file, line);
368#else
369 debugs(45, 9, p << "=" << (c ? c->locks - 1 : -1));
370#endif
371
372 c->check(__LINE__);
373
374 assert(c != nullptr);
375
376 assert(c->locks > 0);
377
378 -- c->locks;
379
380 if (c->locks)
381 return;
382
383 if (c->valid) {
384#if USE_CBDATA_DEBUG
385 debugs(45, 3, "CBDATA valid with no references ... cbdata=" << p << " " << file << ":" << line);
386#endif
387 return;
388 }
389
390#if USE_CBDATA_DEBUG
391 cbdataRealFree(c, file, line);
392#else
393 cbdataRealFree(c, NULL, 0);
394#endif
395}
396
397int
399{
400 if (p == nullptr)
401 return 1; /* A NULL pointer cannot become invalid */
402
403 debugs(45, 9, p);
404
405 const auto c = cbdata::FromUserData(p);
406
407 c->check(__LINE__);
408
409 assert(c->locks > 0);
410
411 return c->valid;
412}
413
414int
415#if USE_CBDATA_DEBUG
416cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
417#else
419#endif
420{
421 void *p = (void *) *pp;
422 int valid = cbdataReferenceValid(p);
423 *pp = nullptr;
424#if USE_CBDATA_DEBUG
425
426 cbdataInternalUnlockDbg(p, file, line);
427#else
428
430#endif
431
432 if (valid) {
433 *tp = p;
434 return 1;
435 } else {
436 *tp = nullptr;
437 return 0;
438 }
439}
440
441#if USE_CBDATA_DEBUG
442void
443cbdata::dump(StoreEntry *sentry) const
444{
445#if WITH_VALGRIND
446 void *p = data;
447#else
448 void *p = (void *)&data;
449#endif
450 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
451 '!', p, type, locks, file, line);
452}
453
454struct CBDataDumper : public unary_function<cbdata, void> {
455 CBDataDumper(StoreEntry *anEntry):where(anEntry) {}
456
457 void operator()(cbdata const &x) {
458 x.dump(where);
459 }
460
461 StoreEntry *where;
462};
463
464#endif
465
466static void
468{
469 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
470#if USE_CBDATA_DEBUG
471
472 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
473 CBDataDumper dumper(sentry);
474 for_each (cbdataEntries, dumper);
475 storeAppendPrintf(sentry, "\n");
476 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
477
478 for (int i = 1; i < cbdata_types; ++i) {
479 MemAllocator *pool = cbdata_index[i].pool;
480
481 if (pool) {
482#if WITH_VALGRIND
483 int obj_size = pool->objectSize();
484#else
485 int obj_size = pool->objectSize() - offsetof(cbdata, data);
486#endif
487 storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.currentLevel(), (long int)obj_size * pool->getMeter().inuse.currentLevel());
488 }
489 }
490
491#else
492 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with --enable-debug-cbdata\n");
493
494#endif
495
496 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
497}
498
501{
502 if (data_ != other.data_) { // assignment to self and no-op assignments
503 auto old = data_;
504 data_ = cbdataReference(other.data_);
506 }
507 return *this;
508}
509
511
512#if USE_CBDATA_DEBUG
513
514struct CBDataCallDumper : public unary_function<CBDataCall, void> {
515 CBDataCallDumper (StoreEntry *anEntry):where(anEntry) {}
516
517 void operator()(CBDataCall * const &x) {
518 storeAppendPrintf(where, "%s\t%s\t%d\n", x->label, x->file, x->line);
519 }
520
521 StoreEntry *where;
522};
523
524struct CBDataHistoryDumper : public CBDataDumper {
525 CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry) {}
526
527 void operator()(cbdata const &x) {
528 CBDataDumper::operator()(x);
529 storeAppendPrintf(where, "\n");
530 storeAppendPrintf(where, "Action\tFile\tLine\n");
531 std::for_each (x.calls.begin(), x.calls.end(), callDumper);
532 storeAppendPrintf(where, "\n");
533 }
534
535 StoreEntry *where;
536 CBDataCallDumper callDumper;
537};
538
539void
540cbdataDumpHistory(StoreEntry *sentry)
541{
542 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
543 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
544 CBDataHistoryDumper dumper(sentry);
545 for_each (cbdataEntries, dumper);
546}
547
548#endif
549
T & for_each(L const &head, T &visitor)
Definition: Generic.h:23
int size
Definition: ModDevPoll.cc:75
#define assert(EX)
Definition: assert.h:19
static void cbdataRealFree(cbdata *c, const char *file, const int line)
Definition: cbdata.cc:264
void cbdataInternalUnlock(const void *p)
Definition: cbdata.cc:357
void * cbdataInternalFree(void *p, const char *file, int line)
Definition: cbdata.cc:301
void * cbdataInternalAlloc(cbdata_type type, const char *file, int line)
Definition: cbdata.cc:223
static OBJH cbdataDump
Definition: cbdata.cc:129
int cbdata_types
Definition: cbdata.cc:139
cbdata_type cbdataInternalAddType(cbdata_type type, const char *name, int size)
Definition: cbdata.cc:196
static int cbdataCount
Definition: cbdata.cc:30
void cbdataRegisterWithCacheManager(void)
Definition: cbdata.cc:209
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:398
static std::map< const void *, cbdata * > cbdata_htable
Definition: cbdata.cc:142
struct CBDataIndex * cbdata_index
int cbdataInternalReferenceDoneValid(void **pp, void **tp)
Definition: cbdata.cc:418
void cbdataInternalLock(const void *p)
Definition: cbdata.cc:331
static void cbdataInternalInitType(cbdata_type type, const char *name, int size)
Definition: cbdata.cc:175
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
#define cbdataReference(var)
Definition: cbdata.h:341
static const cbdata_type CBDATA_UNKNOWN
Definition: cbdata.h:196
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
int cbdata_type
Definition: cbdata.h:195
an old-style void* callback parameter
Definition: cbdata.h:377
CallbackData & operator=(const CallbackData &other)
Definition: cbdata.cc:500
void * data_
raw callback data, maybe invalid
Definition: cbdata.h:392
virtual MemPoolMeter const & getMeter() const =0
virtual void freeOne(void *)=0
virtual void * alloc()=0
virtual size_t objectSize() const =0
virtual char const * objectType() const
Definition: Pool.cc:106
Mem::Meter inuse
Definition: Pool.h:99
ssize_t currentLevel() const
Definition: Meter.h:28
Definition: cbdata.cc:60
static const long Cookie
Definition: cbdata.cc:116
MEMPROXY_CLASS(cbdata)
void check(int) const
Definition: cbdata.cc:115
int valid
Definition: cbdata.cc:95
int32_t locks
Definition: cbdata.cc:96
~cbdata()
Definition: cbdata.cc:145
static cbdata * FromUserData(const void *)
Definition: cbdata.cc:165
long cookie
Definition: cbdata.cc:114
cbdata_type type
Definition: cbdata.cc:97
void * data
Definition: cbdata.cc:122
cbdata()
Definition: cbdata.cc:80
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
int type
Definition: errorpage.cc:152
static size_t dataSize(DB_ENTRY *data)
#define memPoolCreate
Definition: Pool.h:325
void OBJH(StoreEntry *)
Definition: forward.h:44
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
#define xmalloc
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:828
MemAllocator * pool
Definition: cbdata.cc:135
int const char size_t
Definition: stub_liblog.cc:86
#define NULL
Definition: types.h:166
#define INT_MAX
Definition: types.h:76
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors