Squid Web Cache master
Loading...
Searching...
No Matches
cbdata.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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/Allocator.h"
15#include "mem/Pool.h"
16#include "mgr/Registration.h"
17#include "Store.h"
18
19#include <climits>
20#include <cstddef>
21
22#if WITH_VALGRIND
23#include <map>
24#endif
25
26static int cbdataCount = 0;
27
37class cbdata
38{
39#if !WITH_VALGRIND
40public:
41 void *operator new(size_t, void *where) {return where;}
46 void operator delete(void *, void *) {}
47#else
49#endif
50
51 /* TODO: examine making cbdata templated on this - so we get type
52 * safe access to data - RBC 20030902 */
53public:
55 valid(0),
56 locks(0),
58 cookie(0),
59 data(nullptr)
60 {}
61 ~cbdata();
62
63 static cbdata *FromUserData(const void *);
64
65 int valid;
66 int32_t locks;
68
69 /* cookie used while debugging */
70 long cookie;
71 void check(int) const {assert(cookie == ((long)this ^ Cookie));}
72 static const long Cookie;
73
74#if !WITH_VALGRIND
75 size_t dataSize() const { return sizeof(data);}
76#endif
77 /* MUST be the last per-instance member */
78 void *data;
79};
80
81static_assert(std::is_standard_layout<cbdata>::value, "the behavior of offsetof(cbdata) is defined");
82
83const long cbdata::Cookie((long)0xDEADBEEF);
84
88*cbdata_index = nullptr;
89
91
92#if WITH_VALGRIND
93static auto &
95{
96 static const auto htable = new std::map<const void *, cbdata *>();
97 return *htable;
98}
99#endif
100
102{
103#if WITH_VALGRIND
104 void *p = data;
105#else
106 void *p = this;
107#endif
109}
110
111cbdata *
112cbdata::FromUserData(const void *p) {
113#if WITH_VALGRIND
114 return CbdataTable().at(p);
115#else
116 const auto t = static_cast<const char *>(p) - offsetof(cbdata, data);
117 return reinterpret_cast<cbdata *>(const_cast<char *>(t));
118#endif
119}
120
122cbdataInternalAddType(cbdata_type type, const char *name, int size)
123{
124 if (type)
125 return type;
126
127 type = (cbdata_type)(cbdata_types + 1);
128
129 char *label;
130 assert (type == cbdata_types + 1);
131
132 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
133 memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
134 cbdata_types = type;
135
136 label = (char *)xmalloc(strlen(name) + 20);
137
138 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
139
140#if !WITH_VALGRIND
141 size += offsetof(cbdata, data);
142#endif
143
144 cbdata_index[type].pool = memPoolCreate(label, size);
145
146 return type;
147}
148
149void *
151{
152 cbdata *c;
153 void *p;
154 assert(type > 0 && type <= cbdata_types);
155 /* placement new: the pool alloc gives us cbdata + user type memory space
156 * and we init it with cbdata at the start of it
157 */
158#if WITH_VALGRIND
159 c = new cbdata;
160 p = cbdata_index[type].pool->alloc();
161 c->data = p;
162 CbdataTable().emplace(p, c);
163#else
164 c = new (cbdata_index[type].pool->alloc()) cbdata;
165 p = (void *)&c->data;
166#endif
167
168 c->type = type;
169 c->valid = 1;
170 c->locks = 0;
171 c->cookie = (long) c ^ cbdata::Cookie;
172 ++cbdataCount;
173 debugs(45, 9, "Allocating " << p);
174 return p;
175}
176
177static void
179{
180#if WITH_VALGRIND
181 void *p = c->data;
182#else
183 void *p = (void *)&c->data;
184#endif
185
186 --cbdataCount;
187 debugs(45, 9, "Freeing " << p);
188
189#if WITH_VALGRIND
190 CbdataTable().erase(p);
191 delete c;
192#else
193 /* This is ugly. But: operator delete doesn't get
194 * the type parameter, so we can't use that
195 * to free the memory.
196 * So, we free it ourselves.
197 * Note that this means a non-placement
198 * new would be a seriously bad idea.
199 * Lastly, if we where a templated class,
200 * we could use the normal delete operator
201 * and it would Just Work. RBC 20030902
202 */
203 c->cbdata::~cbdata();
204#endif
205}
206
207void *
209{
210 auto *c = cbdata::FromUserData(p);
211
212 c->check(__LINE__);
213 assert(c->valid);
214 c->valid = 0;
215
216 if (c->locks) {
217 debugs(45, 9, p << " has " << c->locks << " locks, not freeing");
218 return nullptr;
219 }
220
222 return nullptr;
223}
224
225void
226cbdataInternalLock(const void *p)
227{
228 if (p == nullptr)
229 return;
230
231 auto *c = cbdata::FromUserData(p);
232
233 debugs(45, 9, p << "=" << (c ? c->locks + 1 : -1));
234
235 c->check(__LINE__);
236
237 assert(c->locks < INT_MAX);
238
239 ++ c->locks;
240}
241
242void
244{
245 if (p == nullptr)
246 return;
247
248 auto *c = cbdata::FromUserData(p);
249
250 debugs(45, 9, p << "=" << (c ? c->locks - 1 : -1));
251
252 c->check(__LINE__);
253
254 assert(c != nullptr);
255
256 assert(c->locks > 0);
257
258 -- c->locks;
259
260 if (c->locks)
261 return;
262
263 if (c->valid)
264 return;
265
267}
268
269int
271{
272 if (p == nullptr)
273 return 1; /* A NULL pointer cannot become invalid */
274
275 debugs(45, 9, p);
276
277 const auto c = cbdata::FromUserData(p);
278
279 c->check(__LINE__);
280
281 assert(c->locks > 0);
282
283 return c->valid;
284}
285
286int
288{
289 void *p = (void *) *pp;
290 int valid = cbdataReferenceValid(p);
291 *pp = nullptr;
292
294
295 if (valid) {
296 *tp = p;
297 return 1;
298 } else {
299 *tp = nullptr;
300 return 0;
301 }
302}
303
306{
307 if (data_ != other.data_) { // assignment to self and no-op assignments
308 auto old = data_;
309 data_ = cbdataReference(other.data_);
311 }
312 return *this;
313}
314
316
int size
Definition ModDevPoll.cc:70
#define memPoolCreate
Creates a named MemPool of elements with the given size.
Definition Pool.h:123
#define assert(EX)
Definition assert.h:17
void * cbdataInternalFree(void *p)
Definition cbdata.cc:208
void cbdataInternalUnlock(const void *p)
Definition cbdata.cc:243
int cbdata_types
Definition cbdata.cc:90
cbdata_type cbdataInternalAddType(cbdata_type type, const char *name, int size)
Definition cbdata.cc:122
static int cbdataCount
Definition cbdata.cc:26
int cbdataReferenceValid(const void *p)
Definition cbdata.cc:270
void * cbdataInternalAlloc(cbdata_type type)
Definition cbdata.cc:150
struct CBDataIndex * cbdata_index
int cbdataInternalReferenceDoneValid(void **pp, void **tp)
Definition cbdata.cc:287
static void cbdataRealFree(cbdata *c)
Definition cbdata.cc:178
void cbdataInternalLock(const void *p)
Definition cbdata.cc:226
static auto & CbdataTable()
Definition cbdata.cc:94
#define cbdataReferenceDone(var)
Definition cbdata.h:357
#define cbdataReference(var)
Definition cbdata.h:348
static const cbdata_type CBDATA_UNKNOWN
Definition cbdata.h:196
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
int cbdata_type
Definition cbdata.h:195
an old-style void* callback parameter
Definition cbdata.h:384
CallbackData & operator=(const CallbackData &other)
Definition cbdata.cc:305
void * data_
raw callback data, maybe invalid
Definition cbdata.h:399
void freeOne(void *obj)
return memory reserved by alloc()
Definition Allocator.h:51
void * alloc()
provide (and reserve) memory suitable for storing one object
Definition Allocator.h:44
static const long Cookie
Definition cbdata.cc:72
MEMPROXY_CLASS(cbdata)
void check(int) const
Definition cbdata.cc:71
int valid
Definition cbdata.cc:65
int32_t locks
Definition cbdata.cc:66
~cbdata()
Definition cbdata.cc:101
static cbdata * FromUserData(const void *)
Definition cbdata.cc:112
long cookie
Definition cbdata.cc:70
cbdata_type type
Definition cbdata.cc:67
void * data
Definition cbdata.cc:78
cbdata()
Definition cbdata.cc:54
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
static size_t dataSize(DB_ENTRY *data)
#define xmalloc
Mem::Allocator * pool
Definition cbdata.cc:86
int const char size_t
#define INT_MAX
Definition types.h:70
void * xrealloc(void *s, size_t sz)
Definition xalloc.cc:126