1 /* $NetBSD: refcount.h,v 1.6 2022/09/23 12:15:33 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
isc_refcount_increment0(isc_refcount_t * target)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
isc_refcount_increment(isc_refcount_t * target)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
isc_refcount_decrement(isc_refcount_t * target)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