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