1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
|
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<section id="locking" xmlns:xi="http://www.w3.org/2001/XInclude">
<sectioninfo>
<revhistory>
<revision>
<revnumber>$Revision$</revnumber>
<date>$Date$</date>
</revision>
</revhistory>
</sectioninfo>
<title>Locking Interface</title>
<section id="why">
<title>Why use it ?</title>
<para>
The main reason in creating it was to have a single transparent
interface to various locking methods. For example right now SER
uses the following locking methods, depending on their availability
on the target system.
</para>
<itemizedlist>
<listitem>
<simpara><emphasis>FAST_LOCK</emphasis></simpara>
<simpara>
Fast inline assembly locks, defined in
<filename>fast_lock.h</filename>. They are currently
available for x86, sparc64, strong-arm (amv4l) and ppc
(external untested contributed code). In general if the
assembly code exists for a given architecture and the
compiler knows inline assembly (for example sun cc does
not) FAST_LOCK is preferred. The main advantage of using
FAST_LOCK is very low memory overhead and extremely fast
lock/unlock operations (like 20 times faster than SYSV
semaphores on linux & 40 times on solaris). The only thing
that comes close to them are pthread mutexes (which are
about 3-4 times slower).
</simpara>
</listitem>
<listitem>
<simpara><emphasis>PTHREAD_MUTEX</emphasis></simpara>
<simpara>
Uses pthread_mutex_lock/unlock. They are quite fast but
they work between processes only on some systems (they do
not work on linux).
</simpara>
</listitem>
<listitem>
<simpara><emphasis>POSIX_SEM</emphasis></simpara>
<simpara>
Uses posix semaphores
(<function>sem_wait</function>/<function>sem_post</function>). They
are slower than the previous methods but still way faster
then SYSV semaphores. Unfortunately they also do not work
on all the systems (e.g. linux).
</simpara>
</listitem>
<listitem>
<simpara><emphasis>SYSV_SEM</emphasis></simpara>
<simpara>
This is the most portable but also the slowest locking
method. Another problem is that the number of semaphores
that can be allocated by a process is limited. One also has
to free them before exiting.
</simpara>
</listitem>
</itemizedlist>
</section>
<section id="how">
<title>How to use it ?</title>
<simpara>
First of all you have to include
<filename>locking.h</filename>. Then when compiling the code one or
all of FAST_LOCK, USE_PTHREAD_MUTEX, USE_PTHREAD_SEM or
USE_SYSV_SEM must be defined (the ser
<filename>Makefile.defs</filename> takes care of this, you should
need to change it only for new architectures or
compilers). <filename>locking.h</filename> defines 2 new types:
<structname>gen_lock_t</structname> and
<structname>lock_set_t</structname>.
</simpara>
</section>
<section id="simple_locks">
<title>Simple Locks</title>
<simpara>
The simple locks are simple mutexes. The type is
<structname>gen_lock_t</structname>.
</simpara>
<warning>
<simpara>
Do not make any assumptions on
<structname>gen_lock_t</structname> base type, it does not have
to be always an int.
</simpara>
</warning>
<section id="allocation_and_initialization">
<title>Allocation And Initialization</title>
<simpara>
The locks are allocated with: <function>gen_lock_t*
lock_alloc()</function> and initialized with
<function>gen_lock_t* lock_init(gen_lock_t*
lock)</function>. Both functions return 0 on failure. The
locks must be initialized before use. A proper alloc/init
sequence looks like:
</simpara>
<programlisting>
gen_lock_t* lock;
lock=lock_alloc();
if (lock==0) goto error;
if (lock_init(lock)==0){
lock_dealloc(lock);
goto error; /* could not init lock*/
}
...
</programlisting>
<simpara>
Lock allocation can be skipped in some cases: if the lock is
already in shared memory you don't need to allocate it again,
you can initialize it directly, but keep in mind that the lock
<emphasis>MUST</emphasis> be in shared memory.
</simpara>
<simpara>
Example:
</simpara>
<programlisting>
struct s {
int foo;
gen_lock_t lock;
} bar;
bar=shm_malloc(sizeof struct s); /* we allocate it in the shared memory */
if (lock_init(&bar->lock)==0){
/* error initializing the lock */
...
}
</programlisting>
</section>
<section id="destroying">
<title>Destroying And Deallocating the Locks</title>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>lock_destroy</function></funcdef>
<paramdef><parameter>gen_lock_t* lock</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>lock_dealloc</function></funcdef>
<paramdef><parameter>gen_lock_t* lock</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<simpara>
The <function>lock_destroy</function> function must be called
first. It removes the resources associated with the lock, but
it does not also free the lock shared memory part. Think of
sysv <command>rmid</command>. Please don't forget to call this
function, or you can leave allocated resources in some cases
(e.g sysv semaphores). Be careful to call it in your module
destroy function if you use any global module locks.
</simpara>
<simpara>
Example:
</simpara>
<programlisting>
lock_destroy(lock);
lock_dealloc(lock);
</programlisting>
<simpara>
Of course you don't need to call
<function>lock_dealloc</function> if your lock was not
allocated with <function>lock_alloc</function>.
</simpara>
</section>
<section id="locking_unlocking">
<title>Locking And Unlocking</title>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>lock_get</function></funcdef>
<paramdef><parameter>gen_lock_t* lock</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>lock_release</function></funcdef>
<paramdef><parameter>gen_lock_t* lock</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</section>
<section id="lock_sets">
<title>Lock Sets</title>
<simpara>
The lock sets are kind of sysv semaphore sets equivalent. The
type is <structname>lock_set_t</structname>. Use them when you
need a lot of mutexes. In some cases they waste less system
resources than arrays of <structname>gen_lock_t</structname>
(e.g. sys v semaphores).
</simpara>
<section id="sets.allocating">
<title>Allocating And Initializing</title>
<funcsynopsis>
<funcprototype>
<funcdef>lock_set_t* lock_set_alloc</funcdef>
<paramdef><parameter>int no</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>lock_set_t* lock_set_init</funcdef>
<paramdef><parameter>lock_set_t* set</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<simpara>
Both functions return 0 on failure.
</simpara>
<warning>
<simpara>
Expect the allocation function to fail for large
numbers. It depends on the locking method used and the
system available resources (again the sysv semaphores
example).
</simpara>
</warning>
<simpara>
Example:
</simpara>
<programlisting>
lock_set_t *lock_set;
lock_set=lock_set_alloc(100);
if (lock_set==0) goto error;
if (lock_set_init(lock_set)==0){
lock_set_dealloc(lock_set);
goto error;
}
</programlisting>
</section>
<section id="sets.destroying">
<title>Destroying And Deallocating</title>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>lock_set_destroy</function></funcdef>
<paramdef><parameter>lock_set_t* s</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>lock_set_dealloc</function></funcdef>
<paramdef><parameter>lock_set_t* s</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<simpara>
Again don't forget to "destroy" the locks.
</simpara>
</section>
<section id="sets.locking">
<title>Locking And Unlocking</title>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>lock_set_get</function></funcdef>
<paramdef>
<parameter>lock_set_t* s</parameter>
<parameter>int i</parameter>
</paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>lock_set_release</function></funcdef>
<paramdef>
<parameter>lock_set_t* s</parameter>
<parameter>int i</parameter>
</paramdef>
</funcprototype>
</funcsynopsis>
<simpara>
Example:
</simpara>
<programlisting>
lock_set_get(lock_set, 2);
/* do something */
lock_set_release(lock_set, 2);
</programlisting>
</section>
</section>
</section>
</section>
|