]>
Commit | Line | Data |
---|---|---|
aa839030 | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 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 | ||
9 | #ifndef SQUID_CBDATA_H | |
10 | #define SQUID_CBDATA_H | |
11 | ||
582c2af2 | 12 | #include "typedefs.h" |
aa839030 | 13 | |
63be0a78 | 14 | /** |
15 | \defgroup CBDATAAPI Callback Data Allocator API | |
16 | \ingroup Components | |
17 | \par | |
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 | * | |
63be0a78 | 29 | * |
30 | \section Examples Examples | |
31 | \par | |
f53969cc | 32 | * Here you can find some examples on how to use cbdata, and why. |
63be0a78 | 33 | * |
34 | \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed | |
35 | \par | |
f53969cc SM |
36 | * For a asyncronous operation with callback functions, the normal |
37 | * sequence of events in programs NOT using cbdata is as follows: | |
63be0a78 | 38 | * |
39 | \code | |
f53969cc SM |
40 | // initialization |
41 | type_of_data our_data; | |
42 | ... | |
43 | our_data = malloc(...); | |
44 | ... | |
45 | // Initiate a asyncronous operation, with our_data as callback_data | |
46 | fooOperationStart(bar, callback_func, our_data); | |
47 | ... | |
48 | // The asyncronous operation completes and makes the callback | |
49 | callback_func(callback_data, ....); | |
50 | // Some time later we clean up our data | |
51 | free(our_data); | |
63be0a78 | 52 | \endcode |
53 | * | |
54 | \par | |
f53969cc SM |
55 | * However, things become more interesting if we want or need |
56 | * to free the callback_data, or otherwise cancel the callback, | |
57 | * before the operation completes. In constructs like this you | |
58 | * can quite easily end up with having the memory referenced | |
59 | * pointed to by callback_data freed before the callback is invoked | |
60 | * causing a program failure or memory corruption: | |
63be0a78 | 61 | * |
62 | \code | |
f53969cc SM |
63 | // initialization |
64 | type_of_data our_data; | |
65 | ... | |
66 | our_data = malloc(...); | |
67 | ... | |
68 | // Initiate a asyncronous operation, with our_data as callback_data | |
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 | |
73 | // fooOperationsStart() (an easy thing to forget when writing code | |
74 | // to deal with errors, especially if there may be many different | |
75 | // pending operation) | |
76 | free(our_data); | |
77 | ... | |
78 | // The asyncronous operation completes and makes the callback | |
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 |
83 | * | |
84 | \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata | |
85 | * | |
86 | \par | |
f53969cc SM |
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 | |
90 | * operations. Allocated memory is locked while the asyncronous | |
91 | * operation executes elsewhere, and is freed when the operation | |
92 | * completes. The normal sequence of events is: | |
63be0a78 | 93 | * |
94 | \code | |
f53969cc SM |
95 | // initialization |
96 | type_of_data our_data; | |
97 | ... | |
98 | our_data = cbdataAlloc(type_of_data); | |
99 | ... | |
100 | // Initiate a asyncronous operation, with our_data as callback_data | |
101 | fooOperationStart(..., callback_func, our_data); | |
102 | ... | |
103 | // foo | |
104 | void *local_pointer = cbdataReference(callback_data); | |
105 | .... | |
106 | // The asyncronous operation completes and makes the callback | |
107 | void *cbdata; | |
108 | if (cbdataReferenceValidDone(local_pointer, &cbdata)) | |
109 | callback_func(...., cbdata); | |
110 | ... | |
111 | cbdataFree(our_data); | |
63be0a78 | 112 | \endcode |
113 | * | |
114 | \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata | |
115 | * | |
116 | \par | |
f53969cc SM |
117 | * With this scheme, nothing bad happens if cbdataFree() gets called |
118 | * before fooOperantionComplete(...). | |
63be0a78 | 119 | * |
f53969cc | 120 | \par Initalization |
63be0a78 | 121 | \code |
f53969cc SM |
122 | type_of_data our_data; |
123 | ... | |
124 | our_data = cbdataAlloc(type_of_data); | |
63be0a78 | 125 | \endcode |
f53969cc | 126 | * Initiate a asyncronous operation, with our_data as callback_data |
63be0a78 | 127 | \code |
f53969cc | 128 | fooOperationStart(..., callback_func, our_data); |
63be0a78 | 129 | \endcode |
f53969cc | 130 | * do some stuff with it |
63be0a78 | 131 | \code |
f53969cc | 132 | void *local_pointer = cbdataReference(callback_data); |
63be0a78 | 133 | \endcode |
f53969cc | 134 | * something bad happened elsewhere.. cleanup |
63be0a78 | 135 | \code |
f53969cc | 136 | cbdataFree(our_data); |
63be0a78 | 137 | \endcode |
f53969cc | 138 | * The asyncronous operation completes and tries to make the callback |
63be0a78 | 139 | \code |
f53969cc SM |
140 | void *cbdata; |
141 | if (cbdataReferenceValidDone(local_pointer, &cbdata)) | |
63be0a78 | 142 | { |
143 | \endcode | |
f53969cc | 144 | * won't be called, as the data is no longer valid |
63be0a78 | 145 | \code |
f53969cc SM |
146 | callback_func(...., cbdata); |
147 | } | |
63be0a78 | 148 | \endcode |
149 | * | |
150 | \par | |
f53969cc SM |
151 | * In this case, when cbdataFree() is called before |
152 | * cbdataReferenceValidDone(), the callback_data gets marked as invalid. | |
153 | * When the callback_data is invalid before executing the callback | |
154 | * function, cbdataReferenceValidDone() will return 0 and | |
155 | * callback_func is never executed. | |
63be0a78 | 156 | * |
157 | \subsection AddingCBDATAType Adding a new cbdata registered type | |
158 | * | |
159 | \par | |
f53969cc SM |
160 | * To add new module specific data types to the allocator one uses the |
161 | * macro CBDATA_CLASS() in the class private section, and CBDATA_CLASS_INIT() | |
55bd8ddc AJ |
162 | * or CBDATA_NAMESPACED_CLASS_INIT() in the .cc file. |
163 | * This creates new(), delete() and toCbdata() methods | |
f53969cc | 164 | * definition in class scope. Any allocate calls must be made with |
55bd8ddc | 165 | * new() and destruction with delete(), they may be called from anywhere. |
63be0a78 | 166 | */ |
167 | ||
168 | /** | |
169 | *\ingroup CBDATAAPI | |
e4f1ea43 | 170 | * cbdata types. Similar to the MEM_* types, but managed in cbdata.cc |
171 | * A big difference is that cbdata types are dynamically allocated. | |
172 | * Initially only UNKNOWN type is predefined. Other types are added runtime. | |
aa839030 | 173 | */ |
e4f1ea43 | 174 | typedef int cbdata_type; |
175 | static const cbdata_type CBDATA_UNKNOWN = 0; | |
aa839030 | 176 | |
63be0a78 | 177 | /// \ingroup CBDATAAPI |
8a648e8d | 178 | void cbdataRegisterWithCacheManager(void); |
63be0a78 | 179 | |
63be0a78 | 180 | /** |
63be0a78 | 181 | * Allocates a new entry of a registered CBDATA type. |
5c2f68b7 | 182 | * \deprecated use CBDATA_CLASS() instead |
63be0a78 | 183 | */ |
5c2f68b7 AJ |
184 | void *cbdataInternalAlloc(cbdata_type type, const char *, int); |
185 | /// \deprecated use CBDATA_CLASS() instead | |
186 | #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__)) | |
63be0a78 | 187 | |
188 | /** | |
5c2f68b7 | 189 | * Frees a entry allocated by cbdataAlloc(). |
63be0a78 | 190 | * |
191 | \note If there are active references to the entry then the entry | |
192 | * will be freed with the last reference is removed. However, | |
193 | * cbdataReferenceValid() will return false for those references. | |
5c2f68b7 | 194 | * \deprecated use CBDATA_CLASS() instead |
63be0a78 | 195 | */ |
5c2f68b7 AJ |
196 | void *cbdataInternalFree(void *p, const char *, int); |
197 | /// \deprecated use CBDATA_CLASS() instead | |
f53969cc | 198 | #define cbdataFree(var) do {if (var) {cbdataInternalFree(var,__FILE__,__LINE__); var = NULL;}} while(0) |
5c2f68b7 AJ |
199 | |
200 | #if USE_CBDATA_DEBUG | |
201 | void cbdataInternalLockDbg(const void *p, const char *, int); | |
f53969cc | 202 | #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__) |
5c2f68b7 AJ |
203 | |
204 | void cbdataInternalUnlockDbg(const void *p, const char *, int); | |
f53969cc | 205 | #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__) |
5c2f68b7 AJ |
206 | |
207 | int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int); | |
208 | #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__) | |
209 | ||
210 | #else | |
211 | void cbdataInternalLock(const void *p); | |
212 | void cbdataInternalUnlock(const void *p); | |
63be0a78 | 213 | |
214 | /** | |
63be0a78 | 215 | * Removes a reference created by cbdataReference() and checks |
216 | * it for validity. Meant to be used on the last dereference, | |
217 | * usually to make a callback. | |
218 | * | |
219 | \code | |
220 | void *cbdata; | |
221 | ... | |
222 | if (cbdataReferenceValidDone(reference, &cbdata)) != NULL) | |
223 | callback(..., cbdata); | |
224 | \endcode | |
225 | * | |
f53969cc SM |
226 | \param var The reference variable. Will be automatically cleared to NULL. |
227 | \param ptr A temporary pointer to the referenced data (if valid). | |
63be0a78 | 228 | */ |
5c2f68b7 | 229 | int cbdataInternalReferenceDoneValid(void **p, void **tp); |
aa839030 | 230 | #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr)) |
63be0a78 | 231 | |
5c2f68b7 AJ |
232 | #endif /* !CBDATA_DEBUG */ |
233 | ||
d2bf2f90 | 234 | /** |
f53969cc | 235 | * \param p A cbdata entry reference pointer. |
f54f527e | 236 | * |
f53969cc SM |
237 | * \retval 0 A reference is stale. The pointer refers to a entry freed by cbdataFree(). |
238 | * \retval true The reference is valid and active. | |
d2bf2f90 | 239 | */ |
5c2f68b7 AJ |
240 | int cbdataReferenceValid(const void *p); |
241 | ||
242 | /// \ingroup CBDATAAPI | |
243 | cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func); | |
244 | ||
245 | /** | |
246 | * This needs to be defined FIRST in the class definition. | |
247 | * It plays with private/public states in C++. | |
248 | */ | |
f53969cc SM |
249 | #define CBDATA_CLASS(type) \ |
250 | public: \ | |
251 | void *operator new(size_t size) { \ | |
252 | assert(size == sizeof(type)); \ | |
253 | if (!CBDATA_##type) \ | |
d6f8a323 | 254 | CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL); \ |
f53969cc SM |
255 | return (type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__); \ |
256 | } \ | |
257 | void operator delete (void *address) { \ | |
258 | if (address) cbdataInternalFree(address,__FILE__,__LINE__);\ | |
259 | } \ | |
5c2f68b7 | 260 | void *toCbdata() { return this; } \ |
f53969cc SM |
261 | private: \ |
262 | static cbdata_type CBDATA_##type; | |
63be0a78 | 263 | |
264 | /** | |
63be0a78 | 265 | \par |
266 | * Creates a new reference to a cbdata entry. Used when you need to | |
267 | * store a reference in another structure. The reference can later | |
268 | * be verified for validity by cbdataReferenceValid(). | |
269 | * | |
270 | \param var | |
271 | * The reference variable is a pointer to the entry, in all | |
272 | * aspects identical to the original pointer. But semantically it | |
273 | * is quite different. It is best if the reference is thought of | |
274 | * and handled as a "void *". | |
275 | */ | |
f53969cc | 276 | #define cbdataReference(var) (cbdataInternalLock(var), var) |
63be0a78 | 277 | |
278 | /** | |
279 | \ingroup CBDATAAPI | |
280 | * Removes a reference created by cbdataReference(). | |
281 | * | |
f53969cc | 282 | \param var The reference variable. Will be automatically cleared to NULL. |
63be0a78 | 283 | */ |
aa839030 | 284 | #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0) |
63be0a78 | 285 | |
63be0a78 | 286 | /// \ingroup CBDATAAPI |
aa839030 | 287 | #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN |
99f1f996 | 288 | #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 289 | |
290 | /** | |
63be0a78 | 291 | * Macro that defines a new cbdata datatype. Similar to a variable |
292 | * or struct definition. Scope is always local to the file/block | |
293 | * where it is defined and all calls to cbdataAlloc() for this type | |
294 | * must be within the same scope as the CBDATA_TYPE declaration. | |
295 | * Allocated entries may be referenced or freed anywhere with no | |
296 | * restrictions on scope. | |
5c2f68b7 | 297 | * \deprecated Use CBDATA_CLASS() instead |
63be0a78 | 298 | */ |
f53969cc | 299 | #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 300 | |
63be0a78 | 301 | /** |
302 | \ingroup CBDATAAPI | |
26ac0430 | 303 | * |
63be0a78 | 304 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
305 | * | |
306 | \par | |
b225f6b2 | 307 | * Alternative to CBDATA_INIT_TYPE() |
63be0a78 | 308 | * |
f53969cc SM |
309 | \param type Type being initialized |
310 | \param free_func The freehandler called when the last known reference to an allocated entry goes away. | |
63be0a78 | 311 | */ |
b225f6b2 | 312 | #define CBDATA_INIT_TYPE_FREECB(type, free_func) do { if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func); } while (false) |
63be0a78 | 313 | |
314 | /** | |
63be0a78 | 315 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
316 | * | |
317 | \par | |
b225f6b2 | 318 | * Alternative to CBDATA_INIT_TYPE_FREECB() |
63be0a78 | 319 | * |
f53969cc | 320 | \param type Type being initialized |
5c2f68b7 AJ |
321 | * |
322 | * \deprecated Use CBDATA_CLASS() instead | |
63be0a78 | 323 | */ |
f53969cc | 324 | #define CBDATA_INIT_TYPE(type) CBDATA_INIT_TYPE_FREECB(type, NULL) |
aa839030 | 325 | |
63be0a78 | 326 | /** |
327 | \ingroup CBDATA | |
328 | * | |
329 | * A generic wrapper for passing objects through cbdata. | |
330 | * Use this when you need to pass callback data to a blocking | |
aa839030 | 331 | * operation, but you don't want to/cannot have that pointer be cbdata itself. |
332 | */ | |
aa839030 | 333 | class generic_cbdata |
334 | { | |
5c2f68b7 AJ |
335 | CBDATA_CLASS(generic_cbdata); |
336 | ||
26ac0430 | 337 | public: |
63be0a78 | 338 | |
18ec8500 | 339 | generic_cbdata(void * aData) : data(aData) {} |
63be0a78 | 340 | |
26ac0430 AJ |
341 | template<typename wrapped_type>void unwrap(wrapped_type **output) { |
342 | *output = static_cast<wrapped_type *>(data); | |
343 | delete this; | |
344 | } | |
63be0a78 | 345 | |
bd6e2f16 | 346 | private: |
63be0a78 | 347 | /** |
348 | * The wrapped data - only public to allow the mild abuse of this facility | |
aa839030 | 349 | * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the |
350 | * object to be given to the callbacks. That needs to be fully cleaned up! | |
351 | * - RBC 20060820 | |
63be0a78 | 352 | \todo CODE: make this a private field. |
aa839030 | 353 | */ |
354 | void *data; /* the wrapped data */ | |
aa839030 | 355 | }; |
356 | ||
aa839030 | 357 | #endif /* SQUID_CBDATA_H */ |
f53969cc | 358 |