]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.h
SourceFormat Enforcement
[thirdparty/squid.git] / src / cbdata.h
1 /*
2 * $Id$
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.
21 *
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.
26 *
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
37 #include "typedefs.h"
38
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, &amp;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, &amp;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
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 {
235 CBDATA_UNKNOWN = 0
236 } cbdata_type;
237
238 /// \ingroup CBDATAAPI
239 extern void cbdataRegisterWithCacheManager(void);
240
241 #if USE_CBDATA_DEBUG
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
248
249 /// \ingroup CBDATAAPI
250 extern void *cbdataInternalAlloc(cbdata_type type);
251
252 /// \ingroup CBDATAAPI
253 extern void *cbdataInternalFree(void *p);
254
255 /// \ingroup CBDATAAPI
256 extern void cbdataInternalLock(const void *p);
257
258 /// \ingroup CBDATAAPI
259 extern void cbdataInternalUnlock(const void *p);
260
261 /// \ingroup CBDATAAPI
262 extern int cbdataInternalReferenceDoneValid(void **p, void **tp);
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 */
274 extern int cbdataReferenceValid(const void *p);
275
276 /// \ingroup CBDATAAPI
277 extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
278
279 /* cbdata macros */
280 #if USE_CBDATA_DEBUG
281 #define cbdataAlloc(type) ((type *)cbdataInternalAllocDbg(CBDATA_##type,__FILE__,__LINE__))
282 #define cbdataFree(var) do {if (var) {cbdataInternalFreeDbg(var,__FILE__,__LINE__); var = NULL;}} while(0)
283 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
284 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
285 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
286 #define CBDATA_CLASS2(type) \
287 private: \
288 static cbdata_type CBDATA_##type; \
289 public: \
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__); \
294 } \
295 void operator delete (void *address) { \
296 if (address) cbdataInternalFreeDbg(address,__FILE__,__LINE__); \
297 } \
298 void *toCbdata() { return this; }
299 #else /* USE_CBDATA_DEBUG */
300
301 /**
302 \ingroup CBDATAAPI
303 * Allocates a new entry of a registered CBDATA type.
304 */
305 #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type))
306
307 /**
308 \ingroup CBDATAAPI
309 \par
310 * Frees a entry allocated by cbdataAlloc().
311 *
312 \note If there are active references to the entry then the entry
313 * will be freed with the last reference is removed. However,
314 * cbdataReferenceValid() will return false for those references.
315 */
316 #define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0)
317
318 /**
319 \ingroup CBDATAAPI
320 * Removes a reference created by cbdataReference() and checks
321 * it for validity. Meant to be used on the last dereference,
322 * usually to make a callback.
323 *
324 \code
325 void *cbdata;
326 ...
327 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
328 callback(..., cbdata);
329 \endcode
330 *
331 \param var The reference variable. Will be automatically cleared to NULL.
332 \param ptr A temporary pointer to the referenced data (if valid).
333 */
334 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
335
336 /**
337 * \ingroup CBDATAAPI
338 *
339 * This needs to be defined LAST in teh class definition. It plays with private/public states in C++.
340 */
341 #define CBDATA_CLASS2(type) \
342 private: \
343 static cbdata_type CBDATA_##type; \
344 public: \
345 void *operator new(size_t size) { \
346 assert(size == sizeof(type)); \
347 (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))); \
348 return (type *)cbdataInternalAlloc(CBDATA_##type); \
349 } \
350 void operator delete (void *address) { \
351 if (address) cbdataInternalFree(address);\
352 } \
353 void *toCbdata() { return this; }
354 #endif /* !CBDATA_DEBUG */
355
356 /**
357 \ingroup CBDATAAPI
358 \par
359 * Creates a new reference to a cbdata entry. Used when you need to
360 * store a reference in another structure. The reference can later
361 * be verified for validity by cbdataReferenceValid().
362 *
363 \param var
364 * The reference variable is a pointer to the entry, in all
365 * aspects identical to the original pointer. But semantically it
366 * is quite different. It is best if the reference is thought of
367 * and handled as a "void *".
368 */
369 #define cbdataReference(var) (cbdataInternalLock(var), var)
370
371 /**
372 \ingroup CBDATAAPI
373 * Removes a reference created by cbdataReference().
374 *
375 \param var The reference variable. Will be automatically cleared to NULL.
376 */
377 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
378
379 /// \ingroup CBDATAAPI
380 #define CBDATA_CLASS(type) static cbdata_type CBDATA_##type
381
382 /// \ingroup CBDATAAPI
383 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
384 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
385
386 /**
387 \ingroup CBDATAAPI
388 * Macro that defines a new cbdata datatype. Similar to a variable
389 * or struct definition. Scope is always local to the file/block
390 * where it is defined and all calls to cbdataAlloc() for this type
391 * must be within the same scope as the CBDATA_TYPE declaration.
392 * Allocated entries may be referenced or freed anywhere with no
393 * restrictions on scope.
394 */
395 #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
396
397 /**
398 \ingroup CBDATAAPI
399 * Defines a global cbdata type that can be referenced anywhere in the code.
400 *
401 \code
402 external CBDATA_GLOBAL_TYPE(datatype);
403 \endcode
404 * Should be added to the module *.h header file.
405 *
406 \code
407 CBDATA_GLOBAL_TYPE(datatype);
408 \endcode
409 *
410 * Should be added to the module main *.cc file.
411 */
412 #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type
413
414 /**
415 \ingroup CBDATAAPI
416 *
417 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
418 *
419 \par
420 * Alternative to CBDATA_INIT_TYPE_FREECB()
421 *
422 \param type Type being initialized
423 */
424 #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
425
426 /**
427 \ingroup CBDATAAPI
428 *
429 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
430 *
431 \par
432 * Alternative to CBDATA_INIT_TYPE()
433 *
434 \param type Type being initialized
435 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
436 */
437 #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
438
439 /**
440 \ingroup CBDATA
441 *
442 * A generic wrapper for passing objects through cbdata.
443 * Use this when you need to pass callback data to a blocking
444 * operation, but you don't want to/cannot have that pointer be cbdata itself.
445 */
446 class generic_cbdata
447 {
448 public:
449
450 generic_cbdata(void * aData) : data(aData) {}
451
452 template<typename wrapped_type>void unwrap(wrapped_type **output) {
453 *output = static_cast<wrapped_type *>(data);
454 delete this;
455 }
456
457 /**
458 * The wrapped data - only public to allow the mild abuse of this facility
459 * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the
460 * object to be given to the callbacks. That needs to be fully cleaned up!
461 * - RBC 20060820
462 \todo CODE: make this a private field.
463 */
464 void *data; /* the wrapped data */
465
466 private:
467 CBDATA_CLASS2(generic_cbdata);
468 };
469
470 #endif /* SQUID_CBDATA_H */