xref: /openbsd/sys/dev/pci/drm/include/linux/kref.h (revision 53e1df33)
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