1 #ifndef _IPXE_REFCNT_H
2 #define _IPXE_REFCNT_H
3
4 /** @file
5 *
6 * Reference counting
7 *
8 */
9
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
12 #include <stddef.h>
13 #include <assert.h>
14
15 /**
16 * A reference counter
17 *
18 * This data structure is designed to be embedded within a
19 * reference-counted object.
20 *
21 * Reference-counted objects are freed when their reference count
22 * drops below zero. This means that a freshly allocated-and-zeroed
23 * reference-counted object will be freed on the first call to
24 * ref_put().
25 */
26 struct refcnt {
27 /** Current reference count
28 *
29 * When this count is decremented below zero, the free()
30 * method will be called.
31 */
32 int count;
33 /** Free containing object
34 *
35 * This method is called when the reference count is
36 * decremented below zero.
37 *
38 * If this method is left NULL, the standard library free()
39 * function will be called. The upshot of this is that you
40 * may omit the free() method if the @c refcnt object is the
41 * first element of your reference-counted struct.
42 */
43 void ( * free ) ( struct refcnt *refcnt );
44 };
45
46 /**
47 * Initialise a reference counter
48 *
49 * @v refcnt Reference counter
50 * @v free Freeing function
51 */
52 static inline __attribute__ (( always_inline )) void
ref_init(struct refcnt * refcnt,void (* free)(struct refcnt * refcnt))53 ref_init ( struct refcnt *refcnt,
54 void ( * free ) ( struct refcnt *refcnt ) ) {
55 refcnt->free = free;
56 }
57
58 /**
59 * Initialise a reference counter
60 *
61 * @v refcnt Reference counter
62 * @v free Free containing object
63 */
64 #define ref_init( refcnt, free ) do { \
65 if ( __builtin_constant_p ( (free) ) && ( (free) == NULL ) ) { \
66 /* Skip common case of no initialisation required */ \
67 } else { \
68 ref_init ( (refcnt), (free) ); \
69 } \
70 } while ( 0 )
71
72 /**
73 * Initialise a static reference counter
74 *
75 * @v free_fn Free containing object
76 */
77 #define REF_INIT( free_fn ) { \
78 .free = free_fn, \
79 }
80
81 extern void ref_increment ( struct refcnt *refcnt );
82 extern void ref_decrement ( struct refcnt *refcnt );
83
84 /**
85 * Get additional reference to object
86 *
87 * @v refcnt Reference counter, or NULL
88 * @ret refcnt Reference counter
89 *
90 * If @c refcnt is NULL, no action is taken.
91 */
92 #define ref_get( refcnt ) ( { \
93 if ( refcnt ) \
94 assert ( (refcnt)->count >= 0 ); \
95 ref_increment ( refcnt ); \
96 (refcnt); } )
97
98 /**
99 * Drop reference to object
100 *
101 * @v refcnt Reference counter, or NULL
102 * @ret refcnt Reference counter
103 *
104 * If @c refcnt is NULL, no action is taken.
105 */
106 #define ref_put( refcnt ) do { \
107 if ( refcnt ) \
108 assert ( (refcnt)->count >= 0 ); \
109 ref_decrement ( refcnt ); \
110 } while ( 0 )
111
112 extern void ref_no_free ( struct refcnt *refcnt );
113
114 #endif /* _IPXE_REFCNT_H */
115