]>
Commit | Line | Data |
---|---|---|
aa839030 | 1 | /* |
262a0e14 | 2 | * $Id$ |
aa839030 | 3 | * |
4 | * | |
5 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
6 | * ---------------------------------------------------------- | |
7 | * | |
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. | |
16 | * | |
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. | |
26ac0430 | 21 | * |
aa839030 | 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. | |
26ac0430 | 26 | * |
aa839030 | 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. | |
30 | * | |
31 | * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org> | |
32 | */ | |
33 | ||
34 | #ifndef SQUID_CBDATA_H | |
35 | #define SQUID_CBDATA_H | |
36 | ||
582c2af2 | 37 | #include "typedefs.h" |
aa839030 | 38 | |
63be0a78 | 39 | /** |
40 | \defgroup CBDATAAPI Callback Data Allocator API | |
41 | \ingroup Components | |
42 | \par | |
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. | |
48 | * | |
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 | |
52 | * memory allocator. | |
53 | * | |
54 | \todo CODE: make cbdata a template or class-inheritance system instead of Macros. | |
55 | * | |
56 | \section Examples Examples | |
57 | \par | |
58 | * Here you can find some examples on how to use cbdata, and why. | |
59 | * | |
60 | \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed | |
61 | \par | |
62 | * For a asyncronous operation with callback functions, the normal | |
63 | * sequence of events in programs NOT using cbdata is as follows: | |
64 | * | |
65 | \code | |
66 | // initialization | |
67 | type_of_data our_data; | |
68 | ... | |
69 | our_data = malloc(...); | |
70 | ... | |
71 | // Initiate a asyncronous operation, with our_data as callback_data | |
72 | fooOperationStart(bar, callback_func, our_data); | |
73 | ... | |
74 | // The asyncronous operation completes and makes the callback | |
75 | callback_func(callback_data, ....); | |
76 | // Some time later we clean up our data | |
77 | free(our_data); | |
78 | \endcode | |
79 | * | |
80 | \par | |
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: | |
87 | * | |
88 | \code | |
89 | // initialization | |
90 | type_of_data our_data; | |
91 | ... | |
92 | our_data = malloc(...); | |
93 | ... | |
94 | // Initiate a asyncronous operation, with our_data as callback_data | |
95 | fooOperationStart(bar, callback_func, our_data); | |
96 | ... | |
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) | |
102 | free(our_data); | |
103 | ... | |
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 | |
108 | \endcode | |
109 | * | |
110 | \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata | |
111 | * | |
112 | \par | |
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: | |
119 | * | |
120 | \code | |
121 | // initialization | |
122 | type_of_data our_data; | |
123 | ... | |
124 | our_data = cbdataAlloc(type_of_data); | |
125 | ... | |
126 | // Initiate a asyncronous operation, with our_data as callback_data | |
127 | fooOperationStart(..., callback_func, our_data); | |
128 | ... | |
129 | // foo | |
130 | void *local_pointer = cbdataReference(callback_data); | |
131 | .... | |
132 | // The asyncronous operation completes and makes the callback | |
133 | void *cbdata; | |
134 | if (cbdataReferenceValidDone(local_pointer, &cbdata)) | |
135 | callback_func(...., cbdata); | |
136 | ... | |
137 | cbdataFree(our_data); | |
138 | \endcode | |
139 | * | |
140 | \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata | |
141 | * | |
142 | \par | |
143 | * With this scheme, nothing bad happens if cbdataFree() gets called | |
144 | * before fooOperantionComplete(...). | |
145 | * | |
146 | \par Initalization | |
147 | \code | |
148 | type_of_data our_data; | |
149 | ... | |
150 | our_data = cbdataAlloc(type_of_data); | |
151 | \endcode | |
152 | * Initiate a asyncronous operation, with our_data as callback_data | |
153 | \code | |
154 | fooOperationStart(..., callback_func, our_data); | |
155 | \endcode | |
156 | * do some stuff with it | |
157 | \code | |
158 | void *local_pointer = cbdataReference(callback_data); | |
159 | \endcode | |
160 | * something bad happened elsewhere.. cleanup | |
161 | \code | |
162 | cbdataFree(our_data); | |
163 | \endcode | |
164 | * The asyncronous operation completes and tries to make the callback | |
165 | \code | |
166 | void *cbdata; | |
167 | if (cbdataReferenceValidDone(local_pointer, &cbdata)) | |
168 | { | |
169 | \endcode | |
170 | * won't be called, as the data is no longer valid | |
171 | \code | |
172 | callback_func(...., cbdata); | |
173 | } | |
174 | \endcode | |
175 | * | |
176 | \par | |
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. | |
182 | * | |
183 | \subsection AddingCBDATAType Adding a new cbdata registered type | |
184 | * | |
185 | \par | |
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. | |
190 | * | |
191 | \par | |
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.. | |
195 | \code | |
196 | CBDATA_TYPE(type_of_data); | |
197 | \endcode | |
198 | * Then in the code somewhere before the first allocation | |
199 | * (can be called multiple times with only a minimal overhead) | |
200 | \code | |
201 | CBDATA_INIT_TYPE(type_of_data); | |
202 | \endcode | |
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() | |
208 | \code | |
209 | CBDATA_INIT_TYPE_FREECB(type_of_data, free_function); | |
210 | \endcode | |
211 | * | |
212 | \subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally | |
213 | * | |
214 | \par | |
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. | |
221 | * | |
222 | \code | |
223 | extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF | |
224 | \endcode | |
225 | */ | |
226 | ||
227 | /** | |
228 | *\ingroup CBDATAAPI | |
aa839030 | 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 | |
232 | * are added runtime | |
233 | */ | |
234 | typedef enum { | |
ffb809be | 235 | CBDATA_UNKNOWN = 0 |
aa839030 | 236 | } cbdata_type; |
237 | ||
63be0a78 | 238 | /// \ingroup CBDATAAPI |
dbeed9ea | 239 | extern void cbdataRegisterWithCacheManager(void); |
63be0a78 | 240 | |
9a0a18de | 241 | #if USE_CBDATA_DEBUG |
aa839030 | 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); | |
247 | #else | |
63be0a78 | 248 | |
249 | /// \ingroup CBDATAAPI | |
aa839030 | 250 | extern void *cbdataInternalAlloc(cbdata_type type); |
63be0a78 | 251 | |
252 | /// \ingroup CBDATAAPI | |
aa839030 | 253 | extern void *cbdataInternalFree(void *p); |
63be0a78 | 254 | |
255 | /// \ingroup CBDATAAPI | |
aa839030 | 256 | extern void cbdataInternalLock(const void *p); |
63be0a78 | 257 | |
258 | /// \ingroup CBDATAAPI | |
aa839030 | 259 | extern void cbdataInternalUnlock(const void *p); |
63be0a78 | 260 | |
261 | /// \ingroup CBDATAAPI | |
aa839030 | 262 | extern int cbdataInternalReferenceDoneValid(void **p, void **tp); |
63be0a78 | 263 | |
264 | #endif /* !CBDATA_DEBUG */ | |
265 | ||
266 | /** | |
267 | \ingroup CBDATAAPI | |
268 | * | |
269 | \param p A cbdata entry reference pointer. | |
270 | * | |
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. | |
273 | */ | |
aa839030 | 274 | extern int cbdataReferenceValid(const void *p); |
63be0a78 | 275 | |
276 | /// \ingroup CBDATAAPI | |
aa839030 | 277 | extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func); |
278 | ||
279 | ||
280 | /* cbdata macros */ | |
9a0a18de | 281 | #if USE_CBDATA_DEBUG |
aa839030 | 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) \ | |
e5a06e13 | 288 | private: \ |
aa839030 | 289 | static cbdata_type CBDATA_##type; \ |
290 | public: \ | |
291 | void *operator new(size_t size) { \ | |
292 | assert(size == sizeof(type)); \ | |
293 | (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \ | |
294 | return cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__); \ | |
295 | } \ | |
296 | void operator delete (void *address) { \ | |
297 | if (address) cbdataInternalFreeDbg(address,__FILE__,__LINE__); \ | |
298 | } \ | |
e5a06e13 | 299 | void *toCbdata() { return this; } |
9a0a18de | 300 | #else /* USE_CBDATA_DEBUG */ |
63be0a78 | 301 | |
302 | /** | |
303 | \ingroup CBDATAAPI | |
304 | * Allocates a new entry of a registered CBDATA type. | |
305 | */ | |
aa839030 | 306 | #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type)) |
63be0a78 | 307 | |
308 | /** | |
309 | \ingroup CBDATAAPI | |
310 | \par | |
311 | * Frees a entry allocated by cbdataAlloc(). | |
312 | * | |
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. | |
316 | */ | |
aa839030 | 317 | #define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0) |
63be0a78 | 318 | |
319 | /** | |
320 | \ingroup CBDATAAPI | |
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. | |
324 | * | |
325 | \code | |
326 | void *cbdata; | |
327 | ... | |
328 | if (cbdataReferenceValidDone(reference, &cbdata)) != NULL) | |
329 | callback(..., cbdata); | |
330 | \endcode | |
331 | * | |
332 | \param var The reference variable. Will be automatically cleared to NULL. | |
333 | \param ptr A temporary pointer to the referenced data (if valid). | |
334 | */ | |
aa839030 | 335 | #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr)) |
63be0a78 | 336 | |
d2bf2f90 AJ |
337 | /** |
338 | * \ingroup CBDATAAPI | |
f54f527e | 339 | * |
d2bf2f90 AJ |
340 | * This needs to be defined LAST in teh class definition. It plays with private/public states in C++. |
341 | */ | |
aa839030 | 342 | #define CBDATA_CLASS2(type) \ |
d2bf2f90 | 343 | private: \ |
aa839030 | 344 | static cbdata_type CBDATA_##type; \ |
345 | public: \ | |
346 | void *operator new(size_t size) { \ | |
347 | assert(size == sizeof(type)); \ | |
348 | (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \ | |
349 | return (type *)cbdataInternalAlloc(CBDATA_##type); \ | |
350 | } \ | |
351 | void operator delete (void *address) { \ | |
352 | if (address) cbdataInternalFree(address);\ | |
353 | } \ | |
d2bf2f90 | 354 | void *toCbdata() { return this; } |
63be0a78 | 355 | #endif /* !CBDATA_DEBUG */ |
356 | ||
357 | /** | |
358 | \ingroup CBDATAAPI | |
359 | \par | |
360 | * Creates a new reference to a cbdata entry. Used when you need to | |
361 | * store a reference in another structure. The reference can later | |
362 | * be verified for validity by cbdataReferenceValid(). | |
363 | * | |
364 | \param var | |
365 | * The reference variable is a pointer to the entry, in all | |
366 | * aspects identical to the original pointer. But semantically it | |
367 | * is quite different. It is best if the reference is thought of | |
368 | * and handled as a "void *". | |
369 | */ | |
aa839030 | 370 | #define cbdataReference(var) (cbdataInternalLock(var), var) |
63be0a78 | 371 | |
372 | /** | |
373 | \ingroup CBDATAAPI | |
374 | * Removes a reference created by cbdataReference(). | |
375 | * | |
376 | \param var The reference variable. Will be automatically cleared to NULL. | |
377 | */ | |
aa839030 | 378 | #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0) |
63be0a78 | 379 | |
380 | /// \ingroup CBDATAAPI | |
aa839030 | 381 | #define CBDATA_CLASS(type) static cbdata_type CBDATA_##type |
63be0a78 | 382 | |
383 | /// \ingroup CBDATAAPI | |
aa839030 | 384 | #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN |
99f1f996 | 385 | #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 386 | |
387 | /** | |
388 | \ingroup CBDATAAPI | |
389 | * Macro that defines a new cbdata datatype. Similar to a variable | |
390 | * or struct definition. Scope is always local to the file/block | |
391 | * where it is defined and all calls to cbdataAlloc() for this type | |
392 | * must be within the same scope as the CBDATA_TYPE declaration. | |
393 | * Allocated entries may be referenced or freed anywhere with no | |
394 | * restrictions on scope. | |
395 | */ | |
aa839030 | 396 | #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 397 | |
398 | /** | |
399 | \ingroup CBDATAAPI | |
400 | * Defines a global cbdata type that can be referenced anywhere in the code. | |
401 | * | |
402 | \code | |
403 | external CBDATA_GLOBAL_TYPE(datatype); | |
404 | \endcode | |
405 | * Should be added to the module *.h header file. | |
406 | * | |
407 | \code | |
408 | CBDATA_GLOBAL_TYPE(datatype); | |
409 | \endcode | |
410 | * | |
411 | * Should be added to the module main *.cc file. | |
412 | */ | |
aa839030 | 413 | #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type |
63be0a78 | 414 | |
415 | /** | |
416 | \ingroup CBDATAAPI | |
26ac0430 | 417 | * |
63be0a78 | 418 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
419 | * | |
420 | \par | |
421 | * Alternative to CBDATA_INIT_TYPE_FREECB() | |
422 | * | |
423 | \param type Type being initialized | |
424 | */ | |
aa839030 | 425 | #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))) |
63be0a78 | 426 | |
427 | /** | |
428 | \ingroup CBDATAAPI | |
26ac0430 | 429 | * |
63be0a78 | 430 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
431 | * | |
432 | \par | |
433 | * Alternative to CBDATA_INIT_TYPE() | |
434 | * | |
435 | \param type Type being initialized | |
436 | \param free_func The freehandler called when the last known reference to an allocated entry goes away. | |
437 | */ | |
aa839030 | 438 | #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func))) |
439 | ||
63be0a78 | 440 | /** |
441 | \ingroup CBDATA | |
442 | * | |
443 | * A generic wrapper for passing objects through cbdata. | |
444 | * Use this when you need to pass callback data to a blocking | |
aa839030 | 445 | * operation, but you don't want to/cannot have that pointer be cbdata itself. |
446 | */ | |
aa839030 | 447 | class generic_cbdata |
448 | { | |
26ac0430 | 449 | public: |
63be0a78 | 450 | |
18ec8500 | 451 | generic_cbdata(void * aData) : data(aData) {} |
63be0a78 | 452 | |
26ac0430 AJ |
453 | template<typename wrapped_type>void unwrap(wrapped_type **output) { |
454 | *output = static_cast<wrapped_type *>(data); | |
455 | delete this; | |
456 | } | |
63be0a78 | 457 | |
458 | /** | |
459 | * The wrapped data - only public to allow the mild abuse of this facility | |
aa839030 | 460 | * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the |
461 | * object to be given to the callbacks. That needs to be fully cleaned up! | |
462 | * - RBC 20060820 | |
63be0a78 | 463 | \todo CODE: make this a private field. |
aa839030 | 464 | */ |
465 | void *data; /* the wrapped data */ | |
d2bf2f90 | 466 | |
26ac0430 | 467 | private: |
aa839030 | 468 | CBDATA_CLASS2(generic_cbdata); |
469 | }; | |
470 | ||
aa839030 | 471 | #endif /* SQUID_CBDATA_H */ |