| #ifndef _IPXE_REFCNT_H | |
| #define _IPXE_REFCNT_H | |
| /** @file | |
| * | |
| * Reference counting | |
| * | |
| */ | |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | |
| FILE_SECBOOT ( PERMITTED ); | |
| #include <stddef.h> | |
| #include <assert.h> | |
| /** | |
| * A reference counter | |
| * | |
| * This data structure is designed to be embedded within a | |
| * reference-counted object. | |
| * | |
| * Reference-counted objects are freed when their reference count | |
| * drops below zero. This means that a freshly allocated-and-zeroed | |
| * reference-counted object will be freed on the first call to | |
| * ref_put(). | |
| */ | |
| struct refcnt { | |
| /** Current reference count | |
| * | |
| * When this count is decremented below zero, the free() | |
| * method will be called. | |
| */ | |
| int count; | |
| /** Free containing object | |
| * | |
| * This method is called when the reference count is | |
| * decremented below zero. | |
| * | |
| * If this method is left NULL, the standard library free() | |
| * function will be called. The upshot of this is that you | |
| * may omit the free() method if the @c refcnt object is the | |
| * first element of your reference-counted struct. | |
| */ | |
| void ( * free ) ( struct refcnt *refcnt ); | |
| }; | |
| /** | |
| * Initialise a reference counter | |
| * | |
| * @v refcnt Reference counter | |
| * @v free Freeing function | |
| */ | |
| static inline __attribute__ (( always_inline )) void | |
| ref_init ( struct refcnt *refcnt, | |
| void ( * free ) ( struct refcnt *refcnt ) ) { | |
| refcnt->free = free; | |
| } | |
| /** | |
| * Initialise a reference counter | |
| * | |
| * @v refcnt Reference counter | |
| * @v free Free containing object | |
| */ | |
| #define ref_init( refcnt, free ) do { \ | |
| if ( __builtin_constant_p ( (free) ) && ( (free) == NULL ) ) { \ | |
| /* Skip common case of no initialisation required */ \ | |
| } else { \ | |
| ref_init ( (refcnt), (free) ); \ | |
| } \ | |
| } while ( 0 ) | |
| /** | |
| * Initialise a static reference counter | |
| * | |
| * @v free_fn Free containing object | |
| */ | |
| #define REF_INIT( free_fn ) { \ | |
| .free = free_fn, \ | |
| } | |
| extern void ref_increment ( struct refcnt *refcnt ); | |
| extern void ref_decrement ( struct refcnt *refcnt ); | |
| /** | |
| * Get additional reference to object | |
| * | |
| * @v refcnt Reference counter, or NULL | |
| * @ret refcnt Reference counter | |
| * | |
| * If @c refcnt is NULL, no action is taken. | |
| */ | |
| #define ref_get( refcnt ) ( { \ | |
| if ( refcnt ) \ | |
| assert ( (refcnt)->count >= 0 ); \ | |
| ref_increment ( refcnt ); \ | |
| (refcnt); } ) | |
| /** | |
| * Drop reference to object | |
| * | |
| * @v refcnt Reference counter, or NULL | |
| * @ret refcnt Reference counter | |
| * | |
| * If @c refcnt is NULL, no action is taken. | |
| */ | |
| #define ref_put( refcnt ) do { \ | |
| if ( refcnt ) \ | |
| assert ( (refcnt)->count >= 0 ); \ | |
| ref_decrement ( refcnt ); \ | |
| } while ( 0 ) | |
| extern void ref_no_free ( struct refcnt *refcnt ); | |
| #endif /* _IPXE_REFCNT_H */ |