cbdata.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 
26 static int cbdataCount = 0;
27 
37 class cbdata
38 {
39 #if !WITH_VALGRIND
40 public:
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 */
53 public:
54  cbdata() :
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 
81 static_assert(std::is_standard_layout<cbdata>::value, "the behavior of offsetof(cbdata) is defined");
82 
83 const long cbdata::Cookie((long)0xDEADBEEF);
84 
85 struct CBDataIndex {
87 }
88 *cbdata_index = nullptr;
89 
90 int cbdata_types = 0;
91 
92 #if WITH_VALGRIND
93 static 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 
111 cbdata *
112 cbdata::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 
122 cbdataInternalAddType(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 
149 void *
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 
177 static 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 
207 void *
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 
221  cbdataRealFree(c);
222  return nullptr;
223 }
224 
225 void
226 cbdataInternalLock(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 
242 void
243 cbdataInternalUnlock(const void *p)
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 
266  cbdataRealFree(c);
267 }
268 
269 int
270 cbdataReferenceValid(const void *p)
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 
286 int
287 cbdataInternalReferenceDoneValid(void **pp, void **tp)
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 
304 CallbackData &
306 {
307  if (data_ != other.data_) { // assignment to self and no-op assignments
308  auto old = data_;
309  data_ = cbdataReference(other.data_);
310  cbdataReferenceDone(old);
311  }
312  return *this;
313 }
314 
316 
an old-style void* callback parameter
Definition: cbdata.h:383
int cbdataInternalReferenceDoneValid(void **pp, void **tp)
Definition: cbdata.cc:287
cbdata_type cbdataInternalAddType(cbdata_type type, const char *name, int size)
Definition: cbdata.cc:122
cbdata()
Definition: cbdata.cc:54
CallbackData & operator=(const CallbackData &other)
Definition: cbdata.cc:305
void * cbdataInternalAlloc(cbdata_type type)
Definition: cbdata.cc:150
#define xmalloc
struct CBDataIndex * cbdata_index
void cbdataInternalLock(const void *p)
Definition: cbdata.cc:226
void * alloc()
provide (and reserve) memory suitable for storing one object
Definition: Allocator.h:44
static size_t dataSize(DB_ENTRY *data)
Definition: cbdata.cc:37
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
#define cbdataReference(var)
Definition: cbdata.h:348
int cbdata_types
Definition: cbdata.cc:90
int const char size_t
Definition: stub_liblog.cc:83
void * cbdataInternalFree(void *p)
Definition: cbdata.cc:208
~cbdata()
Definition: cbdata.cc:101
int size
Definition: ModDevPoll.cc:69
static const cbdata_type CBDATA_UNKNOWN
Definition: cbdata.h:196
void freeOne(void *obj)
return memory reserved by alloc()
Definition: Allocator.h:51
static const long Cookie
Definition: cbdata.cc:72
void * data
Definition: cbdata.cc:78
MEMPROXY_CLASS(cbdata)
#define INT_MAX
Definition: types.h:70
cbdata_type type
Definition: cbdata.cc:67
int cbdata_type
Definition: cbdata.h:195
#define memPoolCreate
Creates a named MemPool of elements with the given size.
Definition: Pool.h:123
void check(int) const
Definition: cbdata.cc:71
static int cbdataCount
Definition: cbdata.cc:26
#define assert(EX)
Definition: assert.h:17
int32_t locks
Definition: cbdata.cc:66
static auto & CbdataTable()
Definition: cbdata.cc:94
#define cbdataReferenceDone(var)
Definition: cbdata.h:357
int valid
Definition: cbdata.cc:65
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
static cbdata * FromUserData(const void *)
Definition: cbdata.cc:112
Mem::Allocator * pool
Definition: cbdata.cc:86
static void cbdataRealFree(cbdata *c)
Definition: cbdata.cc:178
long cookie
Definition: cbdata.cc:70
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126
void cbdataInternalUnlock(const void *p)
Definition: cbdata.cc:243
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void * data_
raw callback data, maybe invalid
Definition: cbdata.h:399

 

Introduction

Documentation

Support

Miscellaneous