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