refcount.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: refcount.h,v 1.17 2009/09/29 23:48:04 tbox Exp $ */
00019 
00020 #ifndef ISC_REFCOUNT_H
00021 #define ISC_REFCOUNT_H 1
00022 
00023 #include <isc/atomic.h>
00024 #include <isc/lang.h>
00025 #include <isc/mutex.h>
00026 #include <isc/platform.h>
00027 #include <isc/types.h>
00028 #include <isc/util.h>
00029 
00030 /*! \file isc/refcount.h
00031  * \brief Implements a locked reference counter.
00032  *
00033  * These functions may actually be
00034  * implemented using macros, and implementations of these macros are below.
00035  * The isc_refcount_t type should not be accessed directly, as its contents
00036  * depend on the implementation.
00037  */
00038 
00039 ISC_LANG_BEGINDECLS
00040 
00041 /*
00042  * Function prototypes
00043  */
00044 
00045 /*
00046  * isc_result_t
00047  * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
00048  *
00049  * Initialize the reference counter.  There will be 'n' initial references.
00050  *
00051  * Requires:
00052  *      ref != NULL
00053  */
00054 
00055 /*
00056  * void
00057  * isc_refcount_destroy(isc_refcount_t *ref);
00058  *
00059  * Destroys a reference counter.
00060  *
00061  * Requires:
00062  *      ref != NULL
00063  *      The number of references is 0.
00064  */
00065 
00066 /*
00067  * void
00068  * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
00069  * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
00070  *
00071  * Increments the reference count, returning the new value in targetp if it's
00072  * not NULL.  The reference counter typically begins with the initial counter
00073  * of 1, and will be destroyed once the counter reaches 0.  Thus,
00074  * isc_refcount_increment() additionally requires the previous counter be
00075  * larger than 0 so that an error which violates the usage can be easily
00076  * caught.  isc_refcount_increment0() does not have this restriction.
00077  *
00078  * Requires:
00079  *      ref != NULL.
00080  */
00081 
00082 /*
00083  * void
00084  * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
00085  *
00086  * Decrements the reference count,  returning the new value in targetp if it's
00087  * not NULL.
00088  *
00089  * Requires:
00090  *      ref != NULL.
00091  */
00092 
00093 
00094 /*
00095  * Sample implementations
00096  */
00097 #ifdef ISC_PLATFORM_USETHREADS
00098 #ifdef ISC_PLATFORM_HAVEXADD
00099 
00100 #define ISC_REFCOUNT_HAVEATOMIC 1
00101 
00102 typedef struct isc_refcount {
00103         isc_int32_t refs;
00104 } isc_refcount_t;
00105 
00106 #define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
00107 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
00108 
00109 #define isc_refcount_increment0(rp, tp)                         \
00110         do {                                                    \
00111                 unsigned int *_tmp = (unsigned int *)(tp);      \
00112                 isc_int32_t prev;                               \
00113                 prev = isc_atomic_xadd(&(rp)->refs, 1);         \
00114                 if (_tmp != NULL)                               \
00115                         *_tmp = prev + 1;                       \
00116         } while (0)
00117 
00118 #define isc_refcount_increment(rp, tp)                          \
00119         do {                                                    \
00120                 unsigned int *_tmp = (unsigned int *)(tp);      \
00121                 isc_int32_t prev;                               \
00122                 prev = isc_atomic_xadd(&(rp)->refs, 1);         \
00123                 REQUIRE(prev > 0);                              \
00124                 if (_tmp != NULL)                               \
00125                         *_tmp = prev + 1;                       \
00126         } while (0)
00127 
00128 #define isc_refcount_decrement(rp, tp)                          \
00129         do {                                                    \
00130                 unsigned int *_tmp = (unsigned int *)(tp);      \
00131                 isc_int32_t prev;                               \
00132                 prev = isc_atomic_xadd(&(rp)->refs, -1);        \
00133                 REQUIRE(prev > 0);                              \
00134                 if (_tmp != NULL)                               \
00135                         *_tmp = prev - 1;                       \
00136         } while (0)
00137 
00138 #else  /* ISC_PLATFORM_HAVEXADD */
00139 
00140 typedef struct isc_refcount {
00141         int refs;
00142         isc_mutex_t lock;
00143 } isc_refcount_t;
00144 
00145 /*% Destroys a reference counter. */
00146 #define isc_refcount_destroy(rp)                        \
00147         do {                                            \
00148                 REQUIRE((rp)->refs == 0);               \
00149                 DESTROYLOCK(&(rp)->lock);               \
00150         } while (0)
00151 
00152 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
00153 
00154 /*% Increments the reference count, returning the new value in targetp if it's not NULL. */
00155 #define isc_refcount_increment0(rp, tp)                         \
00156         do {                                                    \
00157                 unsigned int *_tmp = (unsigned int *)(tp);      \
00158                 LOCK(&(rp)->lock);                              \
00159                 ++((rp)->refs);                                 \
00160                 if (_tmp != NULL)                               \
00161                         *_tmp = ((rp)->refs);                   \
00162                 UNLOCK(&(rp)->lock);                            \
00163         } while (0)
00164 
00165 #define isc_refcount_increment(rp, tp)                          \
00166         do {                                                    \
00167                 unsigned int *_tmp = (unsigned int *)(tp);      \
00168                 LOCK(&(rp)->lock);                              \
00169                 REQUIRE((rp)->refs > 0);                        \
00170                 ++((rp)->refs);                                 \
00171                 if (_tmp != NULL)                               \
00172                         *_tmp = ((rp)->refs);                   \
00173                 UNLOCK(&(rp)->lock);                            \
00174         } while (0)
00175 
00176 /*% Decrements the reference count,  returning the new value in targetp if it's not NULL. */
00177 #define isc_refcount_decrement(rp, tp)                          \
00178         do {                                                    \
00179                 unsigned int *_tmp = (unsigned int *)(tp);      \
00180                 LOCK(&(rp)->lock);                              \
00181                 REQUIRE((rp)->refs > 0);                        \
00182                 --((rp)->refs);                                 \
00183                 if (_tmp != NULL)                               \
00184                         *_tmp = ((rp)->refs);                   \
00185                 UNLOCK(&(rp)->lock);                            \
00186         } while (0)
00187 
00188 #endif /* ISC_PLATFORM_HAVEXADD */
00189 #else  /* ISC_PLATFORM_USETHREADS */
00190 
00191 typedef struct isc_refcount {
00192         int refs;
00193 } isc_refcount_t;
00194 
00195 #define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
00196 #define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
00197 
00198 #define isc_refcount_increment0(rp, tp)                                 \
00199         do {                                                            \
00200                 unsigned int *_tmp = (unsigned int *)(tp);              \
00201                 int _n = ++(rp)->refs;                                  \
00202                 if (_tmp != NULL)                                       \
00203                         *_tmp = _n;                                     \
00204         } while (0)
00205 
00206 #define isc_refcount_increment(rp, tp)                                  \
00207         do {                                                            \
00208                 unsigned int *_tmp = (unsigned int *)(tp);              \
00209                 int _n;                                                 \
00210                 REQUIRE((rp)->refs > 0);                                \
00211                 _n = ++(rp)->refs;                                      \
00212                 if (_tmp != NULL)                                       \
00213                         *_tmp = _n;                                     \
00214         } while (0)
00215 
00216 #define isc_refcount_decrement(rp, tp)                                  \
00217         do {                                                            \
00218                 unsigned int *_tmp = (unsigned int *)(tp);              \
00219                 int _n;                                                 \
00220                 REQUIRE((rp)->refs > 0);                                \
00221                 _n = --(rp)->refs;                                      \
00222                 if (_tmp != NULL)                                       \
00223                         *_tmp = _n;                                     \
00224         } while (0)
00225 
00226 #endif /* ISC_PLATFORM_USETHREADS */
00227 
00228 isc_result_t
00229 isc_refcount_init(isc_refcount_t *ref, unsigned int n);
00230 
00231 ISC_LANG_ENDDECLS
00232 
00233 #endif /* ISC_REFCOUNT_H */

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha