user/vmm: add and use a load_elf function
[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 #pragma once
14
15 #include <atomic.h>
16 #include <assert.h>
17
18 /* Current versions of Linux pass in 'release' on the kref_put() callsite to
19  * save on space in whatever struct these are embedded in.  We don't, since it's
20  * a little more complicated and we will probably change the release function a
21  * lot for subsystems in development. */
22 struct kref {
23         atomic_t refcount;
24         void (*release)(struct kref *kref);
25 };
26
27 /* Helper for some debugging situations */
28 static long kref_refcnt(struct kref *kref)
29 {
30         return atomic_read(&kref->refcount);
31 }
32
33 static void kref_init(struct kref *kref, void (*release)(struct kref *kref),
34                       unsigned int init)
35 {
36         assert(release);
37         atomic_init(&kref->refcount, init);
38         kref->release = release;
39 }
40
41 /* Will blindly incref */
42 static struct kref *__kref_get(struct kref *kref, unsigned int inc)
43 {
44         atomic_add(&kref->refcount, inc);
45         return kref;
46 }
47
48 /* Returns the kref ptr on success, 0 on failure */
49 static struct kref *kref_get_not_zero(struct kref *kref, unsigned int inc)
50 {
51         if (atomic_add_not_zero(&kref->refcount, inc))
52                 return kref;
53         else
54                 return 0;
55 }
56
57 /* Will panic on zero */
58 static struct kref *kref_get(struct kref *kref, unsigned int inc)
59 {
60         kref = kref_get_not_zero(kref, inc);
61         assert(kref);
62         return kref;
63 }
64
65 /* Returns True if we hit 0 and executed 'release', False otherwise */
66 static bool kref_put(struct kref *kref)
67 {
68         assert(kref_refcnt(kref) > 0);          /* catch some bugs */
69         if (atomic_sub_and_test(&kref->refcount, 1)) {
70                 kref->release(kref);
71                 return TRUE;
72         }
73         return FALSE;
74 }
75
76 /* Dev / debugging function to catch the attempted freeing of objects we don't
77  * know how to free yet. */
78 static void fake_release(struct kref *kref)
79 {
80         panic("Cleaning up this object is not supported!\n");
81 }