27fe63b6740c4e3d1012e375e256868d2e8ff6f4
[akaros.git] / kern / include / kref.h
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Kernel reference counting, based on Linux's kref:
6  * - http://www.kroah.com/linux/talks/ols_2004_kref_paper/
7  *          Reprint-Kroah-Hartman-OLS2004.pdf
8  * - http://lwn.net/Articles/336224/
9  * - Linux's Documentation/kref.txt
10  *
11  * See our Documentation/kref.txt for more info. */
12
13 #ifndef ROS_KERN_KREF_H
14 #define ROS_KERN_KREF_H
15
16 #include <atomic.h>
17 #include <assert.h>
18
19 /* Current versions of Linux pass in 'release' on the kref_put() callsite to
20  * save on space in whatever struct these are embedded in.  We don't, since it's
21  * a little more complicated and we will probably change the release function a
22  * lot for subsystems in development. */
23 struct kref {
24         atomic_t refcount;
25         void (*release)(struct kref *kref);
26 };
27
28 static void kref_init(struct kref *kref, void (*release)(struct kref *kref),
29                       unsigned int init)
30 {
31         assert(release);
32         atomic_init(&kref->refcount, init);
33         kref->release = release;
34 }
35
36 static struct kref *kref_get(struct kref *kref, unsigned int inc)
37 {
38         assert(atomic_read(&kref->refcount));
39         atomic_add(&kref->refcount, inc);
40         return kref;
41 }
42
43 /* Returns the kref ptr on success, 0 on failure */
44 static struct kref *kref_get_not_zero(struct kref *kref, unsigned int inc)
45 {
46         if (atomic_add_not_zero(&kref->refcount, inc))
47                 return kref;
48         else return 0;
49 }
50
51 /* Returns True if we hit 0 and executed 'release', False otherwise */
52 static bool kref_put(struct kref *kref)
53 {
54         assert(atomic_read(&kref->refcount) > 0);               /* catch some bugs */
55         if (atomic_sub_and_test(&kref->refcount, 1)) {
56                 kref->release(kref);
57                 return TRUE;
58         }
59         return FALSE;
60 }
61
62 #endif /* ROS_KERN_KREF_H */