]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.h
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 #ifndef SQUID_CBDATA_H
35 #define SQUID_CBDATA_H
40 \defgroup CBDATAAPI Callback Data Allocator API
43 * Squid's extensive use of callback functions makes it very
44 * susceptible to memory access errors. To address this all callback
45 * functions make use of a construct called cbdata. This allows
46 * functions doing callbacks to verify that the caller is still
47 * valid before making the callback.
49 \note cbdata is intended for callback data and is tailored specifically
50 * to make callbacks less dangerous leaving as few windows of errors as
51 * possible. It is not suitable or intended as a generic RefCount
54 \todo CODE: make cbdata a template or class-inheritance system instead of Macros.
56 \section Examples Examples
58 * Here you can find some examples on how to use cbdata, and why.
60 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
62 * For a asyncronous operation with callback functions, the normal
63 * sequence of events in programs NOT using cbdata is as follows:
67 type_of_data our_data;
69 our_data = malloc(...);
71 // Initiate a asyncronous operation, with our_data as callback_data
72 fooOperationStart(bar, callback_func, our_data);
74 // The asyncronous operation completes and makes the callback
75 callback_func(callback_data, ....);
76 // Some time later we clean up our data
81 * However, things become more interesting if we want or need
82 * to free the callback_data, or otherwise cancel the callback,
83 * before the operation completes. In constructs like this you
84 * can quite easily end up with having the memory referenced
85 * pointed to by callback_data freed before the callback is invoked
86 * causing a program failure or memory corruption:
90 type_of_data our_data;
92 our_data = malloc(...);
94 // Initiate a asyncronous operation, with our_data as callback_data
95 fooOperationStart(bar, callback_func, our_data);
97 // ouch, something bad happened elsewhere.. try to cleanup
98 // but the programmer forgot there is a callback pending from
99 // fooOperationsStart() (an easy thing to forget when writing code
100 // to deal with errors, especially if there may be many different
101 // pending operation)
104 // The asyncronous operation completes and makes the callback
105 callback_func(callback_data, ....);
106 // CRASH, the memory pointer to by callback_data is no longer valid
107 // at the time of the callback
110 \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata
113 * The callback data allocator lets us do this in a uniform and
114 * safe manner. The callback data allocator is used to allocate,
115 * track and free memory pool objects used during callback
116 * operations. Allocated memory is locked while the asyncronous
117 * operation executes elsewhere, and is freed when the operation
118 * completes. The normal sequence of events is:
122 type_of_data our_data;
124 our_data = cbdataAlloc(type_of_data);
126 // Initiate a asyncronous operation, with our_data as callback_data
127 fooOperationStart(..., callback_func, our_data);
130 void *local_pointer = cbdataReference(callback_data);
132 // The asyncronous operation completes and makes the callback
134 if (cbdataReferenceValidDone(local_pointer, &cbdata))
135 callback_func(...., cbdata);
137 cbdataFree(our_data);
140 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
143 * With this scheme, nothing bad happens if cbdataFree() gets called
144 * before fooOperantionComplete(...).
148 type_of_data our_data;
150 our_data = cbdataAlloc(type_of_data);
152 * Initiate a asyncronous operation, with our_data as callback_data
154 fooOperationStart(..., callback_func, our_data);
156 * do some stuff with it
158 void *local_pointer = cbdataReference(callback_data);
160 * something bad happened elsewhere.. cleanup
162 cbdataFree(our_data);
164 * The asyncronous operation completes and tries to make the callback
167 if (cbdataReferenceValidDone(local_pointer, &cbdata))
170 * won't be called, as the data is no longer valid
172 callback_func(...., cbdata);
177 * In this case, when cbdataFree() is called before
178 * cbdataReferenceValidDone(), the callback_data gets marked as invalid.
179 * When the callback_data is invalid before executing the callback
180 * function, cbdataReferenceValidDone() will return 0 and
181 * callback_func is never executed.
183 \subsection AddingCBDATAType Adding a new cbdata registered type
186 * To add new module specific data types to the allocator one uses the
187 * macros CBDATA_TYPE() and CBDATA_INIT_TYPE(). These creates a local cbdata
188 * definition (file or block scope). Any cbdataAlloc() calls must be made
189 * within this scope. However, cbdataFree() might be called from anywhere.
192 * First the cbdata type needs to be defined in the module. This
193 * is usually done at file scope, but it can also be local to a
194 * function or block..
196 CBDATA_TYPE(type_of_data);
198 * Then in the code somewhere before the first allocation
199 * (can be called multiple times with only a minimal overhead)
201 CBDATA_INIT_TYPE(type_of_data);
203 * Or if a free function is associated with the data type. This
204 * function is responsible for cleaning up any dependencies etc
205 * referenced by the structure and is called on cbdataFree() or
206 * when the last reference is deleted by cbdataReferenceDone() /
207 * cbdataReferenceValidDone()
209 CBDATA_INIT_TYPE_FREECB(type_of_data, free_function);
212 \subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally
215 * To add new global data types that can be allocated from anywhere
216 * within the code one have to add them to the cbdata_type enum in
217 * enums.h, and a corresponding CREATE_CBDATA() call in
218 * cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE()
219 * definition to globals.h as shown below and use CBDATA_INIT_TYPE() at
220 * the appropriate location(s) as described above.
223 extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF
229 * cbdata types. similar to the MEM_* types above, but managed
230 * in cbdata.c. A big difference is that these types are dynamically
231 * allocated. This list is only a list of predefined types. Other types
238 /// \ingroup CBDATAAPI
239 extern void cbdataRegisterWithCacheManager(void);
242 extern void *cbdataInternalAllocDbg(cbdata_type type
, const char *, int);
243 extern void *cbdataInternalFreeDbg(void *p
, const char *, int);
244 extern void cbdataInternalLockDbg(const void *p
, const char *, int);
245 extern void cbdataInternalUnlockDbg(const void *p
, const char *, int);
246 extern int cbdataInternalReferenceDoneValidDbg(void **p
, void **tp
, const char *, int);
249 /// \ingroup CBDATAAPI
250 extern void *cbdataInternalAlloc(cbdata_type type
);
252 /// \ingroup CBDATAAPI
253 extern void *cbdataInternalFree(void *p
);
255 /// \ingroup CBDATAAPI
256 extern void cbdataInternalLock(const void *p
);
258 /// \ingroup CBDATAAPI
259 extern void cbdataInternalUnlock(const void *p
);
261 /// \ingroup CBDATAAPI
262 extern int cbdataInternalReferenceDoneValid(void **p
, void **tp
);
264 #endif /* !CBDATA_DEBUG */
269 \param p A cbdata entry reference pointer.
271 \retval 0 A reference is stale. The pointer refers to a entry freed by cbdataFree().
272 \retval true The reference is valid and active.
274 extern int cbdataReferenceValid(const void *p
);
276 /// \ingroup CBDATAAPI
277 extern cbdata_type
cbdataInternalAddType(cbdata_type type
, const char *label
, int size
, FREE
* free_func
);
282 #define cbdataAlloc(type) ((type *)cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__))
283 #define cbdataFree(var) do {if (var) {cbdataInternalFreeDbg(var,__FILE__,__LINE__); var = NULL;}} while(0)
284 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
285 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
286 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
287 #define CBDATA_CLASS2(type) \
288 static cbdata_type CBDATA_##type; \
290 void *operator new(size_t size) { \
291 assert(size == sizeof(type)); \
292 (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \
293 return cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__); \
295 void operator delete (void *address) { \
296 if (address) cbdataInternalFreeDbg(address,__FILE__,__LINE__); \
298 void *toCbdata() { return this; } \
304 * Allocates a new entry of a registered CBDATA type.
306 #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type))
311 * Frees a entry allocated by cbdataAlloc().
313 \note If there are active references to the entry then the entry
314 * will be freed with the last reference is removed. However,
315 * cbdataReferenceValid() will return false for those references.
317 #define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0)
321 * Removes a reference created by cbdataReference() and checks
322 * it for validity. Meant to be used on the last dereference,
323 * usually to make a callback.
328 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
329 callback(..., cbdata);
332 \param var The reference variable. Will be automatically cleared to NULL.
333 \param ptr A temporary pointer to the referenced data (if valid).
335 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
337 /// \ingroup CBDATAAPI
338 #define CBDATA_CLASS2(type) \
339 static cbdata_type CBDATA_##type; \
341 void *operator new(size_t size) { \
342 assert(size == sizeof(type)); \
343 (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \
344 return (type *)cbdataInternalAlloc(CBDATA_##type); \
346 void operator delete (void *address) { \
347 if (address) cbdataInternalFree(address);\
349 void *toCbdata() { return this; } \
351 #endif /* !CBDATA_DEBUG */
356 * Creates a new reference to a cbdata entry. Used when you need to
357 * store a reference in another structure. The reference can later
358 * be verified for validity by cbdataReferenceValid().
361 * The reference variable is a pointer to the entry, in all
362 * aspects identical to the original pointer. But semantically it
363 * is quite different. It is best if the reference is thought of
364 * and handled as a "void *".
366 #define cbdataReference(var) (cbdataInternalLock(var), var)
370 * Removes a reference created by cbdataReference().
372 \param var The reference variable. Will be automatically cleared to NULL.
374 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
376 /// \ingroup CBDATAAPI
377 #define CBDATA_CLASS(type) static cbdata_type CBDATA_##type
379 /// \ingroup CBDATAAPI
380 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
381 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
385 * Macro that defines a new cbdata datatype. Similar to a variable
386 * or struct definition. Scope is always local to the file/block
387 * where it is defined and all calls to cbdataAlloc() for this type
388 * must be within the same scope as the CBDATA_TYPE declaration.
389 * Allocated entries may be referenced or freed anywhere with no
390 * restrictions on scope.
392 #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
396 * Defines a global cbdata type that can be referenced anywhere in the code.
399 external CBDATA_GLOBAL_TYPE(datatype);
401 * Should be added to the module *.h header file.
404 CBDATA_GLOBAL_TYPE(datatype);
407 * Should be added to the module main *.cc file.
409 #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type
414 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
417 * Alternative to CBDATA_INIT_TYPE_FREECB()
419 \param type Type being initialized
421 #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
426 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
429 * Alternative to CBDATA_INIT_TYPE()
431 \param type Type being initialized
432 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
434 #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
439 * A generic wrapper for passing objects through cbdata.
440 * Use this when you need to pass callback data to a blocking
441 * operation, but you don't want to/cannot have that pointer be cbdata itself.
447 generic_cbdata(void * data
) : data(data
) {}
449 template<typename wrapped_type
>void unwrap(wrapped_type
**output
) {
450 *output
= static_cast<wrapped_type
*>(data
);
455 * The wrapped data - only public to allow the mild abuse of this facility
456 * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the
457 * object to be given to the callbacks. That needs to be fully cleaned up!
459 \todo CODE: make this a private field.
461 void *data
; /* the wrapped data */
463 CBDATA_CLASS2(generic_cbdata
);
466 #endif /* SQUID_CBDATA_H */