Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / include / isc / refcount.h
blob3d9429e20168c86aea802851c79fc7af3d953da4
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001, 2003 Internet Software Consortium.
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.
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.
20 /* Id: refcount.h,v 1.15 2007/06/19 23:47:18 tbox Exp */
22 #ifndef ISC_REFCOUNT_H
23 #define ISC_REFCOUNT_H 1
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>
32 /*! \file isc/refcount.h
33 * \brief Implements a locked reference counter.
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.
41 ISC_LANG_BEGINDECLS
44 * Function prototypes
47 /*
48 * isc_result_t
49 * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
51 * Initialize the reference counter. There will be 'n' initial references.
53 * Requires:
54 * ref != NULL
58 * void
59 * isc_refcount_destroy(isc_refcount_t *ref);
61 * Destroys a reference counter.
63 * Requires:
64 * ref != NULL
65 * The number of references is 0.
69 * void
70 * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
71 * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
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.
80 * Requires:
81 * ref != NULL.
85 * void
86 * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
88 * Decrements the reference count, returning the new value in targetp if it's
89 * not NULL.
91 * Requires:
92 * ref != NULL.
97 * Sample implementations
99 #ifdef ISC_PLATFORM_USETHREADS
100 #ifdef ISC_PLATFORM_HAVEXADD
102 #define ISC_REFCOUNT_HAVEATOMIC 1
104 typedef struct isc_refcount {
105 isc_int32_t refs;
106 } isc_refcount_t;
108 #define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
109 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
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 (0)
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 (0)
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 (0)
140 #else /* ISC_PLATFORM_HAVEXADD */
142 typedef struct isc_refcount {
143 int refs;
144 isc_mutex_t lock;
145 } isc_refcount_t;
147 /*% Destroys a reference counter. */
148 #define isc_refcount_destroy(rp) \
149 do { \
150 REQUIRE((rp)->refs == 0); \
151 DESTROYLOCK(&(rp)->lock); \
152 } while (0)
154 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
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 (0)
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 (0)
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 (0)
190 #endif /* ISC_PLATFORM_HAVEXADD */
191 #else /* ISC_PLATFORM_USETHREADS */
193 typedef struct isc_refcount {
194 int refs;
195 } isc_refcount_t;
197 #define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
198 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
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 (0)
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 (0)
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 (0)
228 #endif /* ISC_PLATFORM_USETHREADS */
230 isc_result_t
231 isc_refcount_init(isc_refcount_t *ref, unsigned int n);
233 ISC_LANG_ENDDECLS
235 #endif /* ISC_REFCOUNT_H */