File: locking.txt

package info (click to toggle)
kamailio 6.0.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 70,472 kB
  • sloc: ansic: 859,394; xml: 203,514; makefile: 9,688; sh: 9,105; sql: 8,571; yacc: 4,121; python: 3,086; perl: 2,955; java: 449; cpp: 289; javascript: 270; php: 258; ruby: 248; awk: 27
file content (181 lines) | stat: -rw-r--r-- 5,928 bytes parent folder | download | duplicates (2)
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

Kamailio locking interface
============================

1. Why use it?
--------------

The main reason for creating it was to have a single transparent interface to various locking methods. 
For example right now Kamailio uses the following locking methods, depending on their availability on the 
target system:
	FAST_LOCK - fast inline assembly locks, defined in fast_lock.h. They are currently available for 
	x86, x86_64, sparc, sparc64, arm , armv6 (no smp mode supported yet), ppc, ppc64, mips, mips64 
	and alpha . 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 prefered. 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).

	PTHREAD_MUTEX - uses pthread_mutex_lock/unlock. They are quite fast but they work between 
	processes only on some systems (they do not work on linux).

	POSIX_SEM  - uses posix semaphores (sem_wait/sem_post). They are slower than the previous 
	methods but still way faster than SYSV semaphores. Unfortunately they also do not work on 
	all the systems (e.g. linux).
	
	SYSV_SEM - 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.


2. How to use it?
-----------------

First of all you have to include locking.h. 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 Kamailio Makefile.defs takes 
care of this, you should need to change it only for new architectures or compilers).

locking.h defines 2 new types: gen_lock_t and lock_set_t.


3. Simple locks
---------------

The simple locks are simple mutexes. The type is gen_lock_t.
WARNING: do not make any assumptions on gen_lock_t base type, it does not have to be always an int.

Allocation & initialization:
----------------------------

The locks are allocated with:
   gen_lock_t* lock_alloc();
and initialized with:
   gen_lock_t* lock_init(gen_lock_t* lock);

Both function return 0 on failure.
The locks must be initialized before use.

A proper alloc/init sequence looks like:

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*/
}
...

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 MUST be in shared memory.

Example:

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 */
 ...
}


Destroying & deallocating the locks:
------------------------------------

  void    lock_destroy(gen_lock_t* lock);
  void    lock_dealloc(gen_lock_t* lock);
 
The lock_destroy 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 rmid.
Please don't forget to call this function, or you can leave allocated resources in some cases 
(e.g sysv semaphores). Be carefull to call it in your module destroy function if you use any 
global module locks.

Example:
	lock_destroy(lock);
	lock_dealloc(lock);

Of course you don't need to call lock_dealloc if your lock was not allocated with lock_alloc.


Locking & unlocking:
--------------------

void    lock_get(gen_lock_t* lock);      - lock (mutex down)
void    lock_release(gen_lock_t* lock);  - unlock (mutex up)
int     lock_try(gen_lock_t* lock);      - tries to lock and returns 0 
                                           if successful, -1 if not (this is
                                           a non-blocking lock_get())



4. Lock Sets
------------

The lock sets are kind of sysv semaphore sets equivalent. The type is lock_set_t.
Use them when you need a lot of mutexes. In some cases they waste less system 
resources than arrays of gen_lock_t (e.g. sys v semaphores).

Allocating & initializing:
--------------------------

	lock_set_t* lock_set_alloc(int no);
	lock_set_t* lock_set_init(lock_set_t* set);

Both functions return 0 on failure.

WARNING: expect the allocation function to fail for large numbers. It depends on the locking 
method used & the system available resources (again the sysv semaphores example).

Example:

	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;
	}

or
 	if ((lock_set=lock_set_alloc(100))==0) || (lock_set_init(lock_set)==0)){
   		if (lock_set) lock_set_dealloc(lock_set);
   		goto error;
 	}


Destroying & deallocating:
--------------------------
  void lock_set_destroy(lock_set_t* s);
  void lock_set_dealloc(lock_set_t* s);

Again don't forget to "destroy" the locks.


Locking & unlocking:
--------------------

void lock_set_get(lock_set_t* s, int i);
void lock_set_release(lock_set_t* s, int i);
int  lock_set_try(lock_set_t* s, int i);      - tries to lock the i-th lock
                                                from the set. If successful
                                                returns 0, if not -1.

Example:

lock_set_get(lock_set, 2);
/* do something */
lock_set_release(lock_set, 2);


When to use lock_set_t & when to use gen_lock_t
-----------------------------------------------
If you use lots of semaphores and GEN_LOCK_T_PREFERED is undefined then use
lock_set_t. If GEN_LOCK_T_PREFERED is defined you can safely use gen_lock_t 
arrays instead.