kref.h revision 1.4.4.2 1 1.4.4.2 tls /* $NetBSD: kref.h,v 1.4.4.2 2014/08/20 00:04:21 tls Exp $ */
2 1.4.4.2 tls
3 1.4.4.2 tls /*-
4 1.4.4.2 tls * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 1.4.4.2 tls * All rights reserved.
6 1.4.4.2 tls *
7 1.4.4.2 tls * This code is derived from software contributed to The NetBSD Foundation
8 1.4.4.2 tls * by Taylor R. Campbell.
9 1.4.4.2 tls *
10 1.4.4.2 tls * Redistribution and use in source and binary forms, with or without
11 1.4.4.2 tls * modification, are permitted provided that the following conditions
12 1.4.4.2 tls * are met:
13 1.4.4.2 tls * 1. Redistributions of source code must retain the above copyright
14 1.4.4.2 tls * notice, this list of conditions and the following disclaimer.
15 1.4.4.2 tls * 2. Redistributions in binary form must reproduce the above copyright
16 1.4.4.2 tls * notice, this list of conditions and the following disclaimer in the
17 1.4.4.2 tls * documentation and/or other materials provided with the distribution.
18 1.4.4.2 tls *
19 1.4.4.2 tls * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.4.4.2 tls * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.4.4.2 tls * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.4.4.2 tls * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.4.4.2 tls * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.4.4.2 tls * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.4.4.2 tls * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.4.4.2 tls * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.4.4.2 tls * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.4.4.2 tls * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.4.4.2 tls * POSSIBILITY OF SUCH DAMAGE.
30 1.4.4.2 tls */
31 1.4.4.2 tls
32 1.4.4.2 tls #ifndef _LINUX_KREF_H_
33 1.4.4.2 tls #define _LINUX_KREF_H_
34 1.4.4.2 tls
35 1.4.4.2 tls #include <sys/types.h>
36 1.4.4.2 tls #include <sys/atomic.h>
37 1.4.4.2 tls #include <sys/systm.h>
38 1.4.4.2 tls
39 1.4.4.2 tls #include <linux/mutex.h>
40 1.4.4.2 tls
41 1.4.4.2 tls struct kref {
42 1.4.4.2 tls unsigned int kr_count;
43 1.4.4.2 tls };
44 1.4.4.2 tls
45 1.4.4.2 tls static inline void
46 1.4.4.2 tls kref_init(struct kref *kref)
47 1.4.4.2 tls {
48 1.4.4.2 tls kref->kr_count = 1;
49 1.4.4.2 tls }
50 1.4.4.2 tls
51 1.4.4.2 tls static inline void
52 1.4.4.2 tls kref_get(struct kref *kref)
53 1.4.4.2 tls {
54 1.4.4.2 tls const unsigned int count __unused =
55 1.4.4.2 tls atomic_inc_uint_nv(&kref->kr_count);
56 1.4.4.2 tls
57 1.4.4.2 tls KASSERTMSG((count > 1), "getting released kref");
58 1.4.4.2 tls }
59 1.4.4.2 tls
60 1.4.4.2 tls static inline bool
61 1.4.4.2 tls kref_get_unless_zero(struct kref *kref)
62 1.4.4.2 tls {
63 1.4.4.2 tls unsigned count;
64 1.4.4.2 tls
65 1.4.4.2 tls do {
66 1.4.4.2 tls count = kref->kr_count;
67 1.4.4.2 tls if ((count == 0) || (count == UINT_MAX))
68 1.4.4.2 tls return false;
69 1.4.4.2 tls } while (atomic_cas_uint(&kref->kr_count, count, (count + 1)) !=
70 1.4.4.2 tls count);
71 1.4.4.2 tls
72 1.4.4.2 tls return true;
73 1.4.4.2 tls }
74 1.4.4.2 tls
75 1.4.4.2 tls static inline int
76 1.4.4.2 tls kref_sub(struct kref *kref, unsigned int count, void (*release)(struct kref *))
77 1.4.4.2 tls {
78 1.4.4.2 tls unsigned int old, new;
79 1.4.4.2 tls
80 1.4.4.2 tls do {
81 1.4.4.2 tls old = kref->kr_count;
82 1.4.4.2 tls KASSERTMSG((count <= old), "overreleasing kref: %u - %u",
83 1.4.4.2 tls old, count);
84 1.4.4.2 tls new = (old - count);
85 1.4.4.2 tls } while (atomic_cas_uint(&kref->kr_count, old, new) != old);
86 1.4.4.2 tls
87 1.4.4.2 tls if (new == 0) {
88 1.4.4.2 tls (*release)(kref);
89 1.4.4.2 tls return 1;
90 1.4.4.2 tls }
91 1.4.4.2 tls
92 1.4.4.2 tls return 0;
93 1.4.4.2 tls }
94 1.4.4.2 tls
95 1.4.4.2 tls static inline int
96 1.4.4.2 tls kref_put(struct kref *kref, void (*release)(struct kref *))
97 1.4.4.2 tls {
98 1.4.4.2 tls
99 1.4.4.2 tls return kref_sub(kref, 1, release);
100 1.4.4.2 tls }
101 1.4.4.2 tls
102 1.4.4.2 tls static inline int
103 1.4.4.2 tls kref_put_mutex(struct kref *kref, void (*release)(struct kref *),
104 1.4.4.2 tls struct mutex *interlock)
105 1.4.4.2 tls {
106 1.4.4.2 tls unsigned int old, new;
107 1.4.4.2 tls
108 1.4.4.2 tls do {
109 1.4.4.2 tls old = kref->kr_count;
110 1.4.4.2 tls KASSERT(old > 0);
111 1.4.4.2 tls if (old == 1) {
112 1.4.4.2 tls mutex_lock(interlock);
113 1.4.4.2 tls if (atomic_add_int_nv(&kref->kr_count, -1) == 0) {
114 1.4.4.2 tls (*release)(kref);
115 1.4.4.2 tls return 1;
116 1.4.4.2 tls }
117 1.4.4.2 tls mutex_unlock(interlock);
118 1.4.4.2 tls return 0;
119 1.4.4.2 tls }
120 1.4.4.2 tls new = (old - 1);
121 1.4.4.2 tls } while (atomic_cas_uint(&kref->kr_count, old, new) != old);
122 1.4.4.2 tls
123 1.4.4.2 tls return 0;
124 1.4.4.2 tls }
125 1.4.4.2 tls
126 1.4.4.2 tls /*
127 1.4.4.2 tls * Not native to Linux. Mostly used for assertions...
128 1.4.4.2 tls */
129 1.4.4.2 tls
130 1.4.4.2 tls static inline bool
131 1.4.4.2 tls kref_referenced_p(struct kref *kref)
132 1.4.4.2 tls {
133 1.4.4.2 tls
134 1.4.4.2 tls return (0 < kref->kr_count);
135 1.4.4.2 tls }
136 1.4.4.2 tls
137 1.4.4.2 tls static inline bool
138 1.4.4.2 tls kref_exclusive_p(struct kref *kref)
139 1.4.4.2 tls {
140 1.4.4.2 tls
141 1.4.4.2 tls KASSERT(0 < kref->kr_count);
142 1.4.4.2 tls return (kref->kr_count == 1);
143 1.4.4.2 tls }
144 1.4.4.2 tls
145 1.4.4.2 tls #endif /* _LINUX_KREF_H_ */
146