xref: /openbsd/sys/dev/pci/drm/include/linux/kref.h (revision 4cfece93)
1 /*	$OpenBSD: kref.h,v 1.4 2020/06/17 02:58:15 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 <sys/atomic.h>
24 #include <linux/atomic.h>
25 #include <linux/compiler.h>
26 #include <linux/refcount.h>
27 
28 struct kref {
29 	uint32_t refcount;
30 };
31 
32 static inline void
33 kref_init(struct kref *ref)
34 {
35 	atomic_set(&ref->refcount, 1);
36 }
37 
38 static inline unsigned int
39 kref_read(const struct kref *ref)
40 {
41 	return atomic_read(&ref->refcount);
42 }
43 
44 static inline void
45 kref_get(struct kref *ref)
46 {
47 	atomic_inc_int(&ref->refcount);
48 }
49 
50 static inline int
51 kref_get_unless_zero(struct kref *ref)
52 {
53 	if (ref->refcount != 0) {
54 		atomic_inc_int(&ref->refcount);
55 		return (1);
56 	} else {
57 		return (0);
58 	}
59 }
60 
61 static inline int
62 kref_put(struct kref *ref, void (*release)(struct kref *ref))
63 {
64 	if (atomic_dec_int_nv(&ref->refcount) == 0) {
65 		release(ref);
66 		return 1;
67 	}
68 	return 0;
69 }
70 
71 static inline int
72 kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref),
73     struct rwlock *lock)
74 {
75 	if (!atomic_add_unless(&kref->refcount, -1, 1)) {
76 		rw_enter_write(lock);
77 		if (likely(atomic_dec_and_test(&kref->refcount))) {
78 			release(kref);
79 			return 1;
80 		}
81 		rw_exit_write(lock);
82 		return 0;
83 	}
84 
85 	return 0;
86 }
87 
88 static inline int
89 kref_put_lock(struct kref *kref, void (*release)(struct kref *kref),
90     struct mutex *lock)
91 {
92 	if (!atomic_add_unless(&kref->refcount, -1, 1)) {
93 		mtx_enter(lock);
94 		if (likely(atomic_dec_and_test(&kref->refcount))) {
95 			release(kref);
96 			return 1;
97 		}
98 		mtx_leave(lock);
99 		return 0;
100 	}
101 
102 	return 0;
103 }
104 
105 #endif
106