]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.h
3 * SQUID Web Proxy Cache http://www.squid-cache.org/
4 * ----------------------------------------------------------
6 * Squid is the result of efforts by numerous individuals from
7 * the Internet community; see the CONTRIBUTORS file for full
8 * details. Many organizations have provided support for Squid's
9 * development; see the SPONSORS file for full details. Squid is
10 * Copyrighted (C) 2001 by the Regents of the University of
11 * California; see the COPYRIGHT file for full details. Squid
12 * incorporates software developed and/or copyrighted by other
13 * sources; see the CREDITS file for full details.
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
29 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
32 #ifndef SQUID_CBDATA_H
33 #define SQUID_CBDATA_H
38 \defgroup CBDATAAPI Callback Data Allocator API
41 * Squid's extensive use of callback functions makes it very
42 * susceptible to memory access errors. To address this all callback
43 * functions make use of a construct called cbdata. This allows
44 * functions doing callbacks to verify that the caller is still
45 * valid before making the callback.
47 \note cbdata is intended for callback data and is tailored specifically
48 * to make callbacks less dangerous leaving as few windows of errors as
49 * possible. It is not suitable or intended as a generic RefCount
52 \todo CODE: make cbdata a template or class-inheritance system instead of Macros.
54 \section Examples Examples
56 * Here you can find some examples on how to use cbdata, and why.
58 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
60 * For a asyncronous operation with callback functions, the normal
61 * sequence of events in programs NOT using cbdata is as follows:
65 type_of_data our_data;
67 our_data = malloc(...);
69 // Initiate a asyncronous operation, with our_data as callback_data
70 fooOperationStart(bar, callback_func, our_data);
72 // The asyncronous operation completes and makes the callback
73 callback_func(callback_data, ....);
74 // Some time later we clean up our data
79 * However, things become more interesting if we want or need
80 * to free the callback_data, or otherwise cancel the callback,
81 * before the operation completes. In constructs like this you
82 * can quite easily end up with having the memory referenced
83 * pointed to by callback_data freed before the callback is invoked
84 * causing a program failure or memory corruption:
88 type_of_data our_data;
90 our_data = malloc(...);
92 // Initiate a asyncronous operation, with our_data as callback_data
93 fooOperationStart(bar, callback_func, our_data);
95 // ouch, something bad happened elsewhere.. try to cleanup
96 // but the programmer forgot there is a callback pending from
97 // fooOperationsStart() (an easy thing to forget when writing code
98 // to deal with errors, especially if there may be many different
102 // The asyncronous operation completes and makes the callback
103 callback_func(callback_data, ....);
104 // CRASH, the memory pointer to by callback_data is no longer valid
105 // at the time of the callback
108 \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata
111 * The callback data allocator lets us do this in a uniform and
112 * safe manner. The callback data allocator is used to allocate,
113 * track and free memory pool objects used during callback
114 * operations. Allocated memory is locked while the asyncronous
115 * operation executes elsewhere, and is freed when the operation
116 * completes. The normal sequence of events is:
120 type_of_data our_data;
122 our_data = cbdataAlloc(type_of_data);
124 // Initiate a asyncronous operation, with our_data as callback_data
125 fooOperationStart(..., callback_func, our_data);
128 void *local_pointer = cbdataReference(callback_data);
130 // The asyncronous operation completes and makes the callback
132 if (cbdataReferenceValidDone(local_pointer, &cbdata))
133 callback_func(...., cbdata);
135 cbdataFree(our_data);
138 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
141 * With this scheme, nothing bad happens if cbdataFree() gets called
142 * before fooOperantionComplete(...).
146 type_of_data our_data;
148 our_data = cbdataAlloc(type_of_data);
150 * Initiate a asyncronous operation, with our_data as callback_data
152 fooOperationStart(..., callback_func, our_data);
154 * do some stuff with it
156 void *local_pointer = cbdataReference(callback_data);
158 * something bad happened elsewhere.. cleanup
160 cbdataFree(our_data);
162 * The asyncronous operation completes and tries to make the callback
165 if (cbdataReferenceValidDone(local_pointer, &cbdata))
168 * won't be called, as the data is no longer valid
170 callback_func(...., cbdata);
175 * In this case, when cbdataFree() is called before
176 * cbdataReferenceValidDone(), the callback_data gets marked as invalid.
177 * When the callback_data is invalid before executing the callback
178 * function, cbdataReferenceValidDone() will return 0 and
179 * callback_func is never executed.
181 \subsection AddingCBDATAType Adding a new cbdata registered type
184 * To add new module specific data types to the allocator one uses the
185 * macros CBDATA_TYPE() and CBDATA_INIT_TYPE(). These creates a local cbdata
186 * definition (file or block scope). Any cbdataAlloc() calls must be made
187 * within this scope. However, cbdataFree() might be called from anywhere.
190 * First the cbdata type needs to be defined in the module. This
191 * is usually done at file scope, but it can also be local to a
192 * function or block..
194 CBDATA_TYPE(type_of_data);
196 * Then in the code somewhere before the first allocation
197 * (can be called multiple times with only a minimal overhead)
199 CBDATA_INIT_TYPE(type_of_data);
201 * Or if a free function is associated with the data type. This
202 * function is responsible for cleaning up any dependencies etc
203 * referenced by the structure and is called on cbdataFree() or
204 * when the last reference is deleted by cbdataReferenceDone() /
205 * cbdataReferenceValidDone()
207 CBDATA_INIT_TYPE_FREECB(type_of_data, free_function);
210 \subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally
213 * To add new global data types that can be allocated from anywhere
214 * within the code one have to add them to the cbdata_type enum in
215 * enums.h, and a corresponding CREATE_CBDATA() call in
216 * cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE()
217 * definition to globals.h as shown below and use CBDATA_INIT_TYPE() at
218 * the appropriate location(s) as described above.
221 extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF
227 * cbdata types. similar to the MEM_* types above, but managed
228 * in cbdata.c. A big difference is that these types are dynamically
229 * allocated. This list is only a list of predefined types. Other types
236 /// \ingroup CBDATAAPI
237 void cbdataRegisterWithCacheManager(void);
240 void *cbdataInternalAllocDbg(cbdata_type type
, const char *, int);
241 void *cbdataInternalFreeDbg(void *p
, const char *, int);
242 void cbdataInternalLockDbg(const void *p
, const char *, int);
243 void cbdataInternalUnlockDbg(const void *p
, const char *, int);
244 int cbdataInternalReferenceDoneValidDbg(void **p
, void **tp
, const char *, int);
247 /// \ingroup CBDATAAPI
248 void *cbdataInternalAlloc(cbdata_type type
);
250 /// \ingroup CBDATAAPI
251 void *cbdataInternalFree(void *p
);
253 /// \ingroup CBDATAAPI
254 void cbdataInternalLock(const void *p
);
256 /// \ingroup CBDATAAPI
257 void cbdataInternalUnlock(const void *p
);
259 /// \ingroup CBDATAAPI
260 int cbdataInternalReferenceDoneValid(void **p
, void **tp
);
262 #endif /* !CBDATA_DEBUG */
267 \param p A cbdata entry reference pointer.
269 \retval 0 A reference is stale. The pointer refers to a entry freed by cbdataFree().
270 \retval true The reference is valid and active.
272 int cbdataReferenceValid(const void *p
);
274 /// \ingroup CBDATAAPI
275 cbdata_type
cbdataInternalAddType(cbdata_type type
, const char *label
, int size
, FREE
* free_func
);
279 #define cbdataAlloc(type) ((type *)cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__))
280 #define cbdataFree(var) do {if (var) {cbdataInternalFreeDbg(var,__FILE__,__LINE__); var = NULL;}} while(0)
281 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
282 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
283 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
284 #define CBDATA_CLASS2(type) \
286 static cbdata_type CBDATA_##type; \
288 void *operator new(size_t size) { \
289 assert(size == sizeof(type)); \
290 (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \
291 return cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__); \
293 void operator delete (void *address) { \
294 if (address) cbdataInternalFreeDbg(address,__FILE__,__LINE__); \
296 void *toCbdata() { return this; }
297 #else /* USE_CBDATA_DEBUG */
301 * Allocates a new entry of a registered CBDATA type.
303 #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type))
308 * Frees a entry allocated by cbdataAlloc().
310 \note If there are active references to the entry then the entry
311 * will be freed with the last reference is removed. However,
312 * cbdataReferenceValid() will return false for those references.
314 #define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0)
318 * Removes a reference created by cbdataReference() and checks
319 * it for validity. Meant to be used on the last dereference,
320 * usually to make a callback.
325 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
326 callback(..., cbdata);
329 \param var The reference variable. Will be automatically cleared to NULL.
330 \param ptr A temporary pointer to the referenced data (if valid).
332 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
337 * This needs to be defined LAST in teh class definition. It plays with private/public states in C++.
339 #define CBDATA_CLASS2(type) \
341 static cbdata_type CBDATA_##type; \
343 void *operator new(size_t size) { \
344 assert(size == sizeof(type)); \
345 (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \
346 return (type *)cbdataInternalAlloc(CBDATA_##type); \
348 void operator delete (void *address) { \
349 if (address) cbdataInternalFree(address);\
351 void *toCbdata() { return this; }
352 #endif /* !CBDATA_DEBUG */
357 * Creates a new reference to a cbdata entry. Used when you need to
358 * store a reference in another structure. The reference can later
359 * be verified for validity by cbdataReferenceValid().
362 * The reference variable is a pointer to the entry, in all
363 * aspects identical to the original pointer. But semantically it
364 * is quite different. It is best if the reference is thought of
365 * and handled as a "void *".
367 #define cbdataReference(var) (cbdataInternalLock(var), var)
371 * Removes a reference created by cbdataReference().
373 \param var The reference variable. Will be automatically cleared to NULL.
375 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
377 /// \ingroup CBDATAAPI
378 #define CBDATA_CLASS(type) static cbdata_type CBDATA_##type
380 /// \ingroup CBDATAAPI
381 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
382 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
386 * Macro that defines a new cbdata datatype. Similar to a variable
387 * or struct definition. Scope is always local to the file/block
388 * where it is defined and all calls to cbdataAlloc() for this type
389 * must be within the same scope as the CBDATA_TYPE declaration.
390 * Allocated entries may be referenced or freed anywhere with no
391 * restrictions on scope.
393 #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
397 * Defines a global cbdata type that can be referenced anywhere in the code.
400 external CBDATA_GLOBAL_TYPE(datatype);
402 * Should be added to the module *.h header file.
405 CBDATA_GLOBAL_TYPE(datatype);
408 * Should be added to the module main *.cc file.
410 #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type
415 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
418 * Alternative to CBDATA_INIT_TYPE_FREECB()
420 \param type Type being initialized
422 #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
427 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
430 * Alternative to CBDATA_INIT_TYPE()
432 \param type Type being initialized
433 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
435 #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
440 * A generic wrapper for passing objects through cbdata.
441 * Use this when you need to pass callback data to a blocking
442 * operation, but you don't want to/cannot have that pointer be cbdata itself.
448 generic_cbdata(void * aData
) : data(aData
) {}
450 template<typename wrapped_type
>void unwrap(wrapped_type
**output
) {
451 *output
= static_cast<wrapped_type
*>(data
);
456 * The wrapped data - only public to allow the mild abuse of this facility
457 * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the
458 * object to be given to the callbacks. That needs to be fully cleaned up!
460 \todo CODE: make this a private field.
462 void *data
; /* the wrapped data */
465 CBDATA_CLASS2(generic_cbdata
);
468 #endif /* SQUID_CBDATA_H */