core: Changed WS from being a flag on a TCP/TLS connection to a protocol in its own...
[sip-router] / lock_ops.h
index 5fd9cde..f83ea77 100644 (file)
@@ -3,26 +3,17 @@
  *
  * Copyright (C) 2001-2003 FhG Fokus
  *
- * This file is part of ser, a free SIP server.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info@iptel.org
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 /*
@@ -42,6 +33,8 @@
  *  2003-03-17  possible signal interruptions treated for sysv (andrei)
  *  2004-07-28  s/lock_set_t/gen_lock_set_t/ because of a type conflict
  *              on darwin (andrei)
+ *  2006-04-04  added lock_try(lock) and lock_set_try(s,i) (andrei)
+ *  2007-05-13  added futex support (andrei)
  *
 Implements:
 
@@ -51,13 +44,35 @@ Implements:
        void    lock_destroy(gen_lock_t* lock);  - removes the lock (e.g sysv rmid)
        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 get the lock, returns
+                                                   0 on success and !=0 on failure
        
-       lock sets: [implemented only for FL & SYSV so far]
+       lock sets: 
        ----------
        gen_lock_set_t* lock_set_init(gen_lock_set_t* set);  - inits the lock set
        void lock_set_destroy(gen_lock_set_t* s);        - removes the lock set
        void lock_set_get(gen_lock_set_t* s, int i);     - locks sem i from the set
-       void lock_set_release(gen_lock_set_t* s, int i)  - unlocks sem i from the set
+       void lock_set_release(gen_lock_set_t* s, int i)  - unlocks sem i from the
+                                                          set
+       int  lock_set_try(gen_lock_set_t* s, int i);    - tries to lock the sem i,
+                                                         returns 0 on success and
+                                                         !=0 on failure
+       
+       defines:
+       --------
+       GEN_LOCK_T_PREFERRED - defined if using  arrays of gen_lock_t is as good as
+                             using a lock set (gen_lock_set_t). 
+                                                 In general is better to have the locks "close" or 
+                                                 inside the protected data structure rather then 
+                                                 having a separate array or lock set. However in some
+                                                 case (e.g. SYSV_LOCKS) is better to use lock sets,
+                                                 either due to lock number limitations, excesive 
+                                                 performance or memory overhead. In this cases
+                                                 GEN_LOCK_T_PREFERRED will not be defined.
+       GEN_LOCK_T_UNLIMITED - defined if there is no system imposed limit on
+                              the number of locks (other then the memory).
+       GEN_LOCK_SET_T_UNLIMITED
+                             - like above but for the size of a lock set.
 
 WARNING: - lock_set_init may fail for large number of sems (e.g. sysv). 
          - signals are not treated! (some locks are "awakened" by the signals)
@@ -66,8 +81,24 @@ WARNING: - lock_set_init may fail for large number of sems (e.g. sysv).
 #ifndef _lock_ops_h
 #define _lock_ops_h
 
+#ifdef USE_FUTEX
+#include "futexlock.h"
+/* if no native atomic ops support => USE_FUTEX will be undefined */
+#endif
+
 
-#ifdef FAST_LOCK
+#ifdef USE_FUTEX
+
+typedef futex_lock_t gen_lock_t;
+
+#define lock_destroy(lock) /* do nothing */
+#define lock_init(lock) futex_init(lock)
+#define lock_try(lock)  futex_try(lock)
+#define lock_get(lock)  futex_get(lock)
+#define lock_release(lock) futex_release(lock)
+
+
+#elif defined FAST_LOCK
 #include "fastlock.h"
 
 typedef fl_lock_t gen_lock_t;
@@ -81,9 +112,11 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock)
        return lock;
 }
 
+#define lock_try(lock) try_lock(lock)
 #define lock_get(lock) get_lock(lock)
 #define lock_release(lock) release_lock(lock)
 
+
 #elif defined USE_PTHREAD_MUTEX
 #include <pthread.h>
 
@@ -97,6 +130,7 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock)
        else return 0;
 }
 
+#define lock_try(lock) pthread_mutex_trylock(lock)
 #define lock_get(lock) pthread_mutex_lock(lock)
 #define lock_release(lock) pthread_mutex_unlock(lock)
 
@@ -115,6 +149,7 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock)
        return lock;
 }
 
+#define lock_try(lock) sem_trywait(lock)
 #define lock_get(lock) sem_wait(lock)
 #define lock_release(lock) sem_post(lock)
 
@@ -123,6 +158,13 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock)
 #include <sys/ipc.h>
 #include <sys/sem.h>
 
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "dprint.h"
+#include "globals.h" /* uid */
+
 #if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED)) 
        
        /* union semun is defined by including sem.h */
