1150629Sjhb/*-
2150629Sjhb * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
3150629Sjhb *
4150629Sjhb * Redistribution and use in source and binary forms, with or without
5150629Sjhb * modification, are permitted provided that the following conditions
6150629Sjhb * are met:
7150629Sjhb * 1. Redistributions of source code must retain the above copyright
8150629Sjhb *    notice, this list of conditions and the following disclaimer.
9150629Sjhb * 2. Redistributions in binary form must reproduce the above copyright
10150629Sjhb *    notice, this list of conditions and the following disclaimer in the
11150629Sjhb *    documentation and/or other materials provided with the distribution.
12150629Sjhb *
13150629Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14150629Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15150629Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16150629Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17150629Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18150629Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19150629Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20150629Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21150629Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22150629Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23150629Sjhb * SUCH DAMAGE.
24150629Sjhb *
25150629Sjhb * $FreeBSD: stable/11/sys/sys/refcount.h 367457 2020-11-07 18:10:59Z dim $
26150629Sjhb */
27150629Sjhb
28150629Sjhb#ifndef __SYS_REFCOUNT_H__
29150629Sjhb#define __SYS_REFCOUNT_H__
30150629Sjhb
31238828Sglebius#include <sys/limits.h>
32180762Sdes#include <machine/atomic.h>
33180762Sdes
34180762Sdes#ifdef _KERNEL
35180762Sdes#include <sys/systm.h>
36180762Sdes#else
37180762Sdes#define	KASSERT(exp, msg)	/* */
38180762Sdes#endif
39180762Sdes
40150629Sjhbstatic __inline void
41150629Sjhbrefcount_init(volatile u_int *count, u_int value)
42150629Sjhb{
43150629Sjhb
44150629Sjhb	*count = value;
45150629Sjhb}
46150629Sjhb
47150629Sjhbstatic __inline void
48150629Sjhbrefcount_acquire(volatile u_int *count)
49150629Sjhb{
50150629Sjhb
51238828Sglebius	KASSERT(*count < UINT_MAX, ("refcount %p overflowed", count));
52320981Skib	atomic_add_int(count, 1);
53150629Sjhb}
54150629Sjhb
55150629Sjhbstatic __inline int
56150629Sjhbrefcount_release(volatile u_int *count)
57150629Sjhb{
58180762Sdes	u_int old;
59150629Sjhb
60320981Skib	atomic_thread_fence_rel();
61180762Sdes	old = atomic_fetchadd_int(count, -1);
62339862Shselasky	KASSERT(old > 0, ("refcount %p is zero", count));
63320981Skib	if (old > 1)
64320981Skib		return (0);
65320981Skib
66320981Skib	/*
67320981Skib	 * Last reference.  Signal the user to call the destructor.
68320981Skib	 *
69320981Skib	 * Ensure that the destructor sees all updates.  The fence_rel
70320981Skib	 * at the start of the function synchronized with this fence.
71320981Skib	 */
72320981Skib	atomic_thread_fence_acq();
73320981Skib	return (1);
74150629Sjhb}
75150629Sjhb
76332755Savg/*
77339862Shselasky * This functions returns non-zero if the refcount was
78339862Shselasky * incremented. Else zero is returned.
79339862Shselasky *
80332755Savg * A temporary hack until refcount_* APIs are sorted out.
81332755Savg */
82339862Shselaskystatic __inline __result_use_check int
83332755Savgrefcount_acquire_if_not_zero(volatile u_int *count)
84332755Savg{
85332755Savg	u_int old;
86332755Savg
87332755Savg	old = *count;
88332755Savg	for (;;) {
89339862Shselasky		KASSERT(old < UINT_MAX, ("refcount %p overflowed", count));
90332755Savg		if (old == 0)
91332755Savg			return (0);
92332755Savg		if (atomic_fcmpset_int(count, &old, old + 1))
93332755Savg			return (1);
94332755Savg	}
95332755Savg}
96332755Savg
97339862Shselaskystatic __inline __result_use_check int
98332755Savgrefcount_release_if_not_last(volatile u_int *count)
99332755Savg{
100332755Savg	u_int old;
101332755Savg
102332755Savg	old = *count;
103332755Savg	for (;;) {
104339862Shselasky		KASSERT(old > 0, ("refcount %p is zero", count));
105332755Savg		if (old == 1)
106332755Savg			return (0);
107332755Savg		if (atomic_fcmpset_int(count, &old, old - 1))
108332755Savg			return (1);
109332755Savg	}
110332755Savg}
111332755Savg
112150629Sjhb#endif	/* ! __SYS_REFCOUNT_H__ */
113