root/usr.bin/dig/lib/isc/include/isc/refcount.h
/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/* $Id: refcount.h,v 1.3 2020/02/25 05:00:43 jsg Exp $ */

#ifndef ISC_REFCOUNT_H
#define ISC_REFCOUNT_H 1

#include <isc/assertions.h>
#include <isc/error.h>
#include <isc/types.h>

/*! \file isc/refcount.h
 * \brief Implements a locked reference counter.
 *
 * These functions may actually be
 * implemented using macros, and implementations of these macros are below.
 * The isc_refcount_t type should not be accessed directly, as its contents
 * depend on the implementation.
 */

/*
 * Function prototypes
 */

/*
 * isc_result_t
 * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
 *
 * Initialize the reference counter.  There will be 'n' initial references.
 *
 * Requires:
 *      ref != NULL
 */

/*
 * void
 * isc_refcount_destroy(isc_refcount_t *ref);
 *
 * Destroys a reference counter.
 *
 * Requires:
 *      ref != NULL
 *      The number of references is 0.
 */

/*
 * void
 * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
 * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
 *
 * Increments the reference count, returning the new value in targetp if it's
 * not NULL.  The reference counter typically begins with the initial counter
 * of 1, and will be destroyed once the counter reaches 0.  Thus,
 * isc_refcount_increment() additionally requires the previous counter be
 * larger than 0 so that an error which violates the usage can be easily
 * caught.  isc_refcount_increment0() does not have this restriction.
 *
 * Requires:
 *      ref != NULL.
 */

/*
 * void
 * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
 *
 * Decrements the reference count,  returning the new value in targetp if it's
 * not NULL.
 *
 * Requires:
 *      ref != NULL.
 */

/*
 * Sample implementations
 */

typedef struct isc_refcount {
        int refs;
} isc_refcount_t;

#define isc_refcount_destroy(rp) ISC_REQUIRE((rp)->refs == 0)
#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))

#define isc_refcount_increment0(rp, tp)                                 \
        do {                                                            \
                unsigned int *_tmp = (unsigned int *)(tp);              \
                int _n = ++(rp)->refs;                                  \
                if (_tmp != NULL)                                       \
                        *_tmp = _n;                                     \
        } while (0)

#define isc_refcount_increment(rp, tp)                                  \
        do {                                                            \
                unsigned int *_tmp = (unsigned int *)(tp);              \
                int _n;                                                 \
                ISC_REQUIRE((rp)->refs > 0);                            \
                _n = ++(rp)->refs;                                      \
                if (_tmp != NULL)                                       \
                        *_tmp = _n;                                     \
        } while (0)

#define isc_refcount_decrement(rp, tp)                                  \
        do {                                                            \
                unsigned int *_tmp = (unsigned int *)(tp);              \
                int _n;                                                 \
                ISC_REQUIRE((rp)->refs > 0);                            \
                _n = --(rp)->refs;                                      \
                if (_tmp != NULL)                                       \
                        *_tmp = _n;                                     \
        } while (0)

isc_result_t
isc_refcount_init(isc_refcount_t *ref, unsigned int n);

#endif /* ISC_REFCOUNT_H */