iPXE
refcnt.h
Go to the documentation of this file.
00001 #ifndef _IPXE_REFCNT_H
00002 #define _IPXE_REFCNT_H
00003 
00004 /** @file
00005  *
00006  * Reference counting
00007  *
00008  */
00009 
00010 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00011 
00012 #include <stddef.h>
00013 #include <assert.h>
00014 
00015 /**
00016  * A reference counter
00017  *
00018  * This data structure is designed to be embedded within a
00019  * reference-counted object.
00020  *
00021  * Reference-counted objects are freed when their reference count
00022  * drops below zero.  This means that a freshly allocated-and-zeroed
00023  * reference-counted object will be freed on the first call to
00024  * ref_put().
00025  */
00026 struct refcnt {
00027         /** Current reference count
00028          *
00029          * When this count is decremented below zero, the free()
00030          * method will be called.
00031          */
00032         int count;
00033         /** Free containing object
00034          *
00035          * This method is called when the reference count is
00036          * decremented below zero.
00037          *
00038          * If this method is left NULL, the standard library free()
00039          * function will be called.  The upshot of this is that you
00040          * may omit the free() method if the @c refcnt object is the
00041          * first element of your reference-counted struct.
00042          */
00043         void ( * free ) ( struct refcnt *refcnt );
00044 };
00045 
00046 /**
00047  * Initialise a reference counter
00048  *
00049  * @v refcnt            Reference counter
00050  * @v free              Freeing function
00051  */
00052 static inline __attribute__ (( always_inline )) void
00053 ref_init ( struct refcnt *refcnt,
00054            void ( * free ) ( struct refcnt *refcnt ) ) {
00055         refcnt->free = free;
00056 }
00057 
00058 /**
00059  * Initialise a reference counter
00060  *
00061  * @v refcnt            Reference counter
00062  * @v free              Free containing object
00063  */
00064 #define ref_init( refcnt, free ) do {                                   \
00065         if ( __builtin_constant_p ( (free) ) && ( (free) == NULL ) ) {  \
00066                 /* Skip common case of no initialisation required */    \
00067         } else {                                                        \
00068                 ref_init ( (refcnt), (free) );                          \
00069         }                                                               \
00070         } while ( 0 )
00071 
00072 /**
00073  * Initialise a static reference counter
00074  *
00075  * @v free_fn           Free containing object
00076  */
00077 #define REF_INIT( free_fn ) {                                           \
00078                 .free = free_fn,                                        \
00079         }
00080 
00081 extern void ref_increment ( struct refcnt *refcnt );
00082 extern void ref_decrement ( struct refcnt *refcnt );
00083 
00084 /**
00085  * Get additional reference to object
00086  *
00087  * @v refcnt            Reference counter, or NULL
00088  * @ret refcnt          Reference counter
00089  *
00090  * If @c refcnt is NULL, no action is taken.
00091  */
00092 #define ref_get( refcnt ) ( {                                           \
00093         if ( refcnt )                                                   \
00094                 assert ( (refcnt)->count >= 0 );                        \
00095         ref_increment ( refcnt );                                       \
00096         (refcnt); } )
00097 
00098 /**
00099  * Drop reference to object
00100  *
00101  * @v refcnt            Reference counter, or NULL
00102  * @ret refcnt          Reference counter
00103  *
00104  * If @c refcnt is NULL, no action is taken.
00105  */
00106 #define ref_put( refcnt ) do {                                          \
00107         if ( refcnt )                                                   \
00108                 assert ( (refcnt)->count >= 0 );                        \
00109         ref_decrement ( refcnt );                                       \
00110         } while ( 0 )
00111 
00112 extern void ref_no_free ( struct refcnt *refcnt );
00113 
00114 #endif /* _IPXE_REFCNT_H */