xref: /freebsd/sys/sys/refcount.h (revision 13ff4eb1)
1d6fe50b6SJohn Baldwin /*-
2c4e20cadSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3c4e20cadSPedro F. Giffuni  *
4d6fe50b6SJohn Baldwin  * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
5d6fe50b6SJohn Baldwin  *
6d6fe50b6SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
7d6fe50b6SJohn Baldwin  * modification, are permitted provided that the following conditions
8d6fe50b6SJohn Baldwin  * are met:
9d6fe50b6SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
10d6fe50b6SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
11d6fe50b6SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
12d6fe50b6SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
13d6fe50b6SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
14d6fe50b6SJohn Baldwin  *
15d6fe50b6SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d6fe50b6SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d6fe50b6SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d6fe50b6SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d6fe50b6SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d6fe50b6SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d6fe50b6SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d6fe50b6SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d6fe50b6SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d6fe50b6SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d6fe50b6SJohn Baldwin  * SUCH DAMAGE.
26d6fe50b6SJohn Baldwin  *
27d6fe50b6SJohn Baldwin  * $FreeBSD$
28d6fe50b6SJohn Baldwin  */
29d6fe50b6SJohn Baldwin 
30d6fe50b6SJohn Baldwin #ifndef __SYS_REFCOUNT_H__
31d6fe50b6SJohn Baldwin #define __SYS_REFCOUNT_H__
32d6fe50b6SJohn Baldwin 
33be6ab406SGleb Smirnoff #include <sys/limits.h>
3475f31a5fSDag-Erling Smørgrav #include <machine/atomic.h>
3575f31a5fSDag-Erling Smørgrav 
3675f31a5fSDag-Erling Smørgrav #ifdef _KERNEL
3775f31a5fSDag-Erling Smørgrav #include <sys/systm.h>
3875f31a5fSDag-Erling Smørgrav #else
3910040398SKonstantin Belousov #include <stdbool.h>
4075f31a5fSDag-Erling Smørgrav #define	KASSERT(exp, msg)	/* */
4175f31a5fSDag-Erling Smørgrav #endif
4275f31a5fSDag-Erling Smørgrav 
43d6fe50b6SJohn Baldwin static __inline void
44d6fe50b6SJohn Baldwin refcount_init(volatile u_int *count, u_int value)
45d6fe50b6SJohn Baldwin {
46d6fe50b6SJohn Baldwin 
47d6fe50b6SJohn Baldwin 	*count = value;
48d6fe50b6SJohn Baldwin }
49d6fe50b6SJohn Baldwin 
50d6fe50b6SJohn Baldwin static __inline void
51d6fe50b6SJohn Baldwin refcount_acquire(volatile u_int *count)
52d6fe50b6SJohn Baldwin {
53d6fe50b6SJohn Baldwin 
54be6ab406SGleb Smirnoff 	KASSERT(*count < UINT_MAX, ("refcount %p overflowed", count));
55157d5e6dSKonstantin Belousov 	atomic_add_int(count, 1);
56d6fe50b6SJohn Baldwin }
57d6fe50b6SJohn Baldwin 
58f1cf2b9dSKonstantin Belousov static __inline __result_use_check bool
59f1cf2b9dSKonstantin Belousov refcount_acquire_checked(volatile u_int *count)
60f1cf2b9dSKonstantin Belousov {
61f1cf2b9dSKonstantin Belousov 	u_int lcount;
62f1cf2b9dSKonstantin Belousov 
63f1cf2b9dSKonstantin Belousov 	for (lcount = *count;;) {
64f1cf2b9dSKonstantin Belousov 		if (__predict_false(lcount + 1 < lcount))
65f1cf2b9dSKonstantin Belousov 			return (false);
66f1cf2b9dSKonstantin Belousov 		if (__predict_true(atomic_fcmpset_int(count, &lcount,
67f1cf2b9dSKonstantin Belousov 		    lcount + 1) == 1))
68f1cf2b9dSKonstantin Belousov 			return (true);
69f1cf2b9dSKonstantin Belousov 	}
70f1cf2b9dSKonstantin Belousov }
71f1cf2b9dSKonstantin Belousov 
7213ff4eb1SKonstantin Belousov static __inline bool
73d6fe50b6SJohn Baldwin refcount_release(volatile u_int *count)
74d6fe50b6SJohn Baldwin {
7575f31a5fSDag-Erling Smørgrav 	u_int old;
76d6fe50b6SJohn Baldwin 
77157d5e6dSKonstantin Belousov 	atomic_thread_fence_rel();
7875f31a5fSDag-Erling Smørgrav 	old = atomic_fetchadd_int(count, -1);
79127a9d73SHans Petter Selasky 	KASSERT(old > 0, ("refcount %p is zero", count));
80157d5e6dSKonstantin Belousov 	if (old > 1)
8113ff4eb1SKonstantin Belousov 		return (false);
82157d5e6dSKonstantin Belousov 
83157d5e6dSKonstantin Belousov 	/*
84157d5e6dSKonstantin Belousov 	 * Last reference.  Signal the user to call the destructor.
85157d5e6dSKonstantin Belousov 	 *
86157d5e6dSKonstantin Belousov 	 * Ensure that the destructor sees all updates.  The fence_rel
87157d5e6dSKonstantin Belousov 	 * at the start of the function synchronized with this fence.
88157d5e6dSKonstantin Belousov 	 */
89157d5e6dSKonstantin Belousov 	atomic_thread_fence_acq();
9013ff4eb1SKonstantin Belousov 	return (true);
91d6fe50b6SJohn Baldwin }
92d6fe50b6SJohn Baldwin 
93f4043145SAndriy Gapon /*
94127a9d73SHans Petter Selasky  * This functions returns non-zero if the refcount was
95127a9d73SHans Petter Selasky  * incremented. Else zero is returned.
96f4043145SAndriy Gapon  */
9713ff4eb1SKonstantin Belousov static __inline __result_use_check bool
98f4043145SAndriy Gapon refcount_acquire_if_not_zero(volatile u_int *count)
99f4043145SAndriy Gapon {
100f4043145SAndriy Gapon 	u_int old;
101f4043145SAndriy Gapon 
102f4043145SAndriy Gapon 	old = *count;
103f4043145SAndriy Gapon 	for (;;) {
104127a9d73SHans Petter Selasky 		KASSERT(old < UINT_MAX, ("refcount %p overflowed", count));
105f4043145SAndriy Gapon 		if (old == 0)
10613ff4eb1SKonstantin Belousov 			return (false);
107f4043145SAndriy Gapon 		if (atomic_fcmpset_int(count, &old, old + 1))
10813ff4eb1SKonstantin Belousov 			return (true);
109f4043145SAndriy Gapon 	}
110f4043145SAndriy Gapon }
111f4043145SAndriy Gapon 
11213ff4eb1SKonstantin Belousov static __inline __result_use_check bool
113f4043145SAndriy Gapon refcount_release_if_not_last(volatile u_int *count)
114f4043145SAndriy Gapon {
115f4043145SAndriy Gapon 	u_int old;
116f4043145SAndriy Gapon 
117f4043145SAndriy Gapon 	old = *count;
118f4043145SAndriy Gapon 	for (;;) {
119127a9d73SHans Petter Selasky 		KASSERT(old > 0, ("refcount %p is zero", count));
120f4043145SAndriy Gapon 		if (old == 1)
12113ff4eb1SKonstantin Belousov 			return (false);
122f4043145SAndriy Gapon 		if (atomic_fcmpset_int(count, &old, old - 1))
12313ff4eb1SKonstantin Belousov 			return (true);
124f4043145SAndriy Gapon 	}
125f4043145SAndriy Gapon }
126f4043145SAndriy Gapon 
127d6fe50b6SJohn Baldwin #endif	/* ! __SYS_REFCOUNT_H__ */
128