nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #include <pthread.h> 00040 #include <stdio.h> 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <execinfo.h> 00044 #include "RW_Lock.h" 00045 #include <execinfo.h> 00046 #include <malloc.h> 00047 #include <assert.h> 00048 00049 /* 00050 * Debugging function 00051 */ 00052 static inline void print_lock(char *s, rw_lock_t * plock) 00053 { 00054 00055 LogFullDebug(COMPONENT_RW_LOCK, 00056 "%s: id = %u: Lock:%p State: nbr_active = %d, nbr_waiting = %d, nbw_active = %d, nbw_waiting = %d", 00057 s, (unsigned int)pthread_self(), plock, plock->nbr_active, plock->nbr_waiting, 00058 plock->nbw_active, plock->nbw_waiting); 00059 } /* print_lock */ 00060 00061 #define DEBUG_STACK_SIZE 1000 00062 void dbg_backtrace(void) 00063 { 00064 int j, nptrs; 00065 void *buffer[DEBUG_STACK_SIZE]; 00066 char **strings; 00067 00068 nptrs = backtrace(buffer, DEBUG_STACK_SIZE); 00069 00070 strings = backtrace_symbols(buffer, nptrs); 00071 if (strings == NULL) 00072 { 00073 LogFullDebug(COMPONENT_RW_LOCK, "dbg_backtrace...No symbols found.\n"); 00074 return; 00075 } 00076 00077 for (j = 0; j < nptrs; j++) 00078 LogFullDebug(COMPONENT_RW_LOCK, "backtrace: %s\n", strings[j]); 00079 00080 free(strings); 00081 } 00082 00083 00084 /* 00085 * Take the lock for reading 00086 */ 00087 int P_r(rw_lock_t * plock) 00088 { 00089 P(plock->mutexProtect); 00090 00091 print_lock("P_r.1", plock); 00092 00093 plock->nbr_waiting++; 00094 00095 /* no new read lock is granted if writters are waiting or active */ 00096 while(plock->nbw_active > 0 || plock->nbw_waiting > 0) 00097 pthread_cond_wait(&(plock->condRead), &(plock->mutexProtect)); 00098 00099 assert(plock->nbw_active == 0); 00100 assert(plock->nbw_waiting == 0); 00101 00102 /* There is no active or waiting writters, readers can go ... */ 00103 plock->nbr_waiting--; 00104 plock->nbr_active++; 00105 assert(plock->nbr_waiting >= 0); 00106 00107 print_lock("P_r.end", plock); 00108 V(plock->mutexProtect); 00109 00110 00111 return 0; 00112 } /* P_r */ 00113 00114 /* 00115 * Release the lock after reading 00116 */ 00117 int V_r(rw_lock_t * plock) 00118 { 00119 P(plock->mutexProtect); 00120 00121 print_lock("V_r.1", plock); 00122 00123 /* I am a reader that is no more active */ 00124 if(plock->nbr_active == 0) 00125 // TODO: Failing on virtual machines 00126 // dbg_backtrace(); 00127 print_lock("V_r.1_1", plock); 00128 else 00129 plock->nbr_active--; 00130 00131 00132 /* I was the last active reader, and there are some waiting writters, I let one of them go */ 00133 if(plock->nbr_active == 0 && plock->nbw_waiting > 0) 00134 { 00135 print_lock("V_r.2 lecteur libere un redacteur", plock); 00136 pthread_cond_signal(&plock->condWrite); 00137 } 00138 00139 print_lock("V_r.end", plock); 00140 00141 V(plock->mutexProtect); 00142 00143 return 0; 00144 } /* V_r */ 00145 00146 /* 00147 * Take the lock for writting 00148 */ 00149 int P_w(rw_lock_t * plock) 00150 { 00151 P(plock->mutexProtect); 00152 00153 print_lock("P_w.1", plock); 00154 00155 plock->nbw_waiting++; 00156 00157 /* nobody must be active obtain exclusive lock */ 00158 while(plock->nbr_active > 0 || plock->nbw_active > 0) 00159 pthread_cond_wait(&plock->condWrite, &plock->mutexProtect); 00160 assert(plock->nbr_active == 0); 00161 assert(plock->nbw_active == 0); 00162 00163 assert(plock->nbr_active==0); 00164 assert(plock->nbw_active==0); 00165 00166 /* I become active and no more waiting */ 00167 plock->nbw_waiting--; 00168 plock->nbw_active++; 00169 assert(plock->nbw_waiting >= 0); 00170 00171 print_lock("P_w.end", plock); 00172 V(plock->mutexProtect); 00173 00174 return 0; 00175 } /* P_w */ 00176 00177 /* 00178 * Release the lock after writting 00179 */ 00180 int V_w(rw_lock_t * plock) 00181 { 00182 P(plock->mutexProtect); 00183 00184 print_lock("V_w.1", plock); 00185 00186 /* I was the active writter, I am not it any more */ 00187 if(plock->nbw_active == 0) 00188 // TODO: Failing on virtual machines 00189 //dbg_backtrace(); 00190 print_lock("V_w.1_1", plock); 00191 else 00192 plock->nbw_active--; 00193 00194 if(plock->nbw_waiting > 0) 00195 { 00196 00197 print_lock("V_w.4 redacteur libere un lecteur", plock); 00198 00199 /* There are waiting writters, but no waiting readers, I let a writter go */ 00200 pthread_cond_signal(&(plock->condWrite)); 00201 00202 print_lock("V_w.5", plock); 00203 00204 } 00205 else if(plock->nbr_waiting > 0) 00206 { 00207 /* if readers are waiting, let them go */ 00208 print_lock("V_w.2 redacteur libere les lecteurs", plock); 00209 pthread_cond_broadcast(&(plock->condRead)); 00210 00211 print_lock("V_w.3", plock); 00212 00213 } 00214 print_lock("V_w.end", plock); 00215 V(plock->mutexProtect); 00216 00217 00218 return 0; 00219 } /* V_w */ 00220 00221 /* Roughly, downgrading a writer lock is making a V_w atomically followed by a P_r */ 00222 int rw_lock_downgrade(rw_lock_t * plock) 00223 { 00224 P(plock->mutexProtect); 00225 00226 print_lock("downgrade.1", plock); 00227 00228 /* I was the active writter, I am not it any more */ 00229 if(plock->nbw_active == 0) 00230 // TODO: Failing on virtual machines 00231 // dbg_backtrace(); 00232 print_lock("downgrade.1_1", plock); 00233 else 00234 plock->nbw_active--; 00235 00236 if(plock->nbr_waiting > 0) 00237 { 00238 00239 /* there are waiting readers, I let all the readers go */ 00240 print_lock("downgrade.2 libere les lecteurs", plock); 00241 pthread_cond_broadcast(&(plock->condRead)); 00242 00243 } 00244 00245 /* nobody must break caller's read lock, so don't consider or unlock writers */ 00246 00247 /* caller is also a reader, now */ 00248 plock->nbr_active++; 00249 00250 print_lock("downgrade.end", plock); 00251 V(plock->mutexProtect); 00252 00253 00254 return 0; 00255 00256 } /* rw_lock_downgrade */ 00257 00258 /* 00259 * Routine for initializing a lock 00260 */ 00261 int rw_lock_init(rw_lock_t * plock) 00262 { 00263 int rc = 0; 00264 pthread_mutexattr_t mutex_attr; 00265 pthread_condattr_t cond_attr; 00266 00267 if((rc = pthread_mutexattr_init(&mutex_attr)) != 0) 00268 return 1; 00269 if((rc = pthread_condattr_init(&cond_attr)) != 0) 00270 return 1; 00271 00272 if((rc = pthread_mutex_init(&(plock->mutexProtect), &mutex_attr)) != 0) 00273 return 1; 00274 00275 if((rc = pthread_cond_init(&(plock->condRead), &cond_attr)) != 0) 00276 return 1; 00277 if((rc = pthread_cond_init(&(plock->condWrite), &cond_attr)) != 0) 00278 return 1; 00279 00280 plock->nbr_waiting = 0; 00281 plock->nbr_active = 0; 00282 00283 plock->nbw_waiting = 0; 00284 plock->nbw_active = 0; 00285 00286 return 0; 00287 } /* rw_lock_init */ 00288 00289 /* 00290 * Routine for destroying a lock 00291 */ 00292 int rw_lock_destroy(rw_lock_t * plock) 00293 { 00294 int rc = 0; 00295 00296 if((rc = pthread_mutex_destroy(&(plock->mutexProtect))) != 0) 00297 return 1; 00298 00299 if((rc = pthread_cond_destroy(&(plock->condWrite))) != 0) 00300 return 1; 00301 if((rc = pthread_cond_destroy(&(plock->condRead))) != 0) 00302 return 1; 00303 00304 memset(plock, 0, sizeof(rw_lock_t)); 00305 00306 return 0; 00307 } /* rw_lock_init */