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