1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968"><title>Exposing Objects Outside This File</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="Unreliable Guide To Locking"><link rel="up" href="Examples.html" title="Chapter&#160;7.&#160;Common Examples"><link rel="prev" href="examples-interrupt.html" title="Accessing From Interrupt Context"><link rel="next" href="examples-lock-per-obj.html" title="Protecting The Objects Themselves"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Exposing Objects Outside This File</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="examples-interrupt.html">Prev</a>&#160;</td><th width="60%" align="center">Chapter&#160;7.&#160;Common Examples</th><td width="20%" align="right">&#160;<a accesskey="n" href="examples-lock-per-obj.html">Next</a></td></tr></table><hr></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="examples-refcnt"></a>Exposing Objects Outside This File</h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="examples-refcnt.html#examples-refcnt-atomic">Using Atomic Operations For The Reference Count</a></span></dt></dl></div><p>
2If our objects contained more information, it might not be sufficient
3to copy the information in and out: other parts of the code might want
4to keep pointers to these objects, for example, rather than looking up
5the id every time.  This produces two problems.
6    </p><p>
7The first problem is that we use the <span class="symbol">cache_lock</span> to
8protect objects: we'd need to make this non-static so the rest of the
9code can use it.  This makes locking trickier, as it is no longer all
10in one place.
11    </p><p>
12The second problem is the lifetime problem: if another structure keeps
13a pointer to an object, it presumably expects that pointer to remain
14valid.  Unfortunately, this is only guaranteed while you hold the
15lock, otherwise someone might call <code class="function">cache_delete</code>
16and even worse, add another object, re-using the same address.
17    </p><p>
18As there is only one lock, you can't hold it forever: no-one else would
19get any work done.
20    </p><p>
21The solution to this problem is to use a reference count: everyone who
22has a pointer to the object increases it when they first get the
23object, and drops the reference count when they're finished with it.
24Whoever drops it to zero knows it is unused, and can actually delete it.
25    </p><p>
26Here is the code:
27    </p><pre class="programlisting">
28--- cache.c.interrupt	2003-12-09 14:25:43.000000000 +1100
29+++ cache.c.refcnt	2003-12-09 14:33:05.000000000 +1100
30@@ -7,6 +7,7 @@
31 struct object
32 {
33         struct list_head list;
34+        unsigned int refcnt;
35         int id;
36         char name[32];
37         int popularity;
38@@ -17,6 +18,35 @@
39 static unsigned int cache_num = 0;
40 #define MAX_CACHE_SIZE 10
41
42+static void __object_put(struct object *obj)
43+{
44+        if (--obj-&gt;refcnt == 0)
45+                kfree(obj);
46+}
47+
48+static void __object_get(struct object *obj)
49+{
50+        obj-&gt;refcnt++;
51+}
52+
53+void object_put(struct object *obj)
54+{
55+        unsigned long flags;
56+
57+        spin_lock_irqsave(&amp;cache_lock, flags);
58+        __object_put(obj);
59+        spin_unlock_irqrestore(&amp;cache_lock, flags);
60+}
61+
62+void object_get(struct object *obj)
63+{
64+        unsigned long flags;
65+
66+        spin_lock_irqsave(&amp;cache_lock, flags);
67+        __object_get(obj);
68+        spin_unlock_irqrestore(&amp;cache_lock, flags);
69+}
70+
71 /* Must be holding cache_lock */
72 static struct object *__cache_find(int id)
73 {
74@@ -35,6 +65,7 @@
75 {
76         BUG_ON(!obj);
77         list_del(&amp;obj-&gt;list);
78+        __object_put(obj);
79         cache_num--;
80 }
81
82@@ -63,6 +94,7 @@
83         strlcpy(obj-&gt;name, name, sizeof(obj-&gt;name));
84         obj-&gt;id = id;
85         obj-&gt;popularity = 0;
86+        obj-&gt;refcnt = 1; /* The cache holds a reference */
87
88         spin_lock_irqsave(&amp;cache_lock, flags);
89         __cache_add(obj);
90@@ -79,18 +111,15 @@
91         spin_unlock_irqrestore(&amp;cache_lock, flags);
92 }
93
94-int cache_find(int id, char *name)
95+struct object *cache_find(int id)
96 {
97         struct object *obj;
98-        int ret = -ENOENT;
99         unsigned long flags;
100
101         spin_lock_irqsave(&amp;cache_lock, flags);
102         obj = __cache_find(id);
103-        if (obj) {
104-                ret = 0;
105-                strcpy(name, obj-&gt;name);
106-        }
107+        if (obj)
108+                __object_get(obj);
109         spin_unlock_irqrestore(&amp;cache_lock, flags);
110-        return ret;
111+        return obj;
112 }
113</pre><p>
114We encapsulate the reference counting in the standard 'get' and 'put'
115functions.  Now we can return the object itself from
116<code class="function">cache_find</code> which has the advantage that the user
117can now sleep holding the object (eg. to
118<code class="function">copy_to_user</code> to name to userspace).
119</p><p>
120The other point to note is that I said a reference should be held for
121every pointer to the object: thus the reference count is 1 when first
122inserted into the cache.  In some versions the framework does not hold
123a reference count, but they are more complicated.
124</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="examples-refcnt-atomic"></a>Using Atomic Operations For The Reference Count</h3></div></div></div><p>
125In practice, <span class="type">atomic_t</span> would usually be used for
126<em class="structfield"><code>refcnt</code></em>.  There are a number of atomic
127operations defined in
128
129<code class="filename">include/asm/atomic.h</code>: these are
130guaranteed to be seen atomically from all CPUs in the system, so no
131lock is required.  In this case, it is simpler than using spinlocks,
132although for anything non-trivial using spinlocks is clearer.  The
133<code class="function">atomic_inc</code> and
134<code class="function">atomic_dec_and_test</code> are used instead of the
135standard increment and decrement operators, and the lock is no longer
136used to protect the reference count itself.
137</p><pre class="programlisting">
138--- cache.c.refcnt	2003-12-09 15:00:35.000000000 +1100
139+++ cache.c.refcnt-atomic	2003-12-11 15:49:42.000000000 +1100
140@@ -7,7 +7,7 @@
141 struct object
142 {
143         struct list_head list;
144-        unsigned int refcnt;
145+        atomic_t refcnt;
146         int id;
147         char name[32];
148         int popularity;
149@@ -18,33 +18,15 @@
150 static unsigned int cache_num = 0;
151 #define MAX_CACHE_SIZE 10
152
153-static void __object_put(struct object *obj)
154-{
155-        if (--obj-&gt;refcnt == 0)
156-                kfree(obj);
157-}
158-
159-static void __object_get(struct object *obj)
160-{
161-        obj-&gt;refcnt++;
162-}
163-
164 void object_put(struct object *obj)
165 {
166-        unsigned long flags;
167-
168-        spin_lock_irqsave(&amp;cache_lock, flags);
169-        __object_put(obj);
170-        spin_unlock_irqrestore(&amp;cache_lock, flags);
171+        if (atomic_dec_and_test(&amp;obj-&gt;refcnt))
172+                kfree(obj);
173 }
174
175 void object_get(struct object *obj)
176 {
177-        unsigned long flags;
178-
179-        spin_lock_irqsave(&amp;cache_lock, flags);
180-        __object_get(obj);
181-        spin_unlock_irqrestore(&amp;cache_lock, flags);
182+        atomic_inc(&amp;obj-&gt;refcnt);
183 }
184
185 /* Must be holding cache_lock */
186@@ -65,7 +47,7 @@
187 {
188         BUG_ON(!obj);
189         list_del(&amp;obj-&gt;list);
190-        __object_put(obj);
191+        object_put(obj);
192         cache_num--;
193 }
194
195@@ -94,7 +76,7 @@
196         strlcpy(obj-&gt;name, name, sizeof(obj-&gt;name));
197         obj-&gt;id = id;
198         obj-&gt;popularity = 0;
199-        obj-&gt;refcnt = 1; /* The cache holds a reference */
200+        atomic_set(&amp;obj-&gt;refcnt, 1); /* The cache holds a reference */
201
202         spin_lock_irqsave(&amp;cache_lock, flags);
203         __cache_add(obj);
204@@ -119,7 +101,7 @@
205         spin_lock_irqsave(&amp;cache_lock, flags);
206         obj = __cache_find(id);
207         if (obj)
208-                __object_get(obj);
209+                object_get(obj);
210         spin_unlock_irqrestore(&amp;cache_lock, flags);
211         return obj;
212 }
213</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="examples-interrupt.html">Prev</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="Examples.html">Up</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="examples-lock-per-obj.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Accessing From Interrupt Context&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&#160;Protecting The Objects Themselves</td></tr></table></div></body></html>
214