1 /* $NetBSD: refcount.h,v 1.1 2024/02/18 20:57:54 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #pragma once 17 18 #include <inttypes.h> 19 20 #include <isc/assertions.h> 21 #include <isc/atomic.h> 22 #include <isc/error.h> 23 #include <isc/lang.h> 24 #include <isc/mutex.h> 25 #include <isc/platform.h> 26 #include <isc/types.h> 27 28 /*! \file isc/refcount.h 29 * \brief Implements a locked reference counter. 30 * 31 * These macros uses C11(-like) atomic functions to implement reference 32 * counting. The isc_refcount_t type must not be accessed directly. 33 */ 34 35 ISC_LANG_BEGINDECLS 36 37 typedef atomic_uint_fast32_t isc_refcount_t; 38 39 /** \def isc_refcount_init(ref, n) 40 * \brief Initialize the reference counter. 41 * \param[in] ref pointer to reference counter. 42 * \param[in] n an initial number of references. 43 * \return nothing. 44 * 45 * \warning No memory barrier are being imposed here. 46 */ 47 #define isc_refcount_init(target, value) atomic_init(target, value) 48 49 /** \def isc_refcount_current(ref) 50 * \brief Returns current number of references. 51 * \param[in] ref pointer to reference counter. 52 * \returns current value of reference counter. 53 * 54 * Undo implicit promotion to 64 bits in our Windows implementation of 55 * atomic_load_explicit() by casting to uint_fast32_t. 56 */ 57 58 #define isc_refcount_current(target) (uint_fast32_t) atomic_load_acquire(target) 59 60 /** \def isc_refcount_destroy(ref) 61 * \brief a destructor that makes sure that all references were cleared. 62 * \param[in] ref pointer to reference counter. 63 * \returns nothing. 64 */ 65 #define isc_refcount_destroy(target) \ 66 ISC_REQUIRE(isc_refcount_current(target) == 0) 67 68 /** \def isc_refcount_increment0(ref) 69 * \brief increases reference counter by 1. 70 * \param[in] ref pointer to reference counter. 71 * \returns previous value of reference counter. 72 */ 73 #if _MSC_VER 74 static inline uint_fast32_t 75 isc_refcount_increment0(isc_refcount_t *target) { 76 uint_fast32_t __v; 77 __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1); 78 INSIST(__v < UINT32_MAX); 79 return (__v); 80 } 81 #else /* _MSC_VER */ 82 #define isc_refcount_increment0(target) \ 83 ({ \ 84 /* cppcheck-suppress shadowVariable */ \ 85 uint_fast32_t __v; \ 86 __v = atomic_fetch_add_relaxed(target, 1); \ 87 INSIST(__v < UINT32_MAX); \ 88 __v; \ 89 }) 90 #endif /* _MSC_VER */ 91 92 /** \def isc_refcount_increment(ref) 93 * \brief increases reference counter by 1. 94 * \param[in] ref pointer to reference counter. 95 * \returns previous value of reference counter. 96 */ 97 #if _MSC_VER 98 static inline uint_fast32_t 99 isc_refcount_increment(isc_refcount_t *target) { 100 uint_fast32_t __v; 101 __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1); 102 INSIST(__v > 0 && __v < UINT32_MAX); 103 return (__v); 104 } 105 #else /* _MSC_VER */ 106 #define isc_refcount_increment(target) \ 107 ({ \ 108 /* cppcheck-suppress shadowVariable */ \ 109 uint_fast32_t __v; \ 110 __v = atomic_fetch_add_relaxed(target, 1); \ 111 INSIST(__v > 0 && __v < UINT32_MAX); \ 112 __v; \ 113 }) 114 #endif /* _MSC_VER */ 115 116 /** \def isc_refcount_decrement(ref) 117 * \brief decreases reference counter by 1. 118 * \param[in] ref pointer to reference counter. 119 * \returns previous value of reference counter. 120 */ 121 #if _MSC_VER 122 static inline uint_fast32_t 123 isc_refcount_decrement(isc_refcount_t *target) { 124 uint_fast32_t __v; 125 __v = (uint_fast32_t)atomic_fetch_sub_acq_rel(target, 1); 126 INSIST(__v > 0); 127 return (__v); 128 } 129 #else /* _MSC_VER */ 130 #define isc_refcount_decrement(target) \ 131 ({ \ 132 /* cppcheck-suppress shadowVariable */ \ 133 uint_fast32_t __v; \ 134 __v = atomic_fetch_sub_acq_rel(target, 1); \ 135 INSIST(__v > 0); \ 136 __v; \ 137 }) 138 #endif /* _MSC_VER */ 139 140 #define isc_refcount_decrementz(target) \ 141 do { \ 142 uint_fast32_t _refs = isc_refcount_decrement(target); \ 143 ISC_INSIST(_refs == 1); \ 144 } while (0) 145 146 #define isc_refcount_decrement1(target) \ 147 do { \ 148 uint_fast32_t _refs = isc_refcount_decrement(target); \ 149 ISC_INSIST(_refs > 1); \ 150 } while (0) 151 152 #define isc_refcount_decrement0(target) \ 153 do { \ 154 uint_fast32_t _refs = isc_refcount_decrement(target); \ 155 ISC_INSIST(_refs > 0); \ 156 } while (0) 157 158 ISC_LANG_ENDDECLS 159