david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/include/ipxe/refcnt.h

115 lines
2.6 KiB
C

#ifndef _IPXE_REFCNT_H
#define _IPXE_REFCNT_H
/** @file
*
* Reference counting
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#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 */