1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968"><title>Chapter 7. Common Examples</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="index.html" title="Unreliable Guide To Locking"><link rel="prev" href="trylock-functions.html" title="Chapter 6. The trylock Functions"><link rel="next" href="examples-interrupt.html" title="Accessing From Interrupt Context"></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">Chapter 7. Common Examples</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="trylock-functions.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="examples-interrupt.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="Examples"></a>Chapter 7. Common Examples</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="sect1"><a href="Examples.html#examples-usercontext">All In User Context</a></span></dt><dt><span class="sect1"><a href="examples-interrupt.html">Accessing From Interrupt Context</a></span></dt><dt><span class="sect1"><a href="examples-refcnt.html">Exposing Objects Outside This File</a></span></dt><dd><dl><dt><span class="sect2"><a href="examples-refcnt.html#examples-refcnt-atomic">Using Atomic Operations For The Reference Count</a></span></dt></dl></dd><dt><span class="sect1"><a href="examples-lock-per-obj.html">Protecting The Objects Themselves</a></span></dt></dl></div><p> 2Let's step through a simple example: a cache of number to name 3mappings. The cache keeps a count of how often each of the objects is 4used, and when it gets full, throws out the least used one. 5 6 </p><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="examples-usercontext"></a>All In User Context</h2></div></div></div><p> 7For our first example, we assume that all operations are in user 8context (ie. from system calls), so we can sleep. This means we can 9use a mutex to protect the cache and all the objects within 10it. Here's the code: 11 </p><pre class="programlisting"> 12#include <linux/list.h> 13#include <linux/slab.h> 14#include <linux/string.h> 15#include <linux/mutex.h> 16#include <asm/errno.h> 17 18struct object 19{ 20 struct list_head list; 21 int id; 22 char name[32]; 23 int popularity; 24}; 25 26/* Protects the cache, cache_num, and the objects within it */ 27static DEFINE_MUTEX(cache_lock); 28static LIST_HEAD(cache); 29static unsigned int cache_num = 0; 30#define MAX_CACHE_SIZE 10 31 32/* Must be holding cache_lock */ 33static struct object *__cache_find(int id) 34{ 35 struct object *i; 36 37 list_for_each_entry(i, &cache, list) 38 if (i->id == id) { 39 i->popularity++; 40 return i; 41 } 42 return NULL; 43} 44 45/* Must be holding cache_lock */ 46static void __cache_delete(struct object *obj) 47{ 48 BUG_ON(!obj); 49 list_del(&obj->list); 50 kfree(obj); 51 cache_num--; 52} 53 54/* Must be holding cache_lock */ 55static void __cache_add(struct object *obj) 56{ 57 list_add(&obj->list, &cache); 58 if (++cache_num > MAX_CACHE_SIZE) { 59 struct object *i, *outcast = NULL; 60 list_for_each_entry(i, &cache, list) { 61 if (!outcast || i->popularity < outcast->popularity) 62 outcast = i; 63 } 64 __cache_delete(outcast); 65 } 66} 67 68int cache_add(int id, const char *name) 69{ 70 struct object *obj; 71 72 if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) 73 return -ENOMEM; 74 75 strlcpy(obj->name, name, sizeof(obj->name)); 76 obj->id = id; 77 obj->popularity = 0; 78 79 mutex_lock(&cache_lock); 80 __cache_add(obj); 81 mutex_unlock(&cache_lock); 82 return 0; 83} 84 85void cache_delete(int id) 86{ 87 mutex_lock(&cache_lock); 88 __cache_delete(__cache_find(id)); 89 mutex_unlock(&cache_lock); 90} 91 92int cache_find(int id, char *name) 93{ 94 struct object *obj; 95 int ret = -ENOENT; 96 97 mutex_lock(&cache_lock); 98 obj = __cache_find(id); 99 if (obj) { 100 ret = 0; 101 strcpy(name, obj->name); 102 } 103 mutex_unlock(&cache_lock); 104 return ret; 105} 106</pre><p> 107Note that we always make sure we have the cache_lock when we add, 108delete, or look up the cache: both the cache infrastructure itself and 109the contents of the objects are protected by the lock. In this case 110it's easy, since we copy the data for the user, and never let them 111access the objects directly. 112 </p><p> 113There is a slight (and common) optimization here: in 114<code class="function">cache_add</code> we set up the fields of the object 115before grabbing the lock. This is safe, as no-one else can access it 116until we put it in cache. 117 </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="trylock-functions.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="examples-interrupt.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. The trylock Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Accessing From Interrupt Context</td></tr></table></div></body></html> 118