123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- <?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 then 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>PHTREAD_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 then 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>
|