1 /*	$NetBSD: refcount.h,v 1.6 2014/12/10 04:38:00 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 2001, 2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: refcount.h,v 1.17 2009/09/29 23:48:04 tbox Exp  */
21 
22 #ifndef ISC_REFCOUNT_H
23 #define ISC_REFCOUNT_H 1
24 
25 #include <isc/atomic.h>
26 #include <isc/lang.h>
27 #include <isc/mutex.h>
28 #include <isc/platform.h>
29 #include <isc/types.h>
30 #include <isc/util.h>
31 
32 /*! \file isc/refcount.h
33  * \brief Implements a locked reference counter.
34  *
35  * These functions may actually be
36  * implemented using macros, and implementations of these macros are below.
37  * The isc_refcount_t type should not be accessed directly, as its contents
38  * depend on the implementation.
39  */
40 
41 ISC_LANG_BEGINDECLS
42 
43 /*
44  * Function prototypes
45  */
46 
47 /*
48  * isc_result_t
49  * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
50  *
51  * Initialize the reference counter.  There will be 'n' initial references.
52  *
53  * Requires:
54  *	ref != NULL
55  */
56 
57 /*
58  * void
59  * isc_refcount_destroy(isc_refcount_t *ref);
60  *
61  * Destroys a reference counter.
62  *
63  * Requires:
64  *	ref != NULL
65  *	The number of references is 0.
66  */
67 
68 /*
69  * void
70  * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
71  * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
72  *
73  * Increments the reference count, returning the new value in targetp if it's
74  * not NULL.  The reference counter typically begins with the initial counter
75  * of 1, and will be destroyed once the counter reaches 0.  Thus,
76  * isc_refcount_increment() additionally requires the previous counter be
77  * larger than 0 so that an error which violates the usage can be easily
78  * caught.  isc_refcount_increment0() does not have this restriction.
79  *
80  * Requires:
81  *	ref != NULL.
82  */
83 
84 /*
85  * void
86  * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
87  *
88  * Decrements the reference count,  returning the new value in targetp if it's
89  * not NULL.
90  *
91  * Requires:
92  *	ref != NULL.
93  */
94 
95 
96 /*
97  * Sample implementations
98  */
99 #ifdef ISC_PLATFORM_USETHREADS
100 #ifdef ISC_PLATFORM_HAVEXADD
101 
102 #define ISC_REFCOUNT_HAVEATOMIC 1
103 
104 typedef struct isc_refcount {
105 	isc_int32_t refs;
106 } isc_refcount_t;
107 
108 #define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
109 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
110 
111 #define isc_refcount_increment0(rp, tp)				\
112 	do {							\
113 		unsigned int *_tmp = (unsigned int *)(tp);	\
114 		isc_int32_t prev;				\
115 		prev = isc_atomic_xadd(&(rp)->refs, 1);		\
116 		if (_tmp != NULL)				\
117 			*_tmp = prev + 1;			\
118 	} while (/*CONSTCOND*/0)
119 
120 #define isc_refcount_increment(rp, tp)				\
121 	do {							\
122 		unsigned int *_tmp = (unsigned int *)(tp);	\
123 		isc_int32_t prev;				\
124 		prev = isc_atomic_xadd(&(rp)->refs, 1);		\
125 		REQUIRE(prev > 0);				\
126 		if (_tmp != NULL)				\
127 			*_tmp = prev + 1;			\
128 	} while (/*CONSTCOND*/0)
129 
130 #define isc_refcount_decrement(rp, tp)				\
131 	do {							\
132 		unsigned int *_tmp = (unsigned int *)(tp);	\
133 		isc_int32_t prev;				\
134 		prev = isc_atomic_xadd(&(rp)->refs, -1);	\
135 		REQUIRE(prev > 0);				\
136 		if (_tmp != NULL)				\
137 			*_tmp = prev - 1;			\
138 	} while (/*CONSTCOND*/0)
139 
140 #else  /* ISC_PLATFORM_HAVEXADD */
141 
142 typedef struct isc_refcount {
143 	int refs;
144 	isc_mutex_t lock;
145 } isc_refcount_t;
146 
147 /*% Destroys a reference counter. */
148 #define isc_refcount_destroy(rp)			\
149 	do {						\
150 		REQUIRE((rp)->refs == 0);		\
151 		DESTROYLOCK(&(rp)->lock);		\
152 	} while (/*CONSTCOND*/0)
153 
154 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
155 
156 /*% Increments the reference count, returning the new value in targetp if it's not NULL. */
157 #define isc_refcount_increment0(rp, tp)				\
158 	do {							\
159 		unsigned int *_tmp = (unsigned int *)(tp);	\
160 		LOCK(&(rp)->lock);				\
161 		++((rp)->refs);					\
162 		if (_tmp != NULL)				\
163 			*_tmp = ((rp)->refs);			\
164 		UNLOCK(&(rp)->lock);				\
165 	} while (/*CONSTCOND*/0)
166 
167 #define isc_refcount_increment(rp, tp)				\
168 	do {							\
169 		unsigned int *_tmp = (unsigned int *)(tp);	\
170 		LOCK(&(rp)->lock);				\
171 		REQUIRE((rp)->refs > 0);			\
172 		++((rp)->refs);					\
173 		if (_tmp != NULL)				\
174 			*_tmp = ((rp)->refs);			\
175 		UNLOCK(&(rp)->lock);				\
176 	} while (/*CONSTCOND*/0)
177 
178 /*% Decrements the reference count,  returning the new value in targetp if it's not NULL. */
179 #define isc_refcount_decrement(rp, tp)				\
180 	do {							\
181 		unsigned int *_tmp = (unsigned int *)(tp);	\
182 		LOCK(&(rp)->lock);				\
183 		REQUIRE((rp)->refs > 0);			\
184 		--((rp)->refs);					\
185 		if (_tmp != NULL)				\
186 			*_tmp = ((rp)->refs);			\
187 		UNLOCK(&(rp)->lock);				\
188 	} while (/*CONSTCOND*/0)
189 
190 #endif /* ISC_PLATFORM_HAVEXADD */
191 #else  /* ISC_PLATFORM_USETHREADS */
192 
193 typedef struct isc_refcount {
194 	int refs;
195 } isc_refcount_t;
196 
197 #define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
198 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
199 
200 #define isc_refcount_increment0(rp, tp)					\
201 	do {								\
202 		unsigned int *_tmp = (unsigned int *)(tp);		\
203 		int _n = ++(rp)->refs;					\
204 		if (_tmp != NULL)					\
205 			*_tmp = _n;					\
206 	} while (/*CONSTCOND*/0)
207 
208 #define isc_refcount_increment(rp, tp)					\
209 	do {								\
210 		unsigned int *_tmp = (unsigned int *)(tp);		\
211 		int _n;							\
212 		REQUIRE((rp)->refs > 0);				\
213 		_n = ++(rp)->refs;					\
214 		if (_tmp != NULL)					\
215 			*_tmp = _n;					\
216 	} while (/*CONSTCOND*/0)
217 
218 #define isc_refcount_decrement(rp, tp)					\
219 	do {								\
220 		unsigned int *_tmp = (unsigned int *)(tp);		\
221 		int _n;							\
222 		REQUIRE((rp)->refs > 0);				\
223 		_n = --(rp)->refs;					\
224 		if (_tmp != NULL)					\
225 			*_tmp = _n;					\
226 	} while (/*CONSTCOND*/0)
227 
228 #endif /* ISC_PLATFORM_USETHREADS */
229 
230 isc_result_t
231 isc_refcount_init(isc_refcount_t *ref, unsigned int n);
232 
233 ISC_LANG_ENDDECLS
234 
235 #endif /* ISC_REFCOUNT_H */
236