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