lock.c

Go to the documentation of this file.
00001 /*
00002  * $Id: lock.c 4729 2008-08-25 09:45:44Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  *  2003-03-17  converted to locking.h (andrei)
00025  *  2004-07-28  s/lock_set_t/gen_lock_set_t/ because of a type conflict
00026  *              on darwin (andrei)
00027  */
00028 
00029 /*! \file
00030  * \brief TM :: Locking functions
00031  *
00032  * \ingroup tm
00033  * - Module: \ref tm
00034  */
00035 
00036 #include <errno.h>
00037 
00038 #include "lock.h"
00039 #include "timer.h"
00040 #include "../../dprint.h"
00041 
00042 
00043 
00044 #ifndef GEN_LOCK_T_PREFERED 
00045 /* semaphore probing limits */
00046 #define SEM_MIN      16
00047 #define SEM_MAX      4096
00048 
00049 /*! \page TMlocking TM :: Transaction locking
00050 
00051    We implement mutex here using lock sets; as the number of
00052    semaphores may be limited (e.g. sysv) and number of synchronized 
00053    elements high, we partition the synced SER elements and share 
00054    semaphores in each of the partitions; we try to use as many 
00055    semaphores as OS gives us for finest granularity. 
00056 
00057    we allocate the locks according to the following plans:
00058 
00059    -1) transaction timer lists have each a semaphore in a semaphore set
00060    -2) retransmission timer lists have each a semaphore in a semaphore set
00061    -3) we allocate a semaphore set for hash_entries and
00062       try to use as many semaphores in it as OS allows;
00063       we partition the hash_entries by available
00064       semaphores which are shared  in each partition
00065    -4) cells get always the same semaphore as its hash entry in which they live
00066 
00067 */
00068 
00069 static int sem_nr;         /*!< and the maximum number of semaphores in the entry_semaphore set */
00070 gen_lock_set_t* timer_semaphore=0;
00071 gen_lock_set_t* entry_semaphore=0;
00072 gen_lock_set_t* reply_semaphore=0;
00073 #endif
00074 
00075 /* timer group locks */
00076 static ser_lock_t* timer_group_lock=0; /*!< timer group locks
00077                 pointer to a TG_NR lock array, it's safer if we alloc this in shared mem 
00078                            ( required for fast lock ) */
00079 
00080 /*!
00081  * \brief Initialize the locks
00082  * \return 0 on success, -1 otherwise
00083  */
00084 int lock_initialize(void)
00085 {
00086    int i;
00087 #ifndef GEN_LOCK_T_PREFERED
00088    int probe_run;
00089 #endif
00090 
00091    /* first try allocating semaphore sets with fixed number of semaphores */
00092    LM_DBG("lock initialization started\n");
00093 
00094    timer_group_lock=shm_malloc(TG_NR*sizeof(ser_lock_t));
00095    if (timer_group_lock==0){
00096       LM_CRIT("no more share mem\n");
00097       goto error;
00098    }
00099 #ifdef GEN_LOCK_T_PREFERED
00100    for(i=0;i<TG_NR;i++) lock_init(&timer_group_lock[i]);
00101 #else
00102    /* transaction timers */
00103    if (((timer_semaphore= lock_set_alloc( TG_NR ) ) == 0)||
00104          (lock_set_init(timer_semaphore)==0)){
00105       if (timer_semaphore) lock_set_destroy(timer_semaphore);
00106       LM_CRIT("transaction timer semaphore initialization failure: %s\n",
00107             strerror(errno));
00108       goto error;
00109    }
00110 
00111    for (i=0; i<TG_NR; i++) {
00112       timer_group_lock[i].semaphore_set = timer_semaphore;
00113       timer_group_lock[i].semaphore_index = timer_group[ i ];
00114    }
00115 
00116 
00117    i=SEM_MIN;
00118    /* probing phase: 0=initial, 1=after the first failure */
00119    probe_run=0;
00120 again:
00121    do {
00122       if (entry_semaphore!=0){ /* clean-up previous attempt */
00123          lock_set_destroy(entry_semaphore);
00124          lock_set_dealloc(entry_semaphore);
00125       }
00126       if (reply_semaphore!=0){
00127          lock_set_destroy(reply_semaphore);
00128          lock_set_dealloc(reply_semaphore);
00129       }
00130       
00131       if (i==0){
00132          LM_CRIT("failed allocate semaphore sets\n");
00133          goto error;
00134       }
00135       
00136       if (((entry_semaphore=lock_set_alloc(i))==0)||
00137          (lock_set_init(entry_semaphore)==0)) {
00138          LM_DBG("entry semaphore initialization failure:  %s\n",
00139                strerror( errno ) );
00140          if (entry_semaphore){
00141             lock_set_dealloc(entry_semaphore);
00142             entry_semaphore=0;
00143          }
00144          /* first time: step back and try again */
00145          if (probe_run==0) {
00146                LM_DBG("first time semaphore allocation failure\n");
00147                i--;
00148                probe_run=1;
00149                continue;
00150             /* failure after we stepped back; give up */
00151          } else {
00152                LM_DBG("second time semaphore allocation failure\n");
00153                goto error;
00154          }
00155       }
00156       /* allocation succeeded */
00157       if (probe_run==1) { /* if ok after we stepped back, we're done */
00158          break;
00159       } else { /* if ok otherwise, try again with larger set */
00160          if (i==SEM_MAX) break;
00161          else {
00162             i++;
00163             continue;
00164          }
00165       }
00166    } while(1);
00167    sem_nr=i;
00168 
00169    if (((reply_semaphore=lock_set_alloc(i))==0)||
00170       (lock_set_init(reply_semaphore)==0)){
00171          if (reply_semaphore){
00172             lock_set_dealloc(reply_semaphore);
00173             reply_semaphore=0;
00174          }
00175          LM_DBG("reply semaphore initialization failure: %s\n",
00176                strerror(errno));
00177          probe_run=1;
00178          i--;
00179          goto again;
00180    }
00181 
00182    /* return success */
00183    LM_INFO("semaphore arrays of size %d allocated\n", sem_nr );
00184 #endif /* GEN_LOCK_T_PREFERED*/
00185    return 0;
00186 error:
00187    lock_cleanup();
00188    return -1;
00189 }
00190 
00191 
00192 #ifdef GEN_LOCK_T_PREFERED
00193 /*! \brief remove the semaphore set from system */
00194 void lock_cleanup(void)
00195 {
00196    /* must check if someone uses them, for now just leave them allocated*/
00197    if (timer_group_lock) shm_free((void*)timer_group_lock);
00198 }
00199 
00200 #else
00201 
00202 
00203 /*! \brief remove the semaphore set from system */
00204 void lock_cleanup()
00205 {
00206    /* that's system-wide; all other processes trying to use
00207       the semaphore will fail! call only if it is for sure
00208       no other process lives 
00209    */
00210 
00211    /* sibling double-check missing here; install a signal handler */
00212 
00213    if (entry_semaphore !=0){
00214       lock_set_destroy(entry_semaphore);
00215       lock_set_dealloc(entry_semaphore);
00216    };
00217    if (timer_semaphore !=0){
00218       lock_set_destroy(timer_semaphore);
00219       lock_set_dealloc(timer_semaphore);
00220    };
00221    if (reply_semaphore !=0) {
00222       lock_set_destroy(reply_semaphore);
00223       lock_set_dealloc(reply_semaphore);
00224    };
00225    entry_semaphore = timer_semaphore = reply_semaphore = 0;
00226    if (timer_group_lock) shm_free(timer_group_lock);
00227 
00228 }
00229 #endif /*GEN_LOCK_T_PREFERED*/
00230 
00231 
00232 int init_cell_lock( struct cell *cell )
00233 {
00234 #ifdef GEN_LOCK_T_PREFERED
00235    lock_init(&cell->reply_mutex);
00236 #else
00237    cell->reply_mutex.semaphore_set=reply_semaphore;
00238    cell->reply_mutex.semaphore_index = cell->hash_index % sem_nr;
00239 #endif /* GEN_LOCK_T_PREFERED */
00240    return 0;
00241 }
00242 
00243 
00244 int init_entry_lock( struct s_table* ht, struct entry *entry )
00245 {
00246 #ifdef GEN_LOCK_T_PREFERED
00247    lock_init(&entry->mutex);
00248 #else
00249    /* just advice which of the available semaphores to use;
00250       specifically, all entries are partitioned into as
00251       many partitions as number of available semaphores allows
00252         */
00253    entry->mutex.semaphore_set=entry_semaphore;
00254    entry->mutex.semaphore_index = ( ((char *)entry - (char *)(ht->entrys ) )
00255                / sizeof(struct entry) ) % sem_nr;
00256 #endif
00257    return 0;
00258 }
00259 
00260 
00261 int init_timerlist_lock( enum lists timerlist_id)
00262 {
00263    get_timertable()->timers[timerlist_id].mutex=
00264       &(timer_group_lock[ timer_group[timerlist_id] ]);
00265    return 0;
00266 }

Generated on Wed May 23 18:00:28 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6