]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.h
Added some class documentation.
[thirdparty/squid.git] / src / cbdata.h
CommitLineData
aa839030 1/*
aa839030 2 *
3 * SQUID Web Proxy Cache http://www.squid-cache.org/
4 * ----------------------------------------------------------
5 *
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.
14 *
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.
26ac0430 19 *
aa839030 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.
26ac0430 24 *
aa839030 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.
28 *
29 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
30 */
31
32#ifndef SQUID_CBDATA_H
33#define SQUID_CBDATA_H
34
582c2af2 35#include "typedefs.h"
aa839030 36
63be0a78 37/**
38 \defgroup CBDATAAPI Callback Data Allocator API
39 \ingroup Components
40 \par
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.
46 *
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
50 * memory allocator.
51 *
52 \todo CODE: make cbdata a template or class-inheritance system instead of Macros.
53 *
54 \section Examples Examples
55 \par
56 * Here you can find some examples on how to use cbdata, and why.
57 *
58 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
59 \par
60 * For a asyncronous operation with callback functions, the normal
61 * sequence of events in programs NOT using cbdata is as follows:
62 *
63 \code
64 // initialization
65 type_of_data our_data;
66 ...
67 our_data = malloc(...);
68 ...
69 // Initiate a asyncronous operation, with our_data as callback_data
70 fooOperationStart(bar, callback_func, our_data);
71 ...
72 // The asyncronous operation completes and makes the callback
73 callback_func(callback_data, ....);
74 // Some time later we clean up our data
75 free(our_data);
76 \endcode
77 *
78 \par
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:
85 *
86 \code
87 // initialization
88 type_of_data our_data;
89 ...
90 our_data = malloc(...);
91 ...
92 // Initiate a asyncronous operation, with our_data as callback_data
93 fooOperationStart(bar, callback_func, our_data);
94 ...
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
99 // pending operation)
100 free(our_data);
101 ...
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
106 \endcode
107 *
108 \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata
109 *
110 \par
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:
117 *
118 \code
119 // initialization
120 type_of_data our_data;
121 ...
122 our_data = cbdataAlloc(type_of_data);
123 ...
124 // Initiate a asyncronous operation, with our_data as callback_data
125 fooOperationStart(..., callback_func, our_data);
126 ...
127 // foo
128 void *local_pointer = cbdataReference(callback_data);
129 ....
130 // The asyncronous operation completes and makes the callback
131 void *cbdata;
132 if (cbdataReferenceValidDone(local_pointer, &amp;cbdata))
133 callback_func(...., cbdata);
134 ...
135 cbdataFree(our_data);
136 \endcode
137 *
138 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
139 *
140 \par
141 * With this scheme, nothing bad happens if cbdataFree() gets called
142 * before fooOperantionComplete(...).
143 *
144 \par Initalization
145 \code
146 type_of_data our_data;
147 ...
148 our_data = cbdataAlloc(type_of_data);
149 \endcode
150 * Initiate a asyncronous operation, with our_data as callback_data
151 \code
152 fooOperationStart(..., callback_func, our_data);
153 \endcode
154 * do some stuff with it
155 \code
156 void *local_pointer = cbdataReference(callback_data);
157 \endcode
158 * something bad happened elsewhere.. cleanup
159 \code
160 cbdataFree(our_data);
161 \endcode
162 * The asyncronous operation completes and tries to make the callback
163 \code
164 void *cbdata;
165 if (cbdataReferenceValidDone(local_pointer, &amp;cbdata))
166 {
167 \endcode
168 * won't be called, as the data is no longer valid
169 \code
170 callback_func(...., cbdata);
171 }
172 \endcode
173 *
174 \par
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.
180 *
181 \subsection AddingCBDATAType Adding a new cbdata registered type
182 *
183 \par
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.
188 *
189 \par
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..
193 \code
194 CBDATA_TYPE(type_of_data);
195 \endcode
196 * Then in the code somewhere before the first allocation
197 * (can be called multiple times with only a minimal overhead)
198 \code
199 CBDATA_INIT_TYPE(type_of_data);
200 \endcode
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()
206 \code
207 CBDATA_INIT_TYPE_FREECB(type_of_data, free_function);
208 \endcode
209 *
210 \subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally
211 *
212 \par
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.
219 *
220 \code
221 extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF
222 \endcode
223 */
224
225/**
226 *\ingroup CBDATAAPI
aa839030 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
230 * are added runtime
231 */
232typedef enum {
ffb809be 233 CBDATA_UNKNOWN = 0
aa839030 234} cbdata_type;
235
63be0a78 236/// \ingroup CBDATAAPI
dbeed9ea 237extern void cbdataRegisterWithCacheManager(void);
63be0a78 238
9a0a18de 239#if USE_CBDATA_DEBUG
aa839030 240extern void *cbdataInternalAllocDbg(cbdata_type type, const char *, int);
241extern void *cbdataInternalFreeDbg(void *p, const char *, int);
242extern void cbdataInternalLockDbg(const void *p, const char *, int);
243extern void cbdataInternalUnlockDbg(const void *p, const char *, int);
244extern int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int);
245#else
63be0a78 246
247/// \ingroup CBDATAAPI
aa839030 248extern void *cbdataInternalAlloc(cbdata_type type);
63be0a78 249
250/// \ingroup CBDATAAPI
aa839030 251extern void *cbdataInternalFree(void *p);
63be0a78 252
253/// \ingroup CBDATAAPI
aa839030 254extern void cbdataInternalLock(const void *p);
63be0a78 255
256/// \ingroup CBDATAAPI
aa839030 257extern void cbdataInternalUnlock(const void *p);
63be0a78 258
259/// \ingroup CBDATAAPI
aa839030 260extern int cbdataInternalReferenceDoneValid(void **p, void **tp);
63be0a78 261
262#endif /* !CBDATA_DEBUG */
263
264/**
265 \ingroup CBDATAAPI
266 *
267 \param p A cbdata entry reference pointer.
268 *
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.
271 */
aa839030 272extern int cbdataReferenceValid(const void *p);
63be0a78 273
274/// \ingroup CBDATAAPI
aa839030 275extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
276
aa839030 277/* cbdata macros */
9a0a18de 278#if USE_CBDATA_DEBUG
aa839030 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) \
e5a06e13 285 private: \
aa839030 286 static cbdata_type CBDATA_##type; \
287 public: \
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__); \
292 } \
293 void operator delete (void *address) { \
294 if (address) cbdataInternalFreeDbg(address,__FILE__,__LINE__); \
295 } \
e5a06e13 296 void *toCbdata() { return this; }
9a0a18de 297#else /* USE_CBDATA_DEBUG */
63be0a78 298
299/**
300 \ingroup CBDATAAPI
301 * Allocates a new entry of a registered CBDATA type.
302 */
aa839030 303#define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type))
63be0a78 304
305/**
306 \ingroup CBDATAAPI
307 \par
308 * Frees a entry allocated by cbdataAlloc().
309 *
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.
313 */
aa839030 314#define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0)
63be0a78 315
316/**
317 \ingroup CBDATAAPI
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.
321 *
322 \code
323 void *cbdata;
324 ...
325 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
326 callback(..., cbdata);
327 \endcode
328 *
329 \param var The reference variable. Will be automatically cleared to NULL.
330 \param ptr A temporary pointer to the referenced data (if valid).
331 */
aa839030 332#define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
63be0a78 333
d2bf2f90
AJ
334/**
335 * \ingroup CBDATAAPI
f54f527e 336 *
d2bf2f90
AJ
337 * This needs to be defined LAST in teh class definition. It plays with private/public states in C++.
338 */
aa839030 339#define CBDATA_CLASS2(type) \
d2bf2f90 340 private: \
aa839030 341 static cbdata_type CBDATA_##type; \
342 public: \
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); \
347 } \
348 void operator delete (void *address) { \
349 if (address) cbdataInternalFree(address);\
350 } \
d2bf2f90 351 void *toCbdata() { return this; }
63be0a78 352#endif /* !CBDATA_DEBUG */
353
354/**
355 \ingroup CBDATAAPI
356 \par
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().
360 *
361 \param var
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 *".
366 */
aa839030 367#define cbdataReference(var) (cbdataInternalLock(var), var)
63be0a78 368
369/**
370 \ingroup CBDATAAPI
371 * Removes a reference created by cbdataReference().
372 *
373 \param var The reference variable. Will be automatically cleared to NULL.
374 */
aa839030 375#define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
63be0a78 376
377/// \ingroup CBDATAAPI
aa839030 378#define CBDATA_CLASS(type) static cbdata_type CBDATA_##type
63be0a78 379
380/// \ingroup CBDATAAPI
aa839030 381#define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
99f1f996 382#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
63be0a78 383
384/**
385 \ingroup CBDATAAPI
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.
392 */
aa839030 393#define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
63be0a78 394
395/**
396 \ingroup CBDATAAPI
397 * Defines a global cbdata type that can be referenced anywhere in the code.
398 *
399 \code
400 external CBDATA_GLOBAL_TYPE(datatype);
401 \endcode
402 * Should be added to the module *.h header file.
403 *
404 \code
405 CBDATA_GLOBAL_TYPE(datatype);
406 \endcode
407 *
408 * Should be added to the module main *.cc file.
409 */
aa839030 410#define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type
63be0a78 411
412/**
413 \ingroup CBDATAAPI
26ac0430 414 *
63be0a78 415 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
416 *
417 \par
418 * Alternative to CBDATA_INIT_TYPE_FREECB()
419 *
420 \param type Type being initialized
421 */
aa839030 422#define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
63be0a78 423
424/**
425 \ingroup CBDATAAPI
26ac0430 426 *
63be0a78 427 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
428 *
429 \par
430 * Alternative to CBDATA_INIT_TYPE()
431 *
432 \param type Type being initialized
433 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
434 */
aa839030 435#define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
436
63be0a78 437/**
438 \ingroup CBDATA
439 *
440 * A generic wrapper for passing objects through cbdata.
441 * Use this when you need to pass callback data to a blocking
aa839030 442 * operation, but you don't want to/cannot have that pointer be cbdata itself.
443 */
aa839030 444class generic_cbdata
445{
26ac0430 446public:
63be0a78 447
18ec8500 448 generic_cbdata(void * aData) : data(aData) {}
63be0a78 449
26ac0430
AJ
450 template<typename wrapped_type>void unwrap(wrapped_type **output) {
451 *output = static_cast<wrapped_type *>(data);
452 delete this;
453 }
63be0a78 454
455 /**
456 * The wrapped data - only public to allow the mild abuse of this facility
aa839030 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!
459 * - RBC 20060820
63be0a78 460 \todo CODE: make this a private field.
aa839030 461 */
462 void *data; /* the wrapped data */
d2bf2f90 463
26ac0430 464private:
aa839030 465 CBDATA_CLASS2(generic_cbdata);
466};
467
aa839030 468#endif /* SQUID_CBDATA_H */