1d54cfbdroberto/*
2047f369cy * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3d54cfbdroberto * Copyright (C) 2001, 2003  Internet Software Consortium.
4d54cfbdroberto *
5d54cfbdroberto * Permission to use, copy, modify, and/or distribute this software for any
6d54cfbdroberto * purpose with or without fee is hereby granted, provided that the above
7d54cfbdroberto * copyright notice and this permission notice appear in all copies.
8d54cfbdroberto *
9d54cfbdroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10d54cfbdroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11d54cfbdroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12d54cfbdroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13d54cfbdroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14d54cfbdroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15d54cfbdroberto * PERFORMANCE OF THIS SOFTWARE.
16d54cfbdroberto */
17d54cfbdroberto
18047f369cy/* $Id: refcount.h,v 1.17 2009/09/29 23:48:04 tbox Exp $ */
19d54cfbdroberto
20d54cfbdroberto#ifndef ISC_REFCOUNT_H
21d54cfbdroberto#define ISC_REFCOUNT_H 1
22d54cfbdroberto
23d54cfbdroberto#include <isc/atomic.h>
24d54cfbdroberto#include <isc/lang.h>
25d54cfbdroberto#include <isc/mutex.h>
26d54cfbdroberto#include <isc/platform.h>
27d54cfbdroberto#include <isc/types.h>
28d54cfbdroberto#include <isc/util.h>
29d54cfbdroberto
30d54cfbdroberto/*! \file isc/refcount.h
31047f369cy * \brief Implements a locked reference counter.
32d54cfbdroberto *
33d54cfbdroberto * These functions may actually be
34d54cfbdroberto * implemented using macros, and implementations of these macros are below.
35d54cfbdroberto * The isc_refcount_t type should not be accessed directly, as its contents
36d54cfbdroberto * depend on the implementation.
37d54cfbdroberto */
38d54cfbdroberto
39d54cfbdrobertoISC_LANG_BEGINDECLS
40d54cfbdroberto
41d54cfbdroberto/*
42d54cfbdroberto * Function prototypes
43d54cfbdroberto */
44d54cfbdroberto
45047f369cy/*
46d54cfbdroberto * isc_result_t
47d54cfbdroberto * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
48d54cfbdroberto *
49d54cfbdroberto * Initialize the reference counter.  There will be 'n' initial references.
50d54cfbdroberto *
51d54cfbdroberto * Requires:
52d54cfbdroberto *	ref != NULL
53d54cfbdroberto */
54d54cfbdroberto
55d54cfbdroberto/*
56d54cfbdroberto * void
57d54cfbdroberto * isc_refcount_destroy(isc_refcount_t *ref);
58d54cfbdroberto *
59d54cfbdroberto * Destroys a reference counter.
60d54cfbdroberto *
61d54cfbdroberto * Requires:
62d54cfbdroberto *	ref != NULL
63d54cfbdroberto *	The number of references is 0.
64d54cfbdroberto */
65d54cfbdroberto
66d54cfbdroberto/*
67d54cfbdroberto * void
68d54cfbdroberto * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
69d54cfbdroberto * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
70d54cfbdroberto *
71d54cfbdroberto * Increments the reference count, returning the new value in targetp if it's
72d54cfbdroberto * not NULL.  The reference counter typically begins with the initial counter
73d54cfbdroberto * of 1, and will be destroyed once the counter reaches 0.  Thus,
74d54cfbdroberto * isc_refcount_increment() additionally requires the previous counter be
75d54cfbdroberto * larger than 0 so that an error which violates the usage can be easily
76d54cfbdroberto * caught.  isc_refcount_increment0() does not have this restriction.
77d54cfbdroberto *
78d54cfbdroberto * Requires:
79d54cfbdroberto *	ref != NULL.
80d54cfbdroberto */
81d54cfbdroberto
82d54cfbdroberto/*
83d54cfbdroberto * void
84d54cfbdroberto * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
85d54cfbdroberto *
86d54cfbdroberto * Decrements the reference count,  returning the new value in targetp if it's
87d54cfbdroberto * not NULL.
88d54cfbdroberto *
89d54cfbdroberto * Requires:
90d54cfbdroberto *	ref != NULL.
91d54cfbdroberto */
92d54cfbdroberto
93d54cfbdroberto
94d54cfbdroberto/*
95d54cfbdroberto * Sample implementations
96d54cfbdroberto */
97d54cfbdroberto#ifdef ISC_PLATFORM_USETHREADS
98d54cfbdroberto#ifdef ISC_PLATFORM_HAVEXADD
99d54cfbdroberto
100d54cfbdroberto#define ISC_REFCOUNT_HAVEATOMIC 1
101d54cfbdroberto
102d54cfbdrobertotypedef struct isc_refcount {
103d54cfbdroberto	isc_int32_t refs;
104d54cfbdroberto} isc_refcount_t;
105d54cfbdroberto
106047f369cy#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
107d54cfbdroberto#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
108d54cfbdroberto
109d54cfbdroberto#define isc_refcount_increment0(rp, tp)				\
110d54cfbdroberto	do {							\
111d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
112d54cfbdroberto		isc_int32_t prev;				\
113d54cfbdroberto		prev = isc_atomic_xadd(&(rp)->refs, 1);		\
114d54cfbdroberto		if (_tmp != NULL)				\
115d54cfbdroberto			*_tmp = prev + 1;			\
116d54cfbdroberto	} while (0)
117d54cfbdroberto
118d54cfbdroberto#define isc_refcount_increment(rp, tp)				\
119d54cfbdroberto	do {							\
120d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
121d54cfbdroberto		isc_int32_t prev;				\
122d54cfbdroberto		prev = isc_atomic_xadd(&(rp)->refs, 1);		\
123d54cfbdroberto		REQUIRE(prev > 0);				\
124d54cfbdroberto		if (_tmp != NULL)				\
125d54cfbdroberto			*_tmp = prev + 1;			\
126d54cfbdroberto	} while (0)
127d54cfbdroberto
128d54cfbdroberto#define isc_refcount_decrement(rp, tp)				\
129d54cfbdroberto	do {							\
130d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
131d54cfbdroberto		isc_int32_t prev;				\
132d54cfbdroberto		prev = isc_atomic_xadd(&(rp)->refs, -1);	\
133d54cfbdroberto		REQUIRE(prev > 0);				\
134d54cfbdroberto		if (_tmp != NULL)				\
135d54cfbdroberto			*_tmp = prev - 1;			\
136d54cfbdroberto	} while (0)
137d54cfbdroberto
138d54cfbdroberto#else  /* ISC_PLATFORM_HAVEXADD */
139d54cfbdroberto
140d54cfbdrobertotypedef struct isc_refcount {
141d54cfbdroberto	int refs;
142d54cfbdroberto	isc_mutex_t lock;
143d54cfbdroberto} isc_refcount_t;
144d54cfbdroberto
145d54cfbdroberto/*% Destroys a reference counter. */
146d54cfbdroberto#define isc_refcount_destroy(rp)			\
147d54cfbdroberto	do {						\
148d54cfbdroberto		REQUIRE((rp)->refs == 0);		\
149d54cfbdroberto		DESTROYLOCK(&(rp)->lock);		\
150d54cfbdroberto	} while (0)
151d54cfbdroberto
152d54cfbdroberto#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
153d54cfbdroberto
154d54cfbdroberto/*% Increments the reference count, returning the new value in targetp if it's not NULL. */
155d54cfbdroberto#define isc_refcount_increment0(rp, tp)				\
156d54cfbdroberto	do {							\
157d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
158d54cfbdroberto		LOCK(&(rp)->lock);				\
159d54cfbdroberto		++((rp)->refs);					\
160d54cfbdroberto		if (_tmp != NULL)				\
161d54cfbdroberto			*_tmp = ((rp)->refs);			\
162d54cfbdroberto		UNLOCK(&(rp)->lock);				\
163d54cfbdroberto	} while (0)
164d54cfbdroberto
165d54cfbdroberto#define isc_refcount_increment(rp, tp)				\
166d54cfbdroberto	do {							\
167d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
168d54cfbdroberto		LOCK(&(rp)->lock);				\
169d54cfbdroberto		REQUIRE((rp)->refs > 0);			\
170d54cfbdroberto		++((rp)->refs);					\
171d54cfbdroberto		if (_tmp != NULL)				\
172d54cfbdroberto			*_tmp = ((rp)->refs);			\
173d54cfbdroberto		UNLOCK(&(rp)->lock);				\
174d54cfbdroberto	} while (0)
175d54cfbdroberto
176d54cfbdroberto/*% Decrements the reference count,  returning the new value in targetp if it's not NULL. */
177d54cfbdroberto#define isc_refcount_decrement(rp, tp)				\
178d54cfbdroberto	do {							\
179d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);	\
180d54cfbdroberto		LOCK(&(rp)->lock);				\
181d54cfbdroberto		REQUIRE((rp)->refs > 0);			\
182d54cfbdroberto		--((rp)->refs);					\
183d54cfbdroberto		if (_tmp != NULL)				\
184d54cfbdroberto			*_tmp = ((rp)->refs);			\
185d54cfbdroberto		UNLOCK(&(rp)->lock);				\
186d54cfbdroberto	} while (0)
187d54cfbdroberto
188d54cfbdroberto#endif /* ISC_PLATFORM_HAVEXADD */
189d54cfbdroberto#else  /* ISC_PLATFORM_USETHREADS */
190d54cfbdroberto
191d54cfbdrobertotypedef struct isc_refcount {
192d54cfbdroberto	int refs;
193d54cfbdroberto} isc_refcount_t;
194d54cfbdroberto
195047f369cy#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0)
196d54cfbdroberto#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
197d54cfbdroberto
198d54cfbdroberto#define isc_refcount_increment0(rp, tp)					\
199d54cfbdroberto	do {								\
200d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);		\
201d54cfbdroberto		int _n = ++(rp)->refs;					\
202d54cfbdroberto		if (_tmp != NULL)					\
203d54cfbdroberto			*_tmp = _n;					\
204d54cfbdroberto	} while (0)
205d54cfbdroberto
206d54cfbdroberto#define isc_refcount_increment(rp, tp)					\
207d54cfbdroberto	do {								\
208d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);		\
209d54cfbdroberto		int _n;							\
210d54cfbdroberto		REQUIRE((rp)->refs > 0);				\
211d54cfbdroberto		_n = ++(rp)->refs;					\
212d54cfbdroberto		if (_tmp != NULL)					\
213d54cfbdroberto			*_tmp = _n;					\
214d54cfbdroberto	} while (0)
215d54cfbdroberto
216d54cfbdroberto#define isc_refcount_decrement(rp, tp)					\
217d54cfbdroberto	do {								\
218d54cfbdroberto		unsigned int *_tmp = (unsigned int *)(tp);		\
219d54cfbdroberto		int _n;							\
220d54cfbdroberto		REQUIRE((rp)->refs > 0);				\
221d54cfbdroberto		_n = --(rp)->refs;					\
222d54cfbdroberto		if (_tmp != NULL)					\
223d54cfbdroberto			*_tmp = _n;					\
224d54cfbdroberto	} while (0)
225d54cfbdroberto
226d54cfbdroberto#endif /* ISC_PLATFORM_USETHREADS */
227d54cfbdroberto
228d54cfbdrobertoisc_result_t
229d54cfbdrobertoisc_refcount_init(isc_refcount_t *ref, unsigned int n);
230d54cfbdroberto
231d54cfbdrobertoISC_LANG_ENDDECLS
232d54cfbdroberto
233d54cfbdroberto#endif /* ISC_REFCOUNT_H */
234