- Spelling checked
[sip-router] / lock_ops.h
1 /* $Id$ */
2 /*
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28 /*
29  *   ser locking library
30  *   WARNING: do not include this file directly, use instead locking.h
31  *   (unless you don't need to alloc/dealloc locks)
32  *
33  *  2002-12-16  created by andrei
34  *  2003-02-20  s/gen_lock_t/gen_lock_t/ to avoid a type conflict 
35  *               on solaris  (andrei)
36  *  2003-03-05  lock set support added for FAST_LOCK & SYSV (andrei)
37  *  2003-03-06  removed *_alloc,*_dealloc & moved them to lock_alloc.h
38  *              renamed locking.h to lock_ops.h (all this to solve
39  *              the locking.h<->shm_mem.h interdependency) (andrei)
40  *  2003-03-10  lock set support added also for PTHREAD_MUTEX & POSIX_SEM
41  *               (andrei)
42  *  2003-03-17  possible signal interruptions treated for sysv (andrei)
43  *  2004-07-28  s/lock_set_t/gen_lock_set_t/ because of a type conflict
44  *              on darwin (andrei)
45  *
46 Implements:
47
48         simple locks:
49         -------------
50         gen_lock_t* lock_init(gen_lock_t* lock); - inits the lock
51         void    lock_destroy(gen_lock_t* lock);  - removes the lock (e.g sysv rmid)
52         void    lock_get(gen_lock_t* lock);      - lock (mutex down)
53         void    lock_release(gen_lock_t* lock);  - unlock (mutex up)
54         
55         lock sets: [implemented only for FL & SYSV so far]
56         ----------
57         gen_lock_set_t* lock_set_init(gen_lock_set_t* set);  - inits the lock set
58         void lock_set_destroy(gen_lock_set_t* s);        - removes the lock set
59         void lock_set_get(gen_lock_set_t* s, int i);     - locks sem i from the set
60         void lock_set_release(gen_lock_set_t* s, int i)  - unlocks sem i from the set
61
62 WARNING: - lock_set_init may fail for large number of sems (e.g. sysv). 
63          - signals are not treated! (some locks are "awakened" by the signals)
64 */
65
66 #ifndef _lock_ops_h
67 #define _lock_ops_h
68
69
70 #ifdef FAST_LOCK
71 #include "fastlock.h"
72
73 typedef fl_lock_t gen_lock_t;
74
75
76 #define lock_destroy(lock) /* do nothing */ 
77
78 inline static gen_lock_t* lock_init(gen_lock_t* lock)
79 {
80         init_lock(*lock);
81         return lock;
82 }
83
84 #define lock_get(lock) get_lock(lock)
85 #define lock_release(lock) release_lock(lock)
86
87 #elif defined USE_PTHREAD_MUTEX
88 #include <pthread.h>
89
90 typedef pthread_mutex_t gen_lock_t;
91
92 #define lock_destroy(lock) /* do nothing */ 
93
94 inline static gen_lock_t* lock_init(gen_lock_t* lock)
95 {
96         if (pthread_mutex_init(lock, 0)==0) return lock;
97         else return 0;
98 }
99
100 #define lock_get(lock) pthread_mutex_lock(lock)
101 #define lock_release(lock) pthread_mutex_unlock(lock)
102
103
104
105 #elif defined USE_POSIX_SEM
106 #include <semaphore.h>
107
108 typedef sem_t gen_lock_t;
109
110 #define lock_destroy(lock) /* do nothing */ 
111
112 inline static gen_lock_t* lock_init(gen_lock_t* lock)
113 {
114         if (sem_init(lock, 1, 1)<0) return 0;
115         return lock;
116 }
117
118 #define lock_get(lock) sem_wait(lock)
119 #define lock_release(lock) sem_post(lock)
120
121
122 #elif defined USE_SYSV_SEM
123 #include <sys/ipc.h>
124 #include <sys/sem.h>
125
126 #if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED)) 
127         
128         /* union semun is defined by including sem.h */
129 #else
130         /* according to X/OPEN we have to define it ourselves */
131         union semun {
132                 int val;                      /* value for SETVAL */
133                 struct semid_ds *buf;         /* buffer for IPC_STAT, IPC_SET */
134                 unsigned short int *array;    /* array for GETALL, SETALL */
135                 struct seminfo *__buf;        /* buffer for IPC_INFO */
136         };
137 #endif
138
139 typedef int gen_lock_t;
140
141
142
143
144 inline static gen_lock_t* lock_init(gen_lock_t* lock)
145 {
146         union semun su;
147         
148         *lock=semget(IPC_PRIVATE, 1, 0700);
149         if (*lock==-1) return 0;
150         su.val=1;
151         if (semctl(*lock, 0, SETVAL, su)==-1){
152                 /* init error*/
153                 return 0;
154         }
155         return lock;
156 }
157
158 inline static void lock_destroy(gen_lock_t* lock)
159 {
160         semctl(*lock, 0, IPC_RMID, (union semun)(int)0);
161 }
162
163
164 inline static void lock_get(gen_lock_t* lock)
165 {
166         struct sembuf sop;
167
168         sop.sem_num=0;
169         sop.sem_op=-1; /* down */
170         sop.sem_flg=0; 
171 tryagain:
172         if (semop(*lock, &sop, 1)==-1){
173                 if (errno==EINTR){
174                         DBG("lock_get: signal received while waiting for on a mutex\n");
175                         goto tryagain;
176                 }else{
177                         LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
178                                                 errno);
179                 }
180         }
181 }
182
183 inline static void lock_release(gen_lock_t* lock)
184 {
185         struct sembuf sop;
186         
187         sop.sem_num=0;
188         sop.sem_op=1; /* up */
189         sop.sem_flg=0; 
190 tryagain:
191         if (semop(*lock, &sop, 1)==-1){
192                 if (errno==EINTR){
193                         /* very improbable*/
194                         DBG("lock_release: signal received while releasing a mutex\n");
195                         goto tryagain;
196                 }else{
197                         LOG(L_CRIT, "ERROR: lock_release sysv: %s (%d)\n",
198                                         strerror(errno), errno);
199                 }
200         }
201 }
202
203
204 #else
205 #error "no locking method selected"
206 #endif
207
208
209 /* lock sets */
210
211 #if defined(FAST_LOCK) || defined(USE_PTHREAD_MUTEX) || defined(USE_POSIX_SEM)
212 #define GEN_LOCK_T_PREFERED
213
214 struct gen_lock_set_t_ {
215         long size;
216         gen_lock_t* locks;
217 }; /* must be  aligned (32 bits or 64 depending on the arch)*/
218 typedef struct gen_lock_set_t_ gen_lock_set_t;
219
220
221 #define lock_set_destroy(lock_set) /* do nothing */
222
223 inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
224 {
225         int r;
226         for (r=0; r<s->size; r++) if (lock_init(&s->locks[r])==0) return 0;
227         return s;
228 }
229
230 /* WARNING: no boundary checks!*/
231 #define lock_set_get(set, i) lock_get(&set->locks[i])
232 #define lock_set_release(set, i) lock_release(&set->locks[i])
233
234 #elif defined(USE_SYSV_SEM)
235 #undef GEN_LOCK_T_PREFERED
236
237 struct gen_lock_set_t_ {
238         int size;
239         int semid;
240 };
241
242
243 typedef struct gen_lock_set_t_ gen_lock_set_t;
244 inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
245 {
246         union semun su;
247         int r;
248         
249         s->semid=semget(IPC_PRIVATE, s->size, 0700);
250         if (s->semid==-1){
251                 LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semget failed: %s\n",
252                                 strerror(errno));
253                 return 0;
254         }
255         su.val=1;
256         for (r=0; r<s->size; r++){
257                 if (semctl(s->semid, r, SETVAL, su)==-1){
258                         LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semctl failed on sem %d"
259                                         ": %s\n", r, strerror(errno));
260                         semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
261                         return 0;
262                 }
263         }
264         return s;
265 }
266
267 inline static void lock_set_destroy(gen_lock_set_t* s)
268 {
269         semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
270 }
271
272 inline static void lock_set_get(gen_lock_set_t* s, int n)
273 {
274         struct sembuf sop;
275         sop.sem_num=n;
276         sop.sem_op=-1; /* down */
277         sop.sem_flg=0;
278 tryagain:
279         if (semop(s->semid, &sop, 1)==-1){
280                 if (errno==EINTR){
281                         DBG("lock_set_get: signal received while waiting on a mutex\n");
282                         goto tryagain;
283                 }else{
284                         LOG(L_CRIT, "ERROR: lock_set_get sysv: %s (%d)\n",
285                                         strerror(errno), errno);
286                 }
287         }
288 }
289
290 inline static void lock_set_release(gen_lock_set_t* s, int n)
291 {
292         struct sembuf sop;
293         sop.sem_num=n;
294         sop.sem_op=1; /* up */
295         sop.sem_flg=0;
296 tryagain:
297         if (semop(s->semid, &sop, 1)==-1){
298                 if (errno==EINTR){
299                         /* very improbable */
300                         DBG("lock_set_release: signal received while releasing mutex\n");
301                         goto tryagain;
302                 }else{
303                         LOG(L_CRIT, "ERROR: lock_set_release sysv: %s (%d)\n",
304                                         strerror(errno), errno);
305                 }
306         }
307 }
308 #else 
309 #error "no lock set method selected"
310 #endif
311
312
313 #endif