Home | History | Annotate | Line # | Download | only in isc
      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