]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.h
Bug 5428: Warn if pkg-config is not found (#1902)
[thirdparty/squid.git] / src / cbdata.h
CommitLineData
aa839030 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
aa839030 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.
aa839030 7 */
8
ffc6d4e9
AJ
9#ifndef SQUID_SRC_CBDATA_H
10#define SQUID_SRC_CBDATA_H
aa839030 11
63be0a78 12/**
ffc6d4e9
AJ
13\page CBDATA Callback Data Allocator API
14
f439fbd2 15 \section CbDataIntro Introduction
ffc6d4e9 16
63be0a78 17 \par
ffc6d4e9
AJ
18 Squid's extensive use of callback functions makes it very
19 susceptible to memory access errors. To address this all callback
20 functions make use of a construct called cbdata. This allows
21 functions doing callbacks to verify that the caller is still
22 valid before making the callback.
23
24 \note cbdata is intended for callback data and is tailored specifically
25 to make callbacks less dangerous leaving as few windows of errors as
26 possible. It is not suitable or intended as a generic RefCount
27 memory allocator.
28
29 \par
30 The AsyncJob/AsyncCall mechanism is preferred over CBDATA.
31 It replaces cbdata with an AsyncCall::Pointer object which
32 performs the same memory protection duties via other means.
33
63be0a78 34 \section Examples Examples
35 \par
ffc6d4e9
AJ
36 Here you can find some examples on how to use cbdata, and why.
37
63be0a78 38 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
39 \par
2f8abb64 40 For a asynchronous operation with callback functions, the normal
ffc6d4e9
AJ
41 sequence of events in programs NOT using cbdata is as follows:
42
63be0a78 43 \code
f53969cc 44 // initialization
ffc6d4e9 45 type_of_data our_data = new ...;
f53969cc 46 ...
2f8abb64 47 // Initiate a asynchronous operation, with our_data as callback_data
f53969cc
SM
48 fooOperationStart(bar, callback_func, our_data);
49 ...
2f8abb64 50 // The asynchronous operation completes and makes the callback
f53969cc
SM
51 callback_func(callback_data, ....);
52 // Some time later we clean up our data
ffc6d4e9 53 delete our_data;
63be0a78 54 \endcode
ffc6d4e9 55
63be0a78 56 \par
ffc6d4e9
AJ
57 However, things become more interesting if we want or need
58 to free the callback_data, or otherwise cancel the callback,
59 before the operation completes. In constructs like this you
60 can quite easily end up with having the memory referenced
61 pointed to by callback_data freed before the callback is invoked
62 causing a program failure or memory corruption:
63
63be0a78 64 \code
f53969cc 65 // initialization
ffc6d4e9 66 type_of_data our_data = new ...;
f53969cc 67 ...
2f8abb64 68 // Initiate a asynchronous operation, with our_data as callback_data
f53969cc
SM
69 fooOperationStart(bar, callback_func, our_data);
70 ...
71 // ouch, something bad happened elsewhere.. try to cleanup
72 // but the programmer forgot there is a callback pending from
ffc6d4e9 73 // fooOperationsStart(). An easy thing to forget when writing code
f53969cc 74 // to deal with errors, especially if there may be many different
ffc6d4e9
AJ
75 // pending operations.
76 delete our_data;
f53969cc 77 ...
2f8abb64 78 // The asynchronous operation completes and makes the callback
f53969cc
SM
79 callback_func(callback_data, ....);
80 // CRASH, the memory pointer to by callback_data is no longer valid
81 // at the time of the callback
63be0a78 82 \endcode
ffc6d4e9 83
2f8abb64 84 \subsection AsyncOpWithCBDATA Asynchronous operation with cbdata
ffc6d4e9 85
63be0a78 86 \par
ffc6d4e9
AJ
87 The callback data allocator lets us do this in a uniform and
88 safe manner. The callback data allocator is used to allocate,
89 track and free memory pool objects used during callback
2f8abb64 90 operations. Allocated memory is locked while the asynchronous
ffc6d4e9
AJ
91 operation executes elsewhere, and is freed when the operation
92 completes. The normal sequence of events is:
93
63be0a78 94 \code
f53969cc 95 // initialization
ffc6d4e9 96 type_of_data our_data = new type_of_data;
f53969cc 97 ...
2f8abb64 98 // Initiate a asynchronous operation, with our_data as callback_data
f53969cc
SM
99 fooOperationStart(..., callback_func, our_data);
100 ...
101 // foo
102 void *local_pointer = cbdataReference(callback_data);
103 ....
2f8abb64 104 // The asynchronous operation completes and makes the callback
f53969cc
SM
105 void *cbdata;
106 if (cbdataReferenceValidDone(local_pointer, &cbdata))
107 callback_func(...., cbdata);
ffc6d4e9 108 delete our_data;
63be0a78 109 \endcode
ffc6d4e9 110
63be0a78 111 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
ffc6d4e9 112
63be0a78 113 \par
ffc6d4e9
AJ
114 With this scheme, nothing bad happens if delete gets called
115 before fooOperantionComplete(...).
116
2f8abb64 117 \par Initialization
63be0a78 118 \code
ffc6d4e9
AJ
119 // initialization
120 type_of_data our_data = new type_of_data;
f53969cc 121 ...
2f8abb64 122 // Initiate a asynchronous operation, with our_data as callback_data
f53969cc 123 fooOperationStart(..., callback_func, our_data);
ffc6d4e9
AJ
124 ...
125 // do some stuff with it
f53969cc 126 void *local_pointer = cbdataReference(callback_data);
ffc6d4e9
AJ
127 ...
128 // something bad happened elsewhere.. cleanup
129 delete our_data;
130 ....
2f8abb64 131 // The asynchronous operation completes and makes the callback
f53969cc
SM
132 void *cbdata;
133 if (cbdataReferenceValidDone(local_pointer, &cbdata))
ffc6d4e9 134 // won't be called, as the data is no longer valid
f53969cc 135 callback_func(...., cbdata);
ffc6d4e9 136 delete our_data;
63be0a78 137 \endcode
ffc6d4e9 138
63be0a78 139 \par
ffc6d4e9
AJ
140 In this case, when delete is called before cbdataReferenceValidDone(),
141 the callback_data gets marked as invalid.
142 When the callback_data is invalid before executing the callback
143 function, cbdataReferenceValidDone() will return 0 and
144 callback_func is never executed.
145
63be0a78 146 \subsection AddingCBDATAType Adding a new cbdata registered type
ffc6d4e9
AJ
147
148 \par
149 To add new module specific data types to the allocator one uses
150 the macro CBDATA_CLASS() in the class private section, and
151 CBDATA_CLASS_INIT() or CBDATA_NAMESPACED_CLASS_INIT() in the
152 class .cc file.
153
154 \code
155 class Foo
156 {
157 CBDATA_CLASS(Foo);
158
159 public:
160 Foo() {}
161 ~Foo() {}
162 };
163 ...
164 CBDATA_CLASS_INIT(Foo);
165 \endcode
166
167 \par
168 These macros create new(), delete() and toCbdata() methods
169 definition in class scope. Any allocate calls must be made with
170 new() and destruction with delete(), they may be called from
171 anywhere.
172
173 \par
174 The class constructor must make sure that all member
175 variables are initialized, and the class destructor that all
176 dynamic memory is released.
177
63be0a78 178 \par
ffc6d4e9
AJ
179 The CbcPointer<> template should be used to create a smart-pointer
180 type for simple reference tracking. It provides get() and valid()
181 accessors for use instead of cbdataReferenceValid(), and performs
182 reliable automatic cbdataReference() and cbdataReferenceDone()
183 tracking.
184 Note that it does NOT provide a replacement for cbdataReferenceValidDone().
185
63be0a78 186 */
187
188/**
e4f1ea43 189 * cbdata types. Similar to the MEM_* types, but managed in cbdata.cc
190 * A big difference is that cbdata types are dynamically allocated.
ffc6d4e9
AJ
191 *
192 * Initially only UNKNOWN type is predefined.
193 * Other types are added at runtime by CBDATA_CLASS().
aa839030 194 */
e4f1ea43 195typedef int cbdata_type;
196static const cbdata_type CBDATA_UNKNOWN = 0;
aa839030 197
63be0a78 198/**
63be0a78 199 * Allocates a new entry of a registered CBDATA type.
ffc6d4e9
AJ
200 *
201 * \note For internal CBDATA use only.
63be0a78 202 */
bcd05a84 203void *cbdataInternalAlloc(cbdata_type type);
63be0a78 204
205/**
ffc6d4e9
AJ
206 * Frees a entry allocated by cbdataInternalAlloc().
207 *
208 * Once this has been called cbdataReferenceValid() and
209 * cbdataReferenceValidDone() will return false regardless
210 * of whether there are remaining cbdata references.
63be0a78 211 *
ffc6d4e9
AJ
212 * cbdataReferenceDone() must still be called for any active
213 * references to the cbdata entry. The cbdata entry will be freed
214 * only when the last reference is removed.
215 *
216 * \note For internal CBDATA use only.
63be0a78 217 */
bcd05a84 218void *cbdataInternalFree(void *p);
5c2f68b7 219
5c2f68b7
AJ
220void cbdataInternalLock(const void *p);
221void cbdataInternalUnlock(const void *p);
63be0a78 222
223/**
63be0a78 224 * Removes a reference created by cbdataReference() and checks
225 * it for validity. Meant to be used on the last dereference,
226 * usually to make a callback.
227 *
228 \code
229 void *cbdata;
230 ...
8b082ed9 231 if (cbdataReferenceValidDone(reference, &cbdata)))
63be0a78 232 callback(..., cbdata);
233 \endcode
234 *
8b082ed9 235 * \param var The reference variable. Will be automatically cleared to nullptr
ffc6d4e9 236 * \param ptr A temporary pointer to the referenced data (if valid).
63be0a78 237 */
5c2f68b7 238int cbdataInternalReferenceDoneValid(void **p, void **tp);
aa839030 239#define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
63be0a78 240
d2bf2f90 241/**
f53969cc 242 * \param p A cbdata entry reference pointer.
f54f527e 243 *
ffc6d4e9 244 * \retval 0 A reference is stale. The pointer refers to a entry already freed.
f53969cc 245 * \retval true The reference is valid and active.
d2bf2f90 246 */
5c2f68b7
AJ
247int cbdataReferenceValid(const void *p);
248
ffc6d4e9
AJ
249/**
250 * Create a run-time registration for the class type with cbdata memory allocator.
251 *
252 * \note For internal CBDATA use only.
253 */
5545e2f4 254cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size);
5c2f68b7 255
1625e4a1
AR
256/// declaration-generator used internally by CBDATA_CLASS() and CBDATA_CHILD()
257#define CBDATA_DECL_(type, methodSpecifiers) \
f53969cc
SM
258 void *operator new(size_t size) { \
259 assert(size == sizeof(type)); \
5545e2f4 260 if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type)); \
bcd05a84 261 return (type *)cbdataInternalAlloc(CBDATA_##type); \
f53969cc 262 } \
c56edb4a 263 public: \
f53969cc 264 void operator delete (void *address) { \
bcd05a84 265 if (address) cbdataInternalFree(address); \
f53969cc 266 } \
1625e4a1 267 void *toCbdata() methodSpecifiers { return this; } \
f53969cc 268 private: \
ffc6d4e9 269 static cbdata_type CBDATA_##type;
63be0a78 270
1625e4a1 271/// Starts cbdata-protection in a class hierarchy.
337b9aa4
AR
272/// Intermediate classes in the same hierarchy must use CBDATA_INTERMEDIATE() if
273/// they risk creating cbdata pointers in their constructors.
274/// Final classes in the same hierarchy must use CBDATA_CHILD().
1625e4a1
AR
275class CbdataParent
276{
277public:
87ae5947 278 virtual ~CbdataParent() {}
1625e4a1 279 virtual void *toCbdata() = 0;
337b9aa4
AR
280
281private:
282 /// hack: ensure CBDATA_CHILD() after a toCbdata()-defining CBDATA_INTERMEDIATE()
283 virtual void finalizedInCbdataChild() = 0;
1625e4a1
AR
284};
285
286/// cbdata-enables a stand-alone class that is not a CbdataParent child
287/// sets the class declaration section to "private"
288/// use this at the start of your class declaration for consistency sake
c56edb4a
EB
289#define CBDATA_CLASS(type) public: CBDATA_DECL_(type, noexcept)
290
291/// A CBDATA_CLASS() variant for classes that want to prevent accidental
292/// operator new() calls by making that operator private and forcing external
293/// users to call a Make() function instead.
294#define CBDATA_CLASS_WITH_MAKE(type) private: CBDATA_DECL_(type, noexcept)
1625e4a1 295
337b9aa4
AR
296/// cbdata-enables a final CbdataParent-derived class in a hierarchy
297/// sets the class declaration section to "private"
298/// use this at the start of your class declaration for consistency sake
c56edb4a 299#define CBDATA_CHILD(type) public: CBDATA_DECL_(type, final) \
337b9aa4
AR
300 void finalizedInCbdataChild() final {}
301
302/// cbdata-enables a non-final CbdataParent-derived class T in a hierarchy.
303/// Using this macro is required to be able to create cbdata pointers in T
304/// constructors, when the current vtable is still pointing to T::toCbdata()
305/// that would have been pure without this macro, leading to FATAL runtime
306/// OnTerminate() calls. However, assuming that the final cbdata pointer will
307/// still point to T::this is risky -- multiple inheritance changes "this"!
308///
1625e4a1
AR
309/// sets the class declaration section to "private"
310/// use this at the start of your class declaration for consistency sake
337b9aa4
AR
311#define CBDATA_INTERMEDIATE() \
312 public: \
313 void *toCbdata() override { return this; } \
314 private:
1625e4a1 315
63be0a78 316/**
ffc6d4e9
AJ
317 * Creates a global instance pointer for the CBDATA memory allocator
318 * to allocate and free objects for the matching CBDATA_CLASS().
63be0a78 319 *
ffc6d4e9 320 * Place this in the appropriate .cc file for the class being registered.
63be0a78 321 *
ffc6d4e9
AJ
322 * May be placed inside an explicit namespace scope declaration,
323 * or CBDATA_NAMESPACED_CLASS_INIT() used instead.
63be0a78 324 */
aa839030 325#define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
63be0a78 326
327/**
ffc6d4e9
AJ
328 * Creates a global instance pointer for the CBDATA memory allocator
329 * to allocate and free objects for the matching CBDATA_CLASS().
330 *
331 * Place this in the appropriate .cc file for the class being registered.
63be0a78 332 */
ffc6d4e9 333#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
63be0a78 334
63be0a78 335/**
ffc6d4e9
AJ
336 * Creates a new reference to a cbdata entry. Used when you need to
337 * store a reference in another structure. The reference can later
338 * be verified for validity by cbdataReferenceValid().
26ac0430 339 *
ffc6d4e9 340 * \deprecated Prefer the use of CbcPointer<> smart pointer.
63be0a78 341 *
ffc6d4e9
AJ
342 * \param var
343 * The reference variable is a pointer to the entry, in all
344 * aspects identical to the original pointer. But semantically it
345 * is quite different. It is best if the reference is thought of
346 * and handled as a "void *".
63be0a78 347 */
ffc6d4e9 348#define cbdataReference(var) (cbdataInternalLock(var), var)
63be0a78 349
350/**
ffc6d4e9 351 * Removes a reference created by cbdataReference().
63be0a78 352 *
ffc6d4e9 353 * \deprecated Prefer the use of CbcPointer<> smart pointer.
5c2f68b7 354 *
8b082ed9 355 * \param var The reference variable. Will be automatically cleared to nullptr
63be0a78 356 */
8b082ed9 357#define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = nullptr;}} while(0)
aa839030 358
63be0a78 359/**
ffc6d4e9 360 * A generic wrapper for passing object pointers through cbdata.
63be0a78 361 * Use this when you need to pass callback data to a blocking
ffc6d4e9
AJ
362 * operation, but you don't want to/cannot have that pointer be
363 * cbdata itself.
aa839030 364 */
aa839030 365class generic_cbdata
366{
5c2f68b7
AJ
367 CBDATA_CLASS(generic_cbdata);
368
26ac0430 369public:
ffc6d4e9 370 generic_cbdata(void *aData) : data(aData) {}
63be0a78 371
26ac0430
AJ
372 template<typename wrapped_type>void unwrap(wrapped_type **output) {
373 *output = static_cast<wrapped_type *>(data);
374 delete this;
375 }
63be0a78 376
bd6e2f16 377private:
ffc6d4e9 378 void *data;
aa839030 379};
380
58fa3f51
CT
381// Discouraged: Use CbcPointer<> and asynchronous calls instead if possible.
382/// an old-style void* callback parameter
383class CallbackData
384{
385public:
386 CallbackData(): data_(nullptr) {}
387 CallbackData(void *data): data_(cbdataReference(data)) {}
388 CallbackData(const CallbackData &other): data_(cbdataReference(other.data_)) {}
389 CallbackData(CallbackData &&other): data_(other.data_) { other.data_ = nullptr; }
390 ~CallbackData() { cbdataReferenceDone(data_); }
391
fd9c47d1
AR
392 CallbackData &operator =(const CallbackData &other);
393 CallbackData &operator =(CallbackData &&other) { cbdataReferenceDone(data_); data_ = other.data_; other.data_ = nullptr; return *this; }
58fa3f51 394
fd9c47d1 395 bool valid() const { return cbdataReferenceValid(data_); }
58fa3f51
CT
396 void *validDone() { void *result; return cbdataReferenceValidDone(data_, &result) ? result : nullptr; }
397
398private:
399 void *data_; ///< raw callback data, maybe invalid
400};
401
ff9d9458 402#endif /* SQUID_SRC_CBDATA_H */
f53969cc 403