]>
Commit | Line | Data |
---|---|---|
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, &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, &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 | */ | |
232 | typedef enum { | |
ffb809be | 233 | CBDATA_UNKNOWN = 0 |
aa839030 | 234 | } cbdata_type; |
235 | ||
63be0a78 | 236 | /// \ingroup CBDATAAPI |
8a648e8d | 237 | void cbdataRegisterWithCacheManager(void); |
63be0a78 | 238 | |
9a0a18de | 239 | #if USE_CBDATA_DEBUG |
8a648e8d FC |
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); | |
aa839030 | 245 | #else |
63be0a78 | 246 | |
247 | /// \ingroup CBDATAAPI | |
8a648e8d | 248 | void *cbdataInternalAlloc(cbdata_type type); |
63be0a78 | 249 | |
250 | /// \ingroup CBDATAAPI | |
8a648e8d | 251 | void *cbdataInternalFree(void *p); |
63be0a78 | 252 | |
253 | /// \ingroup CBDATAAPI | |
8a648e8d | 254 | void cbdataInternalLock(const void *p); |
63be0a78 | 255 | |
256 | /// \ingroup CBDATAAPI | |
8a648e8d | 257 | void cbdataInternalUnlock(const void *p); |
63be0a78 | 258 | |
259 | /// \ingroup CBDATAAPI | |
8a648e8d | 260 | 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 | */ | |
8a648e8d | 272 | int cbdataReferenceValid(const void *p); |
63be0a78 | 273 | |
274 | /// \ingroup CBDATAAPI | |
8a648e8d | 275 | cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func); |
aa839030 | 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 | |
63be0a78 | 377 | /// \ingroup CBDATAAPI |
aa839030 | 378 | #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN |
99f1f996 | 379 | #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 380 | |
381 | /** | |
382 | \ingroup CBDATAAPI | |
383 | * Macro that defines a new cbdata datatype. Similar to a variable | |
384 | * or struct definition. Scope is always local to the file/block | |
385 | * where it is defined and all calls to cbdataAlloc() for this type | |
386 | * must be within the same scope as the CBDATA_TYPE declaration. | |
387 | * Allocated entries may be referenced or freed anywhere with no | |
388 | * restrictions on scope. | |
389 | */ | |
aa839030 | 390 | #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN |
63be0a78 | 391 | |
392 | /** | |
393 | \ingroup CBDATAAPI | |
394 | * Defines a global cbdata type that can be referenced anywhere in the code. | |
395 | * | |
396 | \code | |
397 | external CBDATA_GLOBAL_TYPE(datatype); | |
398 | \endcode | |
399 | * Should be added to the module *.h header file. | |
400 | * | |
401 | \code | |
402 | CBDATA_GLOBAL_TYPE(datatype); | |
403 | \endcode | |
404 | * | |
405 | * Should be added to the module main *.cc file. | |
406 | */ | |
aa839030 | 407 | #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type |
63be0a78 | 408 | |
409 | /** | |
410 | \ingroup CBDATAAPI | |
26ac0430 | 411 | * |
63be0a78 | 412 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
413 | * | |
414 | \par | |
415 | * Alternative to CBDATA_INIT_TYPE_FREECB() | |
416 | * | |
417 | \param type Type being initialized | |
418 | */ | |
aa839030 | 419 | #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))) |
63be0a78 | 420 | |
421 | /** | |
422 | \ingroup CBDATAAPI | |
26ac0430 | 423 | * |
63be0a78 | 424 | * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. |
425 | * | |
426 | \par | |
427 | * Alternative to CBDATA_INIT_TYPE() | |
428 | * | |
429 | \param type Type being initialized | |
430 | \param free_func The freehandler called when the last known reference to an allocated entry goes away. | |
431 | */ | |
aa839030 | 432 | #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func))) |
433 | ||
63be0a78 | 434 | /** |
435 | \ingroup CBDATA | |
436 | * | |
437 | * A generic wrapper for passing objects through cbdata. | |
438 | * Use this when you need to pass callback data to a blocking | |
aa839030 | 439 | * operation, but you don't want to/cannot have that pointer be cbdata itself. |
440 | */ | |
aa839030 | 441 | class generic_cbdata |
442 | { | |
26ac0430 | 443 | public: |
63be0a78 | 444 | |
18ec8500 | 445 | generic_cbdata(void * aData) : data(aData) {} |
63be0a78 | 446 | |
26ac0430 AJ |
447 | template<typename wrapped_type>void unwrap(wrapped_type **output) { |
448 | *output = static_cast<wrapped_type *>(data); | |
449 | delete this; | |
450 | } | |
63be0a78 | 451 | |
452 | /** | |
453 | * The wrapped data - only public to allow the mild abuse of this facility | |
aa839030 | 454 | * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the |
455 | * object to be given to the callbacks. That needs to be fully cleaned up! | |
456 | * - RBC 20060820 | |
63be0a78 | 457 | \todo CODE: make this a private field. |
aa839030 | 458 | */ |
459 | void *data; /* the wrapped data */ | |
d2bf2f90 | 460 | |
26ac0430 | 461 | private: |
aa839030 | 462 | CBDATA_CLASS2(generic_cbdata); |
463 | }; | |
464 | ||
aa839030 | 465 | #endif /* SQUID_CBDATA_H */ |