2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
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.
10 #define SQUID_CBDATA_H
15 \defgroup CBDATAAPI Callback Data Allocator API
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.
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
30 \section Examples Examples
32 * Here you can find some examples on how to use cbdata, and why.
34 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
36 * For a asyncronous operation with callback functions, the normal
37 * sequence of events in programs NOT using cbdata is as follows:
41 type_of_data our_data;
43 our_data = malloc(...);
45 // Initiate a asyncronous operation, with our_data as callback_data
46 fooOperationStart(bar, callback_func, our_data);
48 // The asyncronous operation completes and makes the callback
49 callback_func(callback_data, ....);
50 // Some time later we clean up our data
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:
64 type_of_data our_data;
66 our_data = malloc(...);
68 // Initiate a asyncronous operation, with our_data as callback_data
69 fooOperationStart(bar, callback_func, our_data);
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
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
84 \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata
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:
96 type_of_data our_data;
98 our_data = cbdataAlloc(type_of_data);
100 // Initiate a asyncronous operation, with our_data as callback_data
101 fooOperationStart(..., callback_func, our_data);
104 void *local_pointer = cbdataReference(callback_data);
106 // The asyncronous operation completes and makes the callback
108 if (cbdataReferenceValidDone(local_pointer, &cbdata))
109 callback_func(...., cbdata);
111 cbdataFree(our_data);
114 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
117 * With this scheme, nothing bad happens if cbdataFree() gets called
118 * before fooOperantionComplete(...).
122 type_of_data our_data;
124 our_data = cbdataAlloc(type_of_data);
126 * Initiate a asyncronous operation, with our_data as callback_data
128 fooOperationStart(..., callback_func, our_data);
130 * do some stuff with it
132 void *local_pointer = cbdataReference(callback_data);
134 * something bad happened elsewhere.. cleanup
136 cbdataFree(our_data);
138 * The asyncronous operation completes and tries to make the callback
141 if (cbdataReferenceValidDone(local_pointer, &cbdata))
144 * won't be called, as the data is no longer valid
146 callback_func(...., cbdata);
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.
157 \subsection AddingCBDATAType Adding a new cbdata registered type
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()
162 * or CBDATA_NAMESPACED_CLASS_INIT() in the .cc file.
163 * This creates new(), delete() and toCbdata() methods
164 * definition in class scope. Any allocate calls must be made with
165 * new() and destruction with delete(), they may be called from anywhere.
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.
174 typedef int cbdata_type
;
175 static const cbdata_type CBDATA_UNKNOWN
= 0;
177 /// \ingroup CBDATAAPI
178 void cbdataRegisterWithCacheManager(void);
181 * Allocates a new entry of a registered CBDATA type.
182 * \deprecated use CBDATA_CLASS() instead
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__))
189 * Frees a entry allocated by cbdataAlloc().
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.
194 * \deprecated use CBDATA_CLASS() instead
196 void *cbdataInternalFree(void *p
, const char *, int);
197 /// \deprecated use CBDATA_CLASS() instead
198 #define cbdataFree(var) do {if (var) {cbdataInternalFree(var,__FILE__,__LINE__); var = NULL;}} while(0)
201 void cbdataInternalLockDbg(const void *p
, const char *, int);
202 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
204 void cbdataInternalUnlockDbg(const void *p
, const char *, int);
205 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
207 int cbdataInternalReferenceDoneValidDbg(void **p
, void **tp
, const char *, int);
208 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
211 void cbdataInternalLock(const void *p
);
212 void cbdataInternalUnlock(const void *p
);
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.
222 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
223 callback(..., cbdata);
226 \param var The reference variable. Will be automatically cleared to NULL.
227 \param ptr A temporary pointer to the referenced data (if valid).
229 int cbdataInternalReferenceDoneValid(void **p
, void **tp
);
230 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
232 #endif /* !CBDATA_DEBUG */
235 * \param p A cbdata entry reference pointer.
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.
240 int cbdataReferenceValid(const void *p
);
242 /// \ingroup CBDATAAPI
243 cbdata_type
cbdataInternalAddType(cbdata_type type
, const char *label
, int size
, FREE
* free_func
);
246 * This needs to be defined FIRST in the class definition.
247 * It plays with private/public states in C++.
249 #define CBDATA_CLASS(type) \
251 void *operator new(size_t size) { \
252 assert(size == sizeof(type)); \
253 if (!CBDATA_##type) \
254 CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL); \
255 return (type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__); \
257 void operator delete (void *address) { \
258 if (address) cbdataInternalFree(address,__FILE__,__LINE__);\
260 void *toCbdata() { return this; } \
262 static cbdata_type CBDATA_##type;
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().
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 *".
276 #define cbdataReference(var) (cbdataInternalLock(var), var)
280 * Removes a reference created by cbdataReference().
282 \param var The reference variable. Will be automatically cleared to NULL.
284 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
286 /// \ingroup CBDATAAPI
287 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
288 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
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.
297 * \deprecated Use CBDATA_CLASS() instead
299 #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
304 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
307 * Alternative to CBDATA_INIT_TYPE()
309 \param type Type being initialized
310 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
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)
315 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
318 * Alternative to CBDATA_INIT_TYPE_FREECB()
320 \param type Type being initialized
322 * \deprecated Use CBDATA_CLASS() instead
324 #define CBDATA_INIT_TYPE(type) CBDATA_INIT_TYPE_FREECB(type, NULL)
329 * A generic wrapper for passing objects through cbdata.
330 * Use this when you need to pass callback data to a blocking
331 * operation, but you don't want to/cannot have that pointer be cbdata itself.
335 CBDATA_CLASS(generic_cbdata
);
339 generic_cbdata(void * aData
) : data(aData
) {}
341 template<typename wrapped_type
>void unwrap(wrapped_type
**output
) {
342 *output
= static_cast<wrapped_type
*>(data
);
347 * The wrapped data - only public to allow the mild abuse of this facility
348 * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the
349 * object to be given to the callbacks. That needs to be fully cleaned up!
351 \todo CODE: make this a private field.
353 void *data
; /* the wrapped data */
356 #endif /* SQUID_CBDATA_H */