--------------------- PatchSet 5219 Date: 2007/08/09 13:05:34 Author: amosjeffries Branch: docs Tag: (none) Log: Migrate documentation of CBDATA into source files. Members: doc/Programming-Guide/23_CallbackDataAllocator.dox:1.1.2.3->1.1.2.4(DEAD) src/cbdata.h:1.1->1.1.22.1 src/clientStream.cc:1.11.2.1->1.11.2.2 --- squid3/doc/Programming-Guide/23_CallbackDataAllocator.dox Sat Aug 11 00:21:15 2007 +++ /dev/null Sat Aug 11 00:21:15 2007 @@ -1,311 +0,0 @@ -/** -\page 23_CallbackDataAllocator Callback Data Allocator - -\par - Squid's extensive use of callback functions makes it very - susceptible to memory access errors. To address this all callback - functions make use of a construct called "cbdata". This allows - functions doing callbacks to verify that the caller is still - valid before making the callback. - -\par - Note: cbdata is intended for callback data and is tailored specifically - to make callbacks less dangerous leaving as few windows of errors as - possible. It is not suitable or intended as a generic referencecounted - memory allocator. - -\section API API - -\subsection CBDATA_TYPE CBDATA_TYPE -\code - CBDATA_TYPE(datatype); -\endcode - -\par - Macro that defines a new cbdata datatype. Similar to a variable - or struct definition. Scope is always local to the file/block - where it is defined and all calls to cbdataAlloc for this type - must be within the same scope as the CBDATA_TYPE declaration. - Allocated entries may be referenced or freed anywhere with no - restrictions on scope. - -\subsection CBDATA_GLOBAL_TYPE CBDATA_GLOBAL_TYPE -\code - // Module header file - external CBDATA_GLOBAL_TYPE(datatype); - - // Module main C file - CBDATA_GLOBAL_TYPE(datatype); -\endcode - -\par - Defines a global cbdata type that can be referenced anywhere in - the code. - -\subsection CBDATA_INIT_TYPE CBDATA_INIT_TYPE -\code - CBDATA_INIT_TYPE(datatype); - // or - CBDATA_INIT_TYPE_FREECB(datatype, FREE *freehandler); -\endcode - -\par - Initializes the cbdatatype. Must be called prior to the first use of - cbdataAlloc() for the type. - -\par - The freehandler is called when the last known reference to a - allocated entry goes away. - -\subsection cbdataAlloc cbdataAlloc -\code - pointer = cbdataAlloc(datatype); -\endcode - -\par - Allocates a new entry of a registered cbdata type. - -\subsection cbdataFree cbdataFree -\code - cbdataFree(pointer); -\endcode - -\par - Frees a entry allocated by cbdataAlloc(). - -\note If there are active references to the entry then the entry - will be freed with the last reference is removed. However, - cbdataReferenceValid() will return false for those references. - -\subsection cbdataReference cbdataReference -\code - reference = cbdataReference(pointer); -\endcode - -\par - Creates a new reference to a cbdata entry. Used when you need to - store a reference in another structure. The reference can later - be verified for validity by cbdataReferenceValid(). - -\note The reference variable is a pointer to the entry, in all - aspects identical to the original pointer. But semantically it - is quite different. It is best if the reference is thought of - and handled as a "void *". - -\subsection cbdataReferenceDone cbdataReferenceDone -\code - cbdataReferenceDone(reference); -\endcode - -\par - Removes a reference created by cbdataReference(). - -\note The reference variable will be automatically cleared to NULL. - -\subsection cbdataReferenceValid cbdataReferenceValid -\code - if (cbdataReferenceValid(reference)) { - ... - } -\endcode - -\par - cbdataReferenceValid() returns false if a reference is stale (refers to a - entry freed by cbdataFree). - -\subsection cbdataReferenceValidDone cbdataReferenceValidDone -\code - void *pointer; - bool cbdataReferenceValidDone(reference, &pointer); -\endcode - -\par - Removes a reference created by cbdataReference() and checks - it for validity. A temporary pointer to the referenced data - (if valid) is returned in the &pointer argument. - -\par - Meant to be used on the last dereference, usually to make - a callback. - -\code - void *cbdata; - ... - if (cbdataReferenceValidDone(reference, &cbdata)) != NULL) - callback(..., cbdata); -\endcode - -\note The reference variable will be automatically cleared to NULL. - -\section Examples Examples -\par - Here you can find some examples on how to use cbdata, and why - -\subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed -\par - For a asyncronous operation with callback functions, the normal - sequence of events in programs NOT using cbdata is as follows: - -\code - // initialization - type_of_data our_data; - ... - our_data = malloc(...); - ... - // Initiate a asyncronous operation, with our_data as callback_data - fooOperationStart(bar, callback_func, our_data); - ... - // The asyncronous operation completes and makes the callback - callback_func(callback_data, ....); - // Some time later we clean up our data - free(our_data); -\endcode - -\par - However, things become more interesting if we want or need - to free the callback_data, or otherwise cancel the callback, - before the operation completes. In constructs like this you - can quite easily end up with having the memory referenced - pointed to by callback_data freed before the callback is invoked - causing a program failure or memory corruption: - -\code - // initialization - type_of_data our_data; - ... - our_data = malloc(...); - ... - // Initiate a asyncronous operation, with our_data as callback_data - fooOperationStart(bar, callback_func, our_data); - ... - // ouch, something bad happened elsewhere.. try to cleanup - // but the programmer forgot there is a callback pending from - // fooOperationsStart() (an easy thing to forget when writing code - // to deal with errors, especially if there may be many different - // pending operation) - free(our_data); - ... - // The asyncronous operation completes and makes the callback - callback_func(callback_data, ....); - // CRASH, the memory pointer to by callback_data is no longer valid - // at the time of the callback -\endcode - -\subsection AsyncOpWithCBDATA Asyncronous operation with cbdata - -\par - The callback data allocator lets us do this in a uniform and - safe manner. The callback data allocator is used to allocate, - track and free memory pool objects used during callback - operations. Allocated memory is locked while the asyncronous - operation executes elsewhere, and is freed when the operation - completes. The normal sequence of events is: - -\code - // initialization - type_of_data our_data; - ... - our_data = cbdataAlloc(type_of_data); - ... - // Initiate a asyncronous operation, with our_data as callback_data - fooOperationStart(..., callback_func, our_data); - ... - // foo - void *local_pointer = cbdataReference(callback_data); - .... - // The asyncronous operation completes and makes the callback - void *cbdata; - if (cbdataReferenceValidDone(local_pointer, &cbdata)) - callback_func(...., cbdata); - ... - cbdataFree(our_data); -\endcode - -\subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata - -\par - With this scheme, nothing bad happens if cbdataFree gets called - before fooOperantionComplete(...). - -\par - Initalization -\code - type_of_data our_data; - ... - our_data = cbdataAlloc(type_of_data); -\endcode - Initiate a asyncronous operation, with our_data as callback_data -\code - fooOperationStart(..., callback_func, our_data); -\endcode - do some stuff with it -\code - void *local_pointer = cbdataReference(callback_data); -\endcode - something bad happened elsewhere.. cleanup -\code - cbdataFree(our_data); -\endcode - The asyncronous operation completes and tries to make the callback -\code - void *cbdata; - if (cbdataReferenceValidDone(local_pointer, &cbdata)) - { -\endcode - won't be called, as the data is no longer valid -\code - callback_func(...., cbdata); - } -\endcode - -\par - In this case, when cbdataFree is called before - cbdataReferenceValidDone, the callback_data gets marked as invalid. - When the callback_data is invalid before executing the callback - function, cbdataReferenceValidDone will return 0 and - callback_func is never executed. - -\subsection AddingCBDATAType Adding a new cbdata registered type - -\par - To add new module specific data types to the allocator one uses the - macros CBDATA_TYPE and CBDATA_INIT_TYPE. These creates a local cbdata - definition (file or block scope). Any cbdataAlloc calls must be made - within this scope. However, cbdataFree might be called from anywhere. - -\par - First the cbdata type needs to be defined in the module. This - is usually done at file scope, but it can also be local to a - function or block.. -\code - CBDATA_TYPE(type_of_data); -\endcode - Then in the code somewhere before the first allocation - (can be called multiple times with only a minimal overhead) -\code - CBDATA_INIT_TYPE(type_of_data); -\endcode - Or if a free function is associated with the data type. This - function is responsible for cleaning up any dependencies etc - referenced by the structure and is called on cbdataFree or - when the last reference is deleted by cbdataReferenceDone / - cbdataReferenceValidDone -\code - CBDATA_INIT_TYPE_FREECB(type_of_data, free_function); -\endcode - -\subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally - -\par - To add new global data types that can be allocated from anywhere - within the code one have to add them to the cbdata_type enum in - enums.h, and a corresponding CREATE_CBDATA call in - cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE - definition to globals.h as shown below and use CBDATA_INIT_TYPE at - the appropriate location(s) as described above. - -\code - extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF -\endcode - - */ Index: squid3/src/cbdata.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/cbdata.h,v retrieving revision 1.1 retrieving revision 1.1.22.1 diff -u -r1.1 -r1.1.22.1 --- squid3/src/cbdata.h 21 Aug 2006 01:51:49 -0000 1.1 +++ squid3/src/cbdata.h 9 Aug 2007 13:05:34 -0000 1.1.22.1 @@ -1,6 +1,5 @@ - /* - * $Id: cbdata.h,v 1.1 2006/08/21 01:51:49 squidadm Exp $ + * $Id: cbdata.h,v 1.1.22.1 2007/08/09 13:05:34 amosjeffries Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -37,7 +36,195 @@ #include "squid.h" -/* +/** + \defgroup CBDATAAPI Callback Data Allocator + \par + * Squid's extensive use of callback functions makes it very + * susceptible to memory access errors. To address this all callback + * functions make use of a construct called cbdata. This allows + * functions doing callbacks to verify that the caller is still + * valid before making the callback. + * + \note cbdata is intended for callback data and is tailored specifically + * to make callbacks less dangerous leaving as few windows of errors as + * possible. It is not suitable or intended as a generic RefCounted + * memory allocator. + * + \todo CODE: make cbdata a template or class-inheritance system instead of Macros. + * + \section Examples Examples + \par + * Here you can find some examples on how to use cbdata, and why. + * + \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed + \par + * For a asyncronous operation with callback functions, the normal + * sequence of events in programs NOT using cbdata is as follows: + * + \code + // initialization + type_of_data our_data; + ... + our_data = malloc(...); + ... + // Initiate a asyncronous operation, with our_data as callback_data + fooOperationStart(bar, callback_func, our_data); + ... + // The asyncronous operation completes and makes the callback + callback_func(callback_data, ....); + // Some time later we clean up our data + free(our_data); + \endcode + * + \par + * However, things become more interesting if we want or need + * to free the callback_data, or otherwise cancel the callback, + * before the operation completes. In constructs like this you + * can quite easily end up with having the memory referenced + * pointed to by callback_data freed before the callback is invoked + * causing a program failure or memory corruption: + * + \code + // initialization + type_of_data our_data; + ... + our_data = malloc(...); + ... + // Initiate a asyncronous operation, with our_data as callback_data + fooOperationStart(bar, callback_func, our_data); + ... + // ouch, something bad happened elsewhere.. try to cleanup + // but the programmer forgot there is a callback pending from + // fooOperationsStart() (an easy thing to forget when writing code + // to deal with errors, especially if there may be many different + // pending operation) + free(our_data); + ... + // The asyncronous operation completes and makes the callback + callback_func(callback_data, ....); + // CRASH, the memory pointer to by callback_data is no longer valid + // at the time of the callback + \endcode + * + \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata + * + \par + * The callback data allocator lets us do this in a uniform and + * safe manner. The callback data allocator is used to allocate, + * track and free memory pool objects used during callback + * operations. Allocated memory is locked while the asyncronous + * operation executes elsewhere, and is freed when the operation + * completes. The normal sequence of events is: + * + \code + // initialization + type_of_data our_data; + ... + our_data = cbdataAlloc(type_of_data); + ... + // Initiate a asyncronous operation, with our_data as callback_data + fooOperationStart(..., callback_func, our_data); + ... + // foo + void *local_pointer = cbdataReference(callback_data); + .... + // The asyncronous operation completes and makes the callback + void *cbdata; + if (cbdataReferenceValidDone(local_pointer, &cbdata)) + callback_func(...., cbdata); + ... + cbdataFree(our_data); + \endcode + * + \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata + * + \par + * With this scheme, nothing bad happens if cbdataFree() gets called + * before fooOperantionComplete(...). + * + \par Initalization + \code + type_of_data our_data; + ... + our_data = cbdataAlloc(type_of_data); + \endcode + * Initiate a asyncronous operation, with our_data as callback_data + \code + fooOperationStart(..., callback_func, our_data); + \endcode + * do some stuff with it + \code + void *local_pointer = cbdataReference(callback_data); + \endcode + * something bad happened elsewhere.. cleanup + \code + cbdataFree(our_data); + \endcode + * The asyncronous operation completes and tries to make the callback + \code + void *cbdata; + if (cbdataReferenceValidDone(local_pointer, &cbdata)) + { + \endcode + * won't be called, as the data is no longer valid + \code + callback_func(...., cbdata); + } + \endcode + * + \par + * In this case, when cbdataFree() is called before + * cbdataReferenceValidDone(), the callback_data gets marked as invalid. + * When the callback_data is invalid before executing the callback + * function, cbdataReferenceValidDone() will return 0 and + * callback_func is never executed. + * + \subsection AddingCBDATAType Adding a new cbdata registered type + * + \par + * To add new module specific data types to the allocator one uses the + * macros CBDATA_TYPE() and CBDATA_INIT_TYPE(). These creates a local cbdata + * definition (file or block scope). Any cbdataAlloc() calls must be made + * within this scope. However, cbdataFree() might be called from anywhere. + * + \par + * First the cbdata type needs to be defined in the module. This + * is usually done at file scope, but it can also be local to a + * function or block.. + \code + CBDATA_TYPE(type_of_data); + \endcode + * Then in the code somewhere before the first allocation + * (can be called multiple times with only a minimal overhead) + \code + CBDATA_INIT_TYPE(type_of_data); + \endcode + * Or if a free function is associated with the data type. This + * function is responsible for cleaning up any dependencies etc + * referenced by the structure and is called on cbdataFree() or + * when the last reference is deleted by cbdataReferenceDone() / + * cbdataReferenceValidDone() + \code + CBDATA_INIT_TYPE_FREECB(type_of_data, free_function); + \endcode + * + \subsection AddingGlobalCBDATATypes Adding a new cbdata registered data type globally + * + \par + * To add new global data types that can be allocated from anywhere + * within the code one have to add them to the cbdata_type enum in + * enums.h, and a corresponding CREATE_CBDATA() call in + * cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE() + * definition to globals.h as shown below and use CBDATA_INIT_TYPE() at + * the appropriate location(s) as described above. + * + \code + extern CBDATA_GLOBAL_TYPE(type_of_data); // CBDATA_UNDEF + \endcode + */ + +/** + *\ingroup CBDATAAPI * cbdata types. similar to the MEM_* types above, but managed * in cbdata.c. A big difference is that these types are dynamically * allocated. This list is only a list of predefined types. Other types @@ -47,7 +234,9 @@ CBDATA_UNKNOWN = 0, } cbdata_type; +/// \ingroup CBDATAAPI extern void cbdataRegisterWithCacheManager(CacheManager & manager); + #if CBDATA_DEBUG extern void *cbdataInternalAllocDbg(cbdata_type type, const char *, int); extern void *cbdataInternalFreeDbg(void *p, const char *, int); @@ -55,13 +244,35 @@ extern void cbdataInternalUnlockDbg(const void *p, const char *, int); extern int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int); #else + +/// \ingroup CBDATAAPI extern void *cbdataInternalAlloc(cbdata_type type); + +/// \ingroup CBDATAAPI extern void *cbdataInternalFree(void *p); + +/// \ingroup CBDATAAPI extern void cbdataInternalLock(const void *p); + +/// \ingroup CBDATAAPI extern void cbdataInternalUnlock(const void *p); + +/// \ingroup CBDATAAPI extern int cbdataInternalReferenceDoneValid(void **p, void **tp); -#endif + +#endif /* !CBDATA_DEBUG */ + +/** + \ingroup CBDATAAPI + * + \param p A cbdata entry reference pointer. + * + \retval 0 A reference is stale. The pointer refers to a entry freed by cbdataFree(). + \retval true The reference is valid and active. + */ extern int cbdataReferenceValid(const void *p); + +/// \ingroup CBDATAAPI extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func); @@ -85,9 +296,43 @@ } \ private: #else + +/** + \ingroup CBDATAAPI + * Allocates a new entry of a registered CBDATA type. + */ #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type)) + +/** + \ingroup CBDATAAPI + \par + * Frees a entry allocated by cbdataAlloc(). + * + \note If there are active references to the entry then the entry + * will be freed with the last reference is removed. However, + * cbdataReferenceValid() will return false for those references. + */ #define cbdataFree(var) do {if (var) {cbdataInternalFree(var); var = NULL;}} while(0) + +/** + \ingroup CBDATAAPI + * Removes a reference created by cbdataReference() and checks + * it for validity. Meant to be used on the last dereference, + * usually to make a callback. + * + \code + void *cbdata; + ... + if (cbdataReferenceValidDone(reference, &cbdata)) != NULL) + callback(..., cbdata); + \endcode + * + \param var The reference variable. Will be automatically cleared to NULL. + \param ptr A temporary pointer to the referenced data (if valid). + */ #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr)) + +/// \ingroup CBDATAAPI #define CBDATA_CLASS2(type) \ static cbdata_type CBDATA_##type; \ public: \ @@ -100,40 +345,119 @@ if (address) cbdataInternalFree(address);\ } \ private: -#endif +#endif /* !CBDATA_DEBUG */ + +/** + \ingroup CBDATAAPI + \par + * Creates a new reference to a cbdata entry. Used when you need to + * store a reference in another structure. The reference can later + * be verified for validity by cbdataReferenceValid(). + * + \param var + * The reference variable is a pointer to the entry, in all + * aspects identical to the original pointer. But semantically it + * is quite different. It is best if the reference is thought of + * and handled as a "void *". + */ #define cbdataReference(var) (cbdataInternalLock(var), var) + +/** + \ingroup CBDATAAPI + * Removes a reference created by cbdataReference(). + * + \param var The reference variable. Will be automatically cleared to NULL. + */ #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0) + +/// \ingroup CBDATAAPI #define CBDATA_CLASS(type) static cbdata_type CBDATA_##type + +/// \ingroup CBDATAAPI #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN + +/** + \ingroup CBDATAAPI + * Macro that defines a new cbdata datatype. Similar to a variable + * or struct definition. Scope is always local to the file/block + * where it is defined and all calls to cbdataAlloc() for this type + * must be within the same scope as the CBDATA_TYPE declaration. + * Allocated entries may be referenced or freed anywhere with no + * restrictions on scope. + */ #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN + +/** + \ingroup CBDATAAPI + * Defines a global cbdata type that can be referenced anywhere in the code. + * + \code + external CBDATA_GLOBAL_TYPE(datatype); + \endcode + * Should be added to the module *.h header file. + * + \code + CBDATA_GLOBAL_TYPE(datatype); + \endcode + * + * Should be added to the module main *.cc file. + */ #define CBDATA_GLOBAL_TYPE(type) cbdata_type CBDATA_##type + +/** + \ingroup CBDATAAPI + * + * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. + * + \par + * Alternative to CBDATA_INIT_TYPE_FREECB() + * + \param type Type being initialized + */ #define CBDATA_INIT_TYPE(type) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL))) + +/** + \ingroup CBDATAAPI + * + * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type. + * + \par + * Alternative to CBDATA_INIT_TYPE() + * + \param type Type being initialized + \param free_func The freehandler called when the last known reference to an allocated entry goes away. + */ #define CBDATA_INIT_TYPE_FREECB(type, free_func) (CBDATA_##type ? CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func))) -/* - * use this when you need to pass callback data to a blocking +/** + * \ingroup CBDATA + * + * A generic wrapper for passing objects through cbdata. + * Use this when you need to pass callback data to a blocking * operation, but you don't want to/cannot have that pointer be cbdata itself. */ - class generic_cbdata { public: + generic_cbdata(void * data) : data(data) {} + templatevoid unwrap(wrapped_type **output) { *output = static_cast(data); delete this; } - /* the wrapped data - only public to allow the mild abuse of this facility + + /** + * The wrapped data - only public to allow the mild abuse of this facility * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the * object to be given to the callbacks. That needs to be fully cleaned up! * - RBC 20060820 + * \todo CODE: make this a private field. */ void *data; /* the wrapped data */ private: CBDATA_CLASS2(generic_cbdata); }; - - #endif /* SQUID_CBDATA_H */ Index: squid3/src/clientStream.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/clientStream.cc,v retrieving revision 1.11.2.1 retrieving revision 1.11.2.2 diff -u -r1.11.2.1 -r1.11.2.2 --- squid3/src/clientStream.cc 9 Aug 2007 10:24:20 -0000 1.11.2.1 +++ squid3/src/clientStream.cc 9 Aug 2007 13:05:34 -0000 1.11.2.2 @@ -1,6 +1,6 @@ /* - * $Id: clientStream.cc,v 1.11.2.1 2007/08/09 10:24:20 amosjeffries Exp $ + * $Id: clientStream.cc,v 1.11.2.2 2007/08/09 13:05:34 amosjeffries Exp $ * * DEBUG: section 87 Client-side Stream routines. * AUTHOR: Robert Collins @@ -33,9 +33,14 @@ * */ +#include "squid.h" +#include "clientStream.h" +#include "HttpReply.h" +#include "HttpRequest.h" +#include "client_side_request.h" + /** - \ingroupClientStream - \section A (Coments from Head of clientStream.cc) + \defgroup ClientStreamInternal Client Streams Internals \par * A client Stream is a uni directional pipe, with the usual non-blocking * asynchronous approach present elsewhere in squid. @@ -49,7 +54,7 @@ * An alternative approach is to pass each node in the pipe the call- * back to use on each IO call. This allows the callbacks to be changed * very easily by a participating node, but requires more maintenance - * in each node (store the call back to the msot recent IO request in + * in each node (store the callback to the most recent IO request in * the nodes context.) Such an approach also prevents dynamically * changing the pipeline from outside without an additional interface * method to extract the callback and context from the next node. @@ -58,28 +63,12 @@ * One important characteristic of the stream is that the readfunc * on the terminating node, and the callback on the first node * will be NULL, and never used. - */ - -#include "squid.h" -#include "clientStream.h" -#include "HttpReply.h" -#include "HttpRequest.h" -#include "client_side_request.h" - -CBDATA_TYPE(clientStreamNode); - -/** - * \todo rather than each node undeleting the next, have a clientStreamDelete - * that walks the list - */ - -/** - \ingroup ClienStream - \section QuickNotes clientStream quick notes: + * + \section QuickNotes Quick Notes \par * Each node including the HEAD of the clientStream has a cbdataReference * held by the stream. Freeing the stream then removes that reference - * and cbdataFrees every node. + * and cbdataFree()'s every node. * Any node with other References, and all nodes downstream will only * free when those references are released. * Stream nodes MAY hold references to the data member of the node. @@ -111,11 +100,18 @@ mycontext = NULL; return; \endcode + * + * \todo rather than each node undeleting the next, have a clientStreamDelete that walks the list */ +/// \ingroup ClientStreamInternal +CBDATA_TYPE(clientStreamNode); + + /* Local functions */ static FREE clientStreamFree; +/// \ingroup ClientStreamInternal clientStreamNode * clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status, ClientStreamData data) @@ -132,6 +128,7 @@ } /** + \ingroup ClientStreamInternal * Initialise a client Stream. * list is the stream * func is the read function for the head @@ -153,6 +150,7 @@ } /** + \ingroup ClientStreamInternal * Doesn't actually insert at head. Instead it inserts one *after* * head. This is because HEAD is a special node, as is tail * This function is not suitable for inserting the real HEAD. @@ -177,6 +175,7 @@ } /** + \ingroup ClientStreamInternal * Callback the next node the in chain with it's requested data */ void @@ -193,6 +192,7 @@ } /** + \ingroup ClientStreamInternal * Call the previous node in the chain to read some data */ void @@ -211,6 +211,7 @@ } /** + \ingroup ClientStreamInternal * Detach from the stream - only allowed for terminal members */ void @@ -250,6 +251,7 @@ } /** + \ingroup ClientStreamInternal * Abort the stream - detach every node in the pipeline. */ void @@ -268,6 +270,7 @@ } /** + \ingroup ClientStreamInternal * Call the upstream node to find it's status */ clientStream_status_t @@ -280,6 +283,7 @@ } /* Local function bodies */ + void clientStreamNode::removeFromStream() { @@ -289,6 +293,7 @@ head = NULL; } +/// \ingroup ClientStreamInternal void clientStreamFree(void *foo) {