1 /* $OpenBSD: kref.h,v 1.6 2023/03/21 09:44:35 jsg Exp $ */
2 /*
3 * Copyright (c) 2015 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef _LINUX_KREF_H
19 #define _LINUX_KREF_H
20
21 #include <sys/types.h>
22 #include <sys/rwlock.h>
23 #include <linux/refcount.h>
24 #include <linux/spinlock.h>
25
26 struct kref {
27 uint32_t refcount;
28 };
29
30 static inline void
kref_init(struct kref * ref)31 kref_init(struct kref *ref)
32 {
33 atomic_set(&ref->refcount, 1);
34 }
35
36 static inline unsigned int
kref_read(const struct kref * ref)37 kref_read(const struct kref *ref)
38 {
39 return atomic_read(&ref->refcount);
40 }
41
42 static inline void
kref_get(struct kref * ref)43 kref_get(struct kref *ref)
44 {
45 atomic_inc_int(&ref->refcount);
46 }
47
48 static inline int
kref_get_unless_zero(struct kref * ref)49 kref_get_unless_zero(struct kref *ref)
50 {
51 if (ref->refcount != 0) {
52 atomic_inc_int(&ref->refcount);
53 return (1);
54 } else {
55 return (0);
56 }
57 }
58
59 static inline int
kref_put(struct kref * ref,void (* release)(struct kref * ref))60 kref_put(struct kref *ref, void (*release)(struct kref *ref))
61 {
62 if (atomic_dec_int_nv(&ref->refcount) == 0) {
63 release(ref);
64 return 1;
65 }
66 return 0;
67 }
68
69 static inline int
kref_put_mutex(struct kref * kref,void (* release)(struct kref * kref),struct rwlock * lock)70 kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref),
71 struct rwlock *lock)
72 {
73 if (!atomic_add_unless(&kref->refcount, -1, 1)) {
74 rw_enter_write(lock);
75 if (likely(atomic_dec_and_test(&kref->refcount))) {
76 release(kref);
77 return 1;
78 }
79 rw_exit_write(lock);
80 return 0;
81 }
82
83 return 0;
84 }
85
86 static inline int
kref_put_lock(struct kref * kref,void (* release)(struct kref * kref),struct mutex * lock)87 kref_put_lock(struct kref *kref, void (*release)(struct kref *kref),
88 struct mutex *lock)
89 {
90 if (!atomic_add_unless(&kref->refcount, -1, 1)) {
91 mtx_enter(lock);
92 if (likely(atomic_dec_and_test(&kref->refcount))) {
93 release(kref);
94 return 1;
95 }
96 mtx_leave(lock);
97 return 0;
98 }
99
100 return 0;
101 }
102
103 #endif
104