@@ -144,8 +186,14 @@ typedef int gen_lock_t;
 inline static gen_lock_t* lock_init(gen_lock_t* lock)
 {
        union semun su;
+       int euid;
        
+       euid=geteuid();
+       if (uid && uid!=euid)
+               seteuid(uid); /* set euid to the cfg. requested one */
        *lock=semget(IPC_PRIVATE, 1, 0700);
+       if (uid && uid!=euid)
+               seteuid(euid); /* restore it */
        if (*lock==-1) return 0;
        su.val=1;
        if (semctl(*lock, 0, SETVAL, su)==-1){
@@ -161,6 +209,30 @@ inline static void lock_destroy(gen_lock_t* lock)
 }
 
 
+/* returns 0 if it got the lock, -1 otherwise */
+inline static int lock_try(gen_lock_t* lock)
+{
+       struct sembuf sop;
+
+       sop.sem_num=0;
+       sop.sem_op=-1; /* down */
+       sop.sem_flg=IPC_NOWAIT; 
+tryagain:
+       if (semop(*lock, &sop, 1)==-1){
+               if (errno==EAGAIN){
+                       return -1;
+               }else if (errno==EINTR){
+                       DBG("lock_get: signal received while waiting for on a mutex\n");
+                       goto tryagain;
+               }else{
+                       LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
+                                               errno);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
 inline static void lock_get(gen_lock_t* lock)
 {
        struct sembuf sop;
@@ -208,8 +280,12 @@ tryagain:
 
 /* lock sets */
 
-#if defined(FAST_LOCK) || defined(USE_PTHREAD_MUTEX) || defined(USE_POSIX_SEM)
-#define GEN_LOCK_T_PREFERED
+#if defined(FAST_LOCK) || defined(USE_PTHREAD_MUTEX) || \
+       defined(USE_POSIX_SEM) || defined(USE_FUTEX)
+#define GEN_LOCK_T_PREFERRED
+#define GEN_LOCK_T_PREFERED  /* backwards compat. */
+#define GEN_LOCK_T_UNLIMITED
+#define GEN_LOCK_SET_T_UNLIMITED
 
 struct gen_lock_set_t_ {
        long size;
@@ -228,11 +304,17 @@ inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
 }
 
 /* WARNING: no boundary checks!*/
+#define lock_set_try(set, i) lock_try(&set->locks[i])
 #define lock_set_get(set, i) lock_get(&set->locks[i])
 #define lock_set_release(set, i) lock_release(&set->locks[i])
 
 #elif defined(USE_SYSV_SEM)
-#undef GEN_LOCK_T_PREFERED
+#undef GEN_LOCK_T_PREFERRED
+#undef GEN_LOCK_T_PREFERED  /* backwards compat. */
+#undef GEN_LOCK_T_UNLIMITED
+#undef GEN_LOCK_SET_T_UNLIMITED
+#define GEN_LOCK_T_LIMITED
+#define GEN_LOCK_SET_T_LIMITED
 
 struct gen_lock_set_t_ {
        int size;
@@ -245,11 +327,18 @@ inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
 {
        union semun su;
        int r;
-       
+       int euid;
+
+       euid=geteuid();
+       if (uid && uid!=euid)
+               seteuid(uid); /* set euid to the cfg. requested one */
        s->semid=semget(IPC_PRIVATE, s->size, 0700);
+       if (uid && uid!=euid)
+               seteuid(euid); /* restore euid */
        if (s->semid==-1){
-               LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semget failed: %s\n",
-                               strerror(errno));
+               LOG(L_CRIT, "ERROR: lock_set_init (SYSV): semget (..., %d, 0700)"
+                               " failed: %s\n",
+                               s->size, strerror(errno));
                return 0;
        }
        su.val=1;
@@ -269,6 +358,32 @@ inline static void lock_set_destroy(gen_lock_set_t* s)
        semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
 }
 
+
+/* returns 0 if it "gets" the lock, -1 otherwise */
+inline static int lock_set_try(gen_lock_set_t* s, int n)
+{
+       struct sembuf sop;
+       
+       sop.sem_num=n;
+       sop.sem_op=-1; /* down */
+       sop.sem_flg=IPC_NOWAIT; 
+tryagain:
+       if (semop(s->semid, &sop, 1)==-1){
+               if (errno==EAGAIN){
+                       return -1;
+               }else if (errno==EINTR){
+                       DBG("lock_get: signal received while waiting for on a mutex\n");
+                       goto tryagain;
+               }else{
+                       LOG(L_CRIT, "ERROR: lock_get sysv: %s (%d)\n", strerror(errno),
+                                               errno);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+
 inline static void lock_set_get(gen_lock_set_t* s, int n)
 {
        struct sembuf sop;