Added krefs, used them for process refcounting
[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  * We differ a bit in that we currently ref count items that are on lists.  If
12  * an item is stored on a list, that counts as a reference.  No need to lock
13  * around kref_put, nor do you need to kref_get your list reference *if* you
14  * take the reference out of the list.  You need to kref_get() (if you want to
15  * use the reference later) before allowing someone else access to the list,
16  * which is still IAW Linux's style.  They might even do this for some lists. If
17  * we have lists that are unsynchronized where two threads can get references to
18  * the same item at the same time, then we'll need to lock to deal with that.
19  *
20  * We also allow incrementing by more than one, which helps in some cases.  We
21  * don't allow decrementing by more than one to catch bugs (for now).
22  *
23  * As far as usage goes, kref users don't make much of a distinction between
24  * internal and external references yet.
25  *
26  * kref rules (paraphrasing the linux ones):
27  * 1. If you pass a pointer somewhere or store it, kref_get() it first.  You can
28  * do this with no locking if you have a valid reference.
29  * 2. When you are done, kref_put() it.  You can usually do this without
30  * locking.
31  * 3. If you never kref_get without already holding a valid reference, you don't
32  * need to lock for Rule 2.  If you ever grab a reference without already having
33  * one, you need some form of sync to prevent a kref_put() from happening
34  * while you kref_get().
35  *
36  * The closest we get to mucking with it is with the proc hash table, though we
37  * don't require a lock on every proc kref_put().  If you're
38  * curious about these sorts of things, note how easy it is for a list where you
39  * are added or removed (like the runnable list) compared to a structure where
40  * we make a copy of the reference (like the pid2proc hash). */
41
42 #include <atomic.h>
43 #include <assert.h>
44
45 /* Current versions of Linux pass in 'release' on the kref_put() callsite to
46  * save on space in whatever struct these are embedded in.  We don't, since it's
47  * a little more complicated and we will probably change the release function a
48  * lot for subsystems in development. */
49 struct kref {
50         atomic_t refcount;
51         void (*release)(struct kref *kref);
52 };
53
54 static void kref_init(struct kref *kref, void (*release)(struct kref *kref),
55                       unsigned int init)
56 {
57         assert(release);
58         atomic_init(&kref->refcount, init);
59         kref->release = release;
60 }
61
62 static struct kref *kref_get(struct kref *kref, unsigned int inc)
63 {
64         assert(atomic_read(&kref->refcount));
65         atomic_add(&kref->refcount, inc);
66         return kref;
67 }
68
69 static void kref_put(struct kref *kref)
70 {
71         assert(atomic_read(&kref->refcount) > 0);               /* catch some bugs */
72         if (atomic_sub_and_test(&kref->refcount, 1))
73                 kref->release(kref);
74 }