1*c0b5d9fbSchristos /* $NetBSD: refcount.h,v 1.6 2022/09/23 12:15:33 christos Exp $ */
2e2b1b9c0Schristos
3e2b1b9c0Schristos /*
4e2b1b9c0Schristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5e2b1b9c0Schristos *
6*c0b5d9fbSchristos * SPDX-License-Identifier: MPL-2.0
7*c0b5d9fbSchristos *
8e2b1b9c0Schristos * This Source Code Form is subject to the terms of the Mozilla Public
9e2b1b9c0Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this
1073584a28Schristos * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11e2b1b9c0Schristos *
12e2b1b9c0Schristos * See the COPYRIGHT file distributed with this work for additional
13e2b1b9c0Schristos * information regarding copyright ownership.
14e2b1b9c0Schristos */
15e2b1b9c0Schristos
16f2e20987Schristos #pragma once
17e2b1b9c0Schristos
18f2e20987Schristos #include <inttypes.h>
19e2b1b9c0Schristos
20e2b1b9c0Schristos #include <isc/assertions.h>
21e2b1b9c0Schristos #include <isc/atomic.h>
22e2b1b9c0Schristos #include <isc/error.h>
23e2b1b9c0Schristos #include <isc/lang.h>
24e2b1b9c0Schristos #include <isc/mutex.h>
25e2b1b9c0Schristos #include <isc/platform.h>
26e2b1b9c0Schristos #include <isc/types.h>
27e2b1b9c0Schristos
28e2b1b9c0Schristos /*! \file isc/refcount.h
29e2b1b9c0Schristos * \brief Implements a locked reference counter.
30e2b1b9c0Schristos *
31f2e20987Schristos * These macros uses C11(-like) atomic functions to implement reference
32f2e20987Schristos * counting. The isc_refcount_t type must not be accessed directly.
33e2b1b9c0Schristos */
34e2b1b9c0Schristos
35e2b1b9c0Schristos ISC_LANG_BEGINDECLS
36e2b1b9c0Schristos
37f2e20987Schristos typedef atomic_uint_fast32_t isc_refcount_t;
38f2e20987Schristos
39f2e20987Schristos /** \def isc_refcount_init(ref, n)
40f2e20987Schristos * \brief Initialize the reference counter.
41f2e20987Schristos * \param[in] ref pointer to reference counter.
42f2e20987Schristos * \param[in] n an initial number of references.
43f2e20987Schristos * \return nothing.
44f2e20987Schristos *
45f2e20987Schristos * \warning No memory barrier are being imposed here.
46f2e20987Schristos */
479742fdb4Schristos #define isc_refcount_init(target, value) atomic_init(target, value)
48f2e20987Schristos
49f2e20987Schristos /** \def isc_refcount_current(ref)
50f2e20987Schristos * \brief Returns current number of references.
51f2e20987Schristos * \param[in] ref pointer to reference counter.
52f2e20987Schristos * \returns current value of reference counter.
53f2e20987Schristos *
549742fdb4Schristos * Undo implicit promotion to 64 bits in our Windows implementation of
55f2e20987Schristos * atomic_load_explicit() by casting to uint_fast32_t.
56e2b1b9c0Schristos */
57e2b1b9c0Schristos
589742fdb4Schristos #define isc_refcount_current(target) (uint_fast32_t) atomic_load_acquire(target)
59f2e20987Schristos
60f2e20987Schristos /** \def isc_refcount_destroy(ref)
61f2e20987Schristos * \brief a destructor that makes sure that all references were cleared.
62f2e20987Schristos * \param[in] ref pointer to reference counter.
63f2e20987Schristos * \returns nothing.
64e2b1b9c0Schristos */
65f2e20987Schristos #define isc_refcount_destroy(target) \
66f2e20987Schristos ISC_REQUIRE(isc_refcount_current(target) == 0)
67e2b1b9c0Schristos
68f2e20987Schristos /** \def isc_refcount_increment0(ref)
69f2e20987Schristos * \brief increases reference counter by 1.
70f2e20987Schristos * \param[in] ref pointer to reference counter.
71f2e20987Schristos * \returns previous value of reference counter.
72e2b1b9c0Schristos */
739742fdb4Schristos #if _MSC_VER
749742fdb4Schristos static inline uint_fast32_t
isc_refcount_increment0(isc_refcount_t * target)759742fdb4Schristos isc_refcount_increment0(isc_refcount_t *target) {
769742fdb4Schristos uint_fast32_t __v;
779742fdb4Schristos __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1);
789742fdb4Schristos INSIST(__v < UINT32_MAX);
799742fdb4Schristos return (__v);
809742fdb4Schristos }
819742fdb4Schristos #else /* _MSC_VER */
82f2e20987Schristos #define isc_refcount_increment0(target) \
839742fdb4Schristos ({ \
849742fdb4Schristos /* cppcheck-suppress shadowVariable */ \
859742fdb4Schristos uint_fast32_t __v; \
869742fdb4Schristos __v = atomic_fetch_add_relaxed(target, 1); \
879742fdb4Schristos INSIST(__v < UINT32_MAX); \
889742fdb4Schristos __v; \
899742fdb4Schristos })
909742fdb4Schristos #endif /* _MSC_VER */
91e2b1b9c0Schristos
92f2e20987Schristos /** \def isc_refcount_increment(ref)
93f2e20987Schristos * \brief increases reference counter by 1.
94f2e20987Schristos * \param[in] ref pointer to reference counter.
95f2e20987Schristos * \returns previous value of reference counter.
96e2b1b9c0Schristos */
979742fdb4Schristos #if _MSC_VER
989742fdb4Schristos static inline uint_fast32_t
isc_refcount_increment(isc_refcount_t * target)999742fdb4Schristos isc_refcount_increment(isc_refcount_t *target) {
1009742fdb4Schristos uint_fast32_t __v;
1019742fdb4Schristos __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1);
1029742fdb4Schristos INSIST(__v > 0 && __v < UINT32_MAX);
1039742fdb4Schristos return (__v);
1049742fdb4Schristos }
1059742fdb4Schristos #else /* _MSC_VER */
106f2e20987Schristos #define isc_refcount_increment(target) \
1079742fdb4Schristos ({ \
1089742fdb4Schristos /* cppcheck-suppress shadowVariable */ \
1099742fdb4Schristos uint_fast32_t __v; \
1109742fdb4Schristos __v = atomic_fetch_add_relaxed(target, 1); \
1119742fdb4Schristos INSIST(__v > 0 && __v < UINT32_MAX); \
1129742fdb4Schristos __v; \
1139742fdb4Schristos })
1149742fdb4Schristos #endif /* _MSC_VER */
115e2b1b9c0Schristos
116f2e20987Schristos /** \def isc_refcount_decrement(ref)
117f2e20987Schristos * \brief decreases reference counter by 1.
118f2e20987Schristos * \param[in] ref pointer to reference counter.
119f2e20987Schristos * \returns previous value of reference counter.
120e2b1b9c0Schristos */
1219742fdb4Schristos #if _MSC_VER
1229742fdb4Schristos static inline uint_fast32_t
isc_refcount_decrement(isc_refcount_t * target)1239742fdb4Schristos isc_refcount_decrement(isc_refcount_t *target) {
1249742fdb4Schristos uint_fast32_t __v;
12573584a28Schristos __v = (uint_fast32_t)atomic_fetch_sub_acq_rel(target, 1);
1269742fdb4Schristos INSIST(__v > 0);
1279742fdb4Schristos return (__v);
1289742fdb4Schristos }
1299742fdb4Schristos #else /* _MSC_VER */
130f2e20987Schristos #define isc_refcount_decrement(target) \
1319742fdb4Schristos ({ \
1329742fdb4Schristos /* cppcheck-suppress shadowVariable */ \
1339742fdb4Schristos uint_fast32_t __v; \
13473584a28Schristos __v = atomic_fetch_sub_acq_rel(target, 1); \
1359742fdb4Schristos INSIST(__v > 0); \
1369742fdb4Schristos __v; \
1379742fdb4Schristos })
1389742fdb4Schristos #endif /* _MSC_VER */
139e2b1b9c0Schristos
14073584a28Schristos #define isc_refcount_decrementz(target) \
14173584a28Schristos do { \
14273584a28Schristos uint_fast32_t _refs = isc_refcount_decrement(target); \
14373584a28Schristos ISC_INSIST(_refs == 1); \
14473584a28Schristos } while (0)
14573584a28Schristos
14673584a28Schristos #define isc_refcount_decrement1(target) \
14773584a28Schristos do { \
14873584a28Schristos uint_fast32_t _refs = isc_refcount_decrement(target); \
14973584a28Schristos ISC_INSIST(_refs > 1); \
15073584a28Schristos } while (0)
15173584a28Schristos
15273584a28Schristos #define isc_refcount_decrement0(target) \
15373584a28Schristos do { \
15473584a28Schristos uint_fast32_t _refs = isc_refcount_decrement(target); \
15573584a28Schristos ISC_INSIST(_refs > 0); \
15673584a28Schristos } while (0)
15773584a28Schristos
158e2b1b9c0Schristos ISC_LANG_ENDDECLS
159