1 /* $NetBSD: refcount.h,v 1.1.1.1 2009/12/13 16:54:27 kardel Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2007 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.15 2007/06/19 23:47:18 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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