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 7. 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> </td><th width="60%" align="center">Chapter 7. Common Examples</th><td width="20%" align="right"> <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->refcnt == 0) 45+ kfree(obj); 46+} 47+ 48+static void __object_get(struct object *obj) 49+{ 50+ obj->refcnt++; 51+} 52+ 53+void object_put(struct object *obj) 54+{ 55+ unsigned long flags; 56+ 57+ spin_lock_irqsave(&cache_lock, flags); 58+ __object_put(obj); 59+ spin_unlock_irqrestore(&cache_lock, flags); 60+} 61+ 62+void object_get(struct object *obj) 63+{ 64+ unsigned long flags; 65+ 66+ spin_lock_irqsave(&cache_lock, flags); 67+ __object_get(obj); 68+ spin_unlock_irqrestore(&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(&obj->list); 78+ __object_put(obj); 79 cache_num--; 80 } 81 82@@ -63,6 +94,7 @@ 83 strlcpy(obj->name, name, sizeof(obj->name)); 84 obj->id = id; 85 obj->popularity = 0; 86+ obj->refcnt = 1; /* The cache holds a reference */ 87 88 spin_lock_irqsave(&cache_lock, flags); 89 __cache_add(obj); 90@@ -79,18 +111,15 @@ 91 spin_unlock_irqrestore(&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(&cache_lock, flags); 102 obj = __cache_find(id); 103- if (obj) { 104- ret = 0; 105- strcpy(name, obj->name); 106- } 107+ if (obj) 108+ __object_get(obj); 109 spin_unlock_irqrestore(&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->refcnt == 0) 156- kfree(obj); 157-} 158- 159-static void __object_get(struct object *obj) 160-{ 161- obj->refcnt++; 162-} 163- 164 void object_put(struct object *obj) 165 { 166- unsigned long flags; 167- 168- spin_lock_irqsave(&cache_lock, flags); 169- __object_put(obj); 170- spin_unlock_irqrestore(&cache_lock, flags); 171+ if (atomic_dec_and_test(&obj->refcnt)) 172+ kfree(obj); 173 } 174 175 void object_get(struct object *obj) 176 { 177- unsigned long flags; 178- 179- spin_lock_irqsave(&cache_lock, flags); 180- __object_get(obj); 181- spin_unlock_irqrestore(&cache_lock, flags); 182+ atomic_inc(&obj->refcnt); 183 } 184 185 /* Must be holding cache_lock */ 186@@ -65,7 +47,7 @@ 187 { 188 BUG_ON(!obj); 189 list_del(&obj->list); 190- __object_put(obj); 191+ object_put(obj); 192 cache_num--; 193 } 194 195@@ -94,7 +76,7 @@ 196 strlcpy(obj->name, name, sizeof(obj->name)); 197 obj->id = id; 198 obj->popularity = 0; 199- obj->refcnt = 1; /* The cache holds a reference */ 200+ atomic_set(&obj->refcnt, 1); /* The cache holds a reference */ 201 202 spin_lock_irqsave(&cache_lock, flags); 203 __cache_add(obj); 204@@ -119,7 +101,7 @@ 205 spin_lock_irqsave(&cache_lock, flags); 206 obj = __cache_find(id); 207 if (obj) 208- __object_get(obj); 209+ object_get(obj); 210 spin_unlock_irqrestore(&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> </td><td width="20%" align="center"><a accesskey="u" href="Examples.html">Up</a></td><td width="40%" align="right"> <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 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Protecting The Objects Themselves</td></tr></table></div></body></html> 214