• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • Directories
  • File List
  • Globals

lock_ops.h

00001 /* $Id$ */
00002 /*
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 
00019 /*
00020  *   ser locking library
00021  *   WARNING: do not include this file directly, use instead locking.h
00022  *   (unless you don't need to alloc/dealloc locks)
00023  *
00024  *  2002-12-16  created by andrei
00025  *  2003-02-20  s/gen_lock_t/gen_lock_t/ to avoid a type conflict 
00026  *               on solaris  (andrei)
00027  *  2003-03-05  lock set support added for FAST_LOCK & SYSV (andrei)
00028  *  2003-03-06  removed *_alloc,*_dealloc & moved them to lock_alloc.h
00029  *              renamed locking.h to lock_ops.h (all this to solve
00030  *              the locking.h<->shm_mem.h interdependency) (andrei)
00031  *  2003-03-10  lock set support added also for PTHREAD_MUTEX & POSIX_SEM
00032  *               (andrei)
00033  *  2003-03-17  possible signal interruptions treated for sysv (andrei)
00034  *  2004-07-28  s/lock_set_t/gen_lock_set_t/ because of a type conflict
00035  *              on darwin (andrei)
00036  *  2006-04-04  added lock_try(lock) and lock_set_try(s,i) (andrei)
00037  *  2007-05-13  added futex support (andrei)
00038  *
00039 Implements:
00040 
00041         simple locks:
00042         -------------
00043         gen_lock_t* lock_init(gen_lock_t* lock); - inits the lock
00044         void    lock_destroy(gen_lock_t* lock);  - removes the lock (e.g sysv rmid)
00045         void    lock_get(gen_lock_t* lock);      - lock (mutex down)
00046         void    lock_release(gen_lock_t* lock);  - unlock (mutex up)
00047         int     lock_try(gen_lock_t* lock);      - tries to get the lock, returns
00048                                                     0 on success and !=0 on failure
00049         
00050         lock sets: 
00051         ----------
00052         gen_lock_set_t* lock_set_init(gen_lock_set_t* set);  - inits the lock set
00053         void lock_set_destroy(gen_lock_set_t* s);        - removes the lock set
00054         void lock_set_get(gen_lock_set_t* s, int i);     - locks sem i from the set
00055         void lock_set_release(gen_lock_set_t* s, int i)  - unlocks sem i from the
00056                                                            set
00057         int  lock_set_try(gen_lock_set_t* s, int i);    - tries to lock the sem i,
00058                                                           returns 0 on success and
00059                                                           !=0 on failure
00060         
00061         defines:
00062         --------
00063         GEN_LOCK_T_PREFERRED - defined if using  arrays of gen_lock_t is as good as
00064                               using a lock set (gen_lock_set_t). 
00065                                                   In general is better to have the locks "close" or 
00066                                                   inside the protected data structure rather then 
00067                                                   having a separate array or lock set. However in some
00068                                                   case (e.g. SYSV_LOCKS) is better to use lock sets,
00069                                                   either due to lock number limitations, excesive 
00070                                                   performance or memory overhead. In this cases
00071                                                   GEN_LOCK_T_PREFERRED will not be defined.
00072         GEN_LOCK_T_UNLIMITED - defined if there is no system imposed limit on
00073                                the number of locks (other then the memory).
00074         GEN_LOCK_SET_T_UNLIMITED
00075                               - like above but for the size of a lock set.
00076 
00077 WARNING: - lock_set_init may fail for large number of sems (e.g. sysv). 
00078          - signals are not treated! (some locks are "awakened" by the signals)
00079 */
00080 
00081 #ifndef _lock_ops_h
00082 #define _lock_ops_h
00083 
00084 #ifdef USE_FUTEX
00085 #include "futexlock.h"
00086 /* if no native atomic ops support => USE_FUTEX will be undefined */
00087 #endif
00088 
00089 
00090 #ifdef USE_FUTEX
00091 
00092 typedef futex_lock_t gen_lock_t;
00093 
00094 #define lock_destroy(lock) /* do nothing */
00095 #define lock_init(lock) futex_init(lock)
00096 #define lock_try(lock)  futex_try(lock)
00097 #define lock_get(lock)  futex_get(lock)
00098 #define lock_release(lock) futex_release(lock)
00099 
00100 
00101 #elif defined FAST_LOCK
00102 #include "fastlock.h"
00103 
00104 typedef fl_lock_t gen_lock_t;
00105 
00106 
00107 #define lock_destroy(lock) /* do nothing */ 
00108 
00109 inline static gen_lock_t* lock_init(gen_lock_t* lock)
00110 {
00111         init_lock(*lock);
00112         return lock;
00113 }
00114 
00115 #define lock_try(lock) try_lock(lock)
00116 #define lock_get(lock) get_lock(lock)
00117 #define lock_release(lock) release_lock(lock)
00118 
00119 
00120 #elif defined USE_PTHREAD_MUTEX
00121 #include <pthread.h>
00122 
00123 typedef pthread_mutex_t gen_lock_t;
00124 
00125 #define lock_destroy(lock) /* do nothing */ 
00126 
00127 inline static gen_lock_t* lock_init(gen_lock_t* lock)
00128 {
00129         if (pthread_mutex_init(lock, 0)==0) return lock;
00130         else return 0;
00131 }
00132 
00133 #define lock_try(lock) pthread_mutex_trylock(lock)
00134 #define lock_get(lock) pthread_mutex_lock(lock)
00135 #define lock_release(lock) pthread_mutex_unlock(lock)
00136 
00137 
00138 
00139 #elif defined USE_POSIX_SEM
00140 #include <semaphore.h>
00141 
00142 typedef sem_t gen_lock_t;
00143 
00144 #define lock_destroy(lock) /* do nothing */ 
00145 
00146 inline static gen_lock_t* lock_init(gen_lock_t* lock)
00147 {
00148         if (sem_init(lock, 1, 1)<0) return 0;
00149         return lock;
00150 }
00151 
00152 #define lock_try(lock) sem_trywait(lock)
00153 #define lock_get(lock) sem_wait(lock)
00154 #define lock_release(lock) sem_post(lock)
00155 
00156 
00157 #elif defined USE_SYSV_SEM
00158 #include <sys/ipc.h>
00159 #include <sys/sem.h>
00160 
00161 #include <errno.h>
00162 #include <string.h>
00163 #include <sys/types.h>
00164 #include <unistd.h>
00165 #include "dprint.h"
00166 #include "globals.h" /* uid */
00167 
00168 #if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED)) 
00169         
00170         /* union semun is defined by including sem.h */
00171 #else
00172         /* according to X/OPEN we have to define it ourselves */
00173         union semun {
00174                 int val;                      /* value for SETVAL */
00175                 struct semid_ds *buf;         /* buffer for IPC_STAT, IPC_SET */
00176                 unsigned short int *array;    /* array for GETALL, SETALL */
00177                 struct seminfo *__buf;        /* buffer for IPC_INFO */
00178         };
00179 #endif
00180 
00181 typedef int gen_lock_t;
00182 
00183 
00184 
00185 
00186 inline static gen_lock_t* lock_init(gen_lock_t* lock)
00187 {
00188         union semun su;
00189         int euid;
00190         
00191         euid=geteuid();
00192         if (uid && uid!=euid)
00193                 seteuid(uid); /* set euid to the cfg. requested one */
00194         *lock=semget(IPC_PRIVATE, 1, 0700);
00195         if (uid && uid!=euid)
00196                 seteuid(euid); /* restore it */
00197         if (*lock==-1) return 0;
00198         su.val=1;
00199         if (semctl(*lock, 0, SETVAL, su)==-1){
00200                 /* init error*/
00201                 return 0;
00202         }
00203         return lock;
00204 }
00205 
00206 inline static void lock_destroy(gen_lock_t* lock)
00207 {
00208         semctl(*lock, 0, IPC_RMID, (union semun)(int)0);
00209 }
00210 
00211 
00212 /* returns 0 if it got the lock, -1 otherwise */
00213 inline static int lock_try(gen_lock_t* lock)
00214 {
00215         struct sembuf sop;
00216 
00217         sop.sem_num=0;
00218         sop.sem_op=-1; /* down */
00219         sop.sem_flg=IPC_NOWAIT; 
00220 tryagain:
00221         if (semop(*lock, &sop, 1)==-1){
00222                 if (errno==EAGAIN){
00223                         return -1;
00224                 }else if (errno==EINTR){
00225                         DBG("lock_get: signal received while waiting for on a mutex\n");
00226                         goto tryagain;
00227                 }else{
00228                         LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
00229                                                 errno);
00230                         return -1;
00231                 }
00232         }
00233         return 0;
00234 }
00235 
00236 inline static void lock_get(gen_lock_t* lock)
00237 {
00238         struct sembuf sop;
00239 
00240         sop.sem_num=0;
00241         sop.sem_op=-1; /* down */
00242         sop.sem_flg=0; 
00243 tryagain:
00244         if (semop(*lock, &sop, 1)==-1){
00245                 if (errno==EINTR){
00246                         DBG("lock_get: signal received while waiting for on a mutex\n");
00247                         goto tryagain;
00248                 }else{
00249                         LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
00250                                                 errno);
00251                 }
00252         }
00253 }
00254 
00255 inline static void lock_release(gen_lock_t* lock)
00256 {
00257         struct sembuf sop;
00258         
00259         sop.sem_num=0;
00260         sop.sem_op=1; /* up */
00261         sop.sem_flg=0; 
00262 tryagain:
00263         if (semop(*lock, &sop, 1)==-1){
00264                 if (errno==EINTR){
00265                         /* very improbable*/
00266                         DBG("lock_release: signal received while releasing a mutex\n");
00267                         goto tryagain;
00268                 }else{
00269                         LOG(L_CRIT, "ERROR: lock_release sysv: %s (%d)\n",
00270                                         strerror(errno), errno);
00271                 }
00272         }
00273 }
00274 
00275 
00276 #else
00277 #error "no locking method selected"
00278 #endif
00279 
00280 
00281 /* lock sets */
00282 
00283 #if defined(FAST_LOCK) || defined(USE_PTHREAD_MUTEX) || \
00284         defined(USE_POSIX_SEM) || defined(USE_FUTEX)
00285 #define GEN_LOCK_T_PREFERRED
00286 #define GEN_LOCK_T_PREFERED  /* backwards compat. */
00287 #define GEN_LOCK_T_UNLIMITED
00288 #define GEN_LOCK_SET_T_UNLIMITED
00289 
00290 struct gen_lock_set_t_ {
00291         long size;
00292         gen_lock_t* locks;
00293 }; /* must be  aligned (32 bits or 64 depending on the arch)*/
00294 typedef struct gen_lock_set_t_ gen_lock_set_t;
00295 
00296 
00297 #define lock_set_destroy(lock_set) /* do nothing */
00298 
00299 inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
00300 {
00301         int r;
00302         for (r=0; r<s->size; r++) if (lock_init(&s->locks[r])==0) return 0;
00303         return s;
00304 }
00305 
00306 /* WARNING: no boundary checks!*/
00307 #define lock_set_try(set, i) lock_try(&set->locks[i])
00308 #define lock_set_get(set, i) lock_get(&set->locks[i])
00309 #define lock_set_release(set, i) lock_release(&set->locks[i])
00310 
00311 #elif defined(USE_SYSV_SEM)
00312 #undef GEN_LOCK_T_PREFERRED
00313 #undef GEN_LOCK_T_PREFERED  /* backwards compat. */
00314 #undef GEN_LOCK_T_UNLIMITED
00315 #undef GEN_LOCK_SET_T_UNLIMITED
00316 #define GEN_LOCK_T_LIMITED
00317 #define GEN_LOCK_SET_T_LIMITED
00318 
00319 struct gen_lock_set_t_ {
00320         int size;
00321         int semid;
00322 };
00323 
00324 
00325 typedef struct gen_lock_set_t_ gen_lock_set_t;
00326 inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
00327 {
00328         union semun su;
00329         int r;
00330         int euid;
00331 
00332         euid=geteuid();
00333         if (uid && uid!=euid)
00334                 seteuid(uid); /* set euid to the cfg. requested one */
00335         s->semid=semget(IPC_PRIVATE, s->size, 0700);
00336         if (uid && uid!=euid)
00337                 seteuid(euid); /* restore euid */
00338         if (s->semid==-1){
00339                 LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semget (..., %d, 0700)"
00340                                 " failed: %s\n",
00341                                 s->size, strerror(errno));
00342                 return 0;
00343         }
00344         su.val=1;
00345         for (r=0; r<s->size; r++){
00346                 if (semctl(s->semid, r, SETVAL, su)==-1){
00347                         LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semctl failed on sem %d"
00348                                         ": %s\n", r, strerror(errno));
00349                         semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
00350                         return 0;
00351                 }
00352         }
00353         return s;
00354 }
00355 
00356 inline static void lock_set_destroy(gen_lock_set_t* s)
00357 {
00358         semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
00359 }
00360 
00361 
00362 /* returns 0 if it "gets" the lock, -1 otherwise */
00363 inline static int lock_set_try(gen_lock_set_t* s, int n)
00364 {
00365         struct sembuf sop;
00366         
00367         sop.sem_num=n;
00368         sop.sem_op=-1; /* down */
00369         sop.sem_flg=IPC_NOWAIT; 
00370 tryagain:
00371         if (semop(s->semid, &sop, 1)==-1){
00372                 if (errno==EAGAIN){
00373                         return -1;
00374                 }else if (errno==EINTR){
00375                         DBG("lock_get: signal received while waiting for on a mutex\n");
00376                         goto tryagain;
00377                 }else{
00378                         LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
00379                                                 errno);
00380                         return -1;
00381                 }
00382         }
00383         return 0;
00384 }
00385 
00386 
00387 inline static void lock_set_get(gen_lock_set_t* s, int n)
00388 {
00389         struct sembuf sop;
00390         sop.sem_num=n;
00391         sop.sem_op=-1; /* down */
00392         sop.sem_flg=0;
00393 tryagain:
00394         if (semop(s->semid, &sop, 1)==-1){
00395                 if (errno==EINTR){
00396                         DBG("lock_set_get: signal received while waiting on a mutex\n");
00397                         goto tryagain;
00398                 }else{
00399                         LOG(L_CRIT, "ERROR: lock_set_get sysv: %s (%d)\n",
00400                                         strerror(errno), errno);
00401                 }
00402         }
00403 }
00404 
00405 inline static void lock_set_release(gen_lock_set_t* s, int n)
00406 {
00407         struct sembuf sop;
00408         sop.sem_num=n;
00409         sop.sem_op=1; /* up */
00410         sop.sem_flg=0;
00411 tryagain:
00412         if (semop(s->semid, &sop, 1)==-1){
00413                 if (errno==EINTR){
00414                         /* very improbable */
00415                         DBG("lock_set_release: signal received while releasing mutex\n");
00416                         goto tryagain;
00417                 }else{
00418                         LOG(L_CRIT, "ERROR: lock_set_release sysv: %s (%d)\n",
00419                                         strerror(errno), errno);
00420                 }
00421         }
00422 }
00423 #else 
00424 #error "no lock set method selected"
00425 #endif
00426 
00427 
00428 #endif

Generated on Tue May 22 2012 13:10:10 for SIP Router by  doxygen 1.7.1