![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
lock.h
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * \brief General Asterisk channel locking definitions. 00021 * 00022 * - See \ref LockDef 00023 */ 00024 00025 /*! \page LockDef Asterisk thread locking models 00026 * 00027 * This file provides different implementation of the functions, 00028 * depending on the platform, the use of DEBUG_THREADS, and the way 00029 * module-level mutexes are initialized. 00030 * 00031 * - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE 00032 * this is done at compile time, and is the way used on Linux. 00033 * This method is not applicable to all platforms e.g. when the 00034 * initialization needs that some code is run. 00035 * 00036 * - \b through constructors: for each mutex, a constructor function is 00037 * defined, which then runs when the program (or the module) 00038 * starts. The problem with this approach is that there is a 00039 * lot of code duplication (a new block of code is created for 00040 * each mutex). Also, it does not prevent a user from declaring 00041 * a global mutex without going through the wrapper macros, 00042 * so sane programming practices are still required. 00043 */ 00044 00045 #ifndef _ASTERISK_LOCK_H 00046 #define _ASTERISK_LOCK_H 00047 00048 #include <pthread.h> 00049 #include <netdb.h> 00050 #include <time.h> 00051 #include <sys/param.h> 00052 00053 #include "asterisk/logger.h" 00054 00055 /* internal macro to profile mutexes. Only computes the delay on 00056 * non-blocking calls. 00057 */ 00058 #ifndef HAVE_MTX_PROFILE 00059 #define __MTX_PROF(a) return pthread_mutex_lock((a)) 00060 #else 00061 #define __MTX_PROF(a) do { \ 00062 int i; \ 00063 /* profile only non-blocking events */ \ 00064 ast_mark(mtx_prof, 1); \ 00065 i = pthread_mutex_trylock((a)); \ 00066 ast_mark(mtx_prof, 0); \ 00067 if (!i) \ 00068 return i; \ 00069 else \ 00070 return pthread_mutex_lock((a)); \ 00071 } while (0) 00072 #endif /* HAVE_MTX_PROFILE */ 00073 00074 #define AST_PTHREADT_NULL (pthread_t) -1 00075 #define AST_PTHREADT_STOP (pthread_t) -2 00076 00077 #if defined(SOLARIS) || defined(BSD) 00078 #define AST_MUTEX_INIT_W_CONSTRUCTORS 00079 #endif /* SOLARIS || BSD */ 00080 00081 /* Asterisk REQUIRES recursive (not error checking) mutexes 00082 and will not run without them. */ 00083 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) 00084 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00085 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP 00086 #else 00087 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER 00088 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE 00089 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ 00090 00091 #ifdef DEBUG_THREADS 00092 00093 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0) 00094 00095 #ifdef THREAD_CRASH 00096 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0) 00097 #else 00098 #define DO_THREAD_CRASH do { } while (0) 00099 #endif 00100 00101 #include <errno.h> 00102 #include <string.h> 00103 #include <stdio.h> 00104 #include <unistd.h> 00105 00106 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } } 00107 00108 #define AST_MAX_REENTRANCY 10 00109 00110 struct ast_mutex_info { 00111 pthread_mutex_t mutex; 00112 const char *file[AST_MAX_REENTRANCY]; 00113 int lineno[AST_MAX_REENTRANCY]; 00114 int reentrancy; 00115 const char *func[AST_MAX_REENTRANCY]; 00116 pthread_t thread[AST_MAX_REENTRANCY]; 00117 }; 00118 00119 typedef struct ast_mutex_info ast_mutex_t; 00120 00121 typedef pthread_cond_t ast_cond_t; 00122 00123 static pthread_mutex_t empty_mutex; 00124 00125 static void __attribute__((constructor)) init_empty_mutex(void) 00126 { 00127 memset(&empty_mutex, 0, sizeof(empty_mutex)); 00128 } 00129 00130 static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func, 00131 const char *mutex_name, ast_mutex_t *t, 00132 pthread_mutexattr_t *attr) 00133 { 00134 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS 00135 int canlog = strcmp(filename, "logger.c"); 00136 00137 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00138 if ((t->mutex) != (empty_mutex)) { 00139 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n", 00140 filename, lineno, func, mutex_name); 00141 __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n", 00142 t->file[0], t->lineno[0], t->func[0], mutex_name); 00143 DO_THREAD_CRASH; 00144 return 0; 00145 } 00146 } 00147 #endif 00148 00149 t->file[0] = filename; 00150 t->lineno[0] = lineno; 00151 t->func[0] = func; 00152 t->thread[0] = 0; 00153 t->reentrancy = 0; 00154 00155 return pthread_mutex_init(&t->mutex, attr); 00156 } 00157 00158 static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func, 00159 const char *mutex_name, ast_mutex_t *t) 00160 { 00161 static pthread_mutexattr_t attr; 00162 00163 pthread_mutexattr_init(&attr); 00164 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND); 00165 00166 return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr); 00167 } 00168 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex) 00169 00170 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func, 00171 const char *mutex_name, ast_mutex_t *t) 00172 { 00173 int res; 00174 int canlog = strcmp(filename, "logger.c"); 00175 00176 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS 00177 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00178 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00179 filename, lineno, func, mutex_name); 00180 } 00181 #endif 00182 00183 res = pthread_mutex_trylock(&t->mutex); 00184 switch (res) { 00185 case 0: 00186 pthread_mutex_unlock(&t->mutex); 00187 break; 00188 case EINVAL: 00189 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n", 00190 filename, lineno, func, mutex_name); 00191 break; 00192 case EBUSY: 00193 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n", 00194 filename, lineno, func, mutex_name); 00195 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n", 00196 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); 00197 break; 00198 } 00199 00200 if ((res = pthread_mutex_destroy(&t->mutex))) 00201 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n", 00202 filename, lineno, func, strerror(res)); 00203 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00204 else 00205 t->mutex = PTHREAD_MUTEX_INIT_VALUE; 00206 #endif 00207 t->file[0] = filename; 00208 t->lineno[0] = lineno; 00209 t->func[0] = func; 00210 00211 return res; 00212 } 00213 00214 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, 00215 const char* mutex_name, ast_mutex_t *t) 00216 { 00217 int res; 00218 int canlog = strcmp(filename, "logger.c"); 00219 00220 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) 00221 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00222 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00223 filename, lineno, func, mutex_name); 00224 ast_mutex_init(t); 00225 } 00226 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ 00227 00228 #ifdef DETECT_DEADLOCKS 00229 { 00230 time_t seconds = time(NULL); 00231 time_t current; 00232 do { 00233 #ifdef HAVE_MTX_PROFILE 00234 ast_mark(mtx_prof, 1); 00235 #endif 00236 res = pthread_mutex_trylock(&t->mutex); 00237 #ifdef HAVE_MTX_PROFILE 00238 ast_mark(mtx_prof, 0); 00239 #endif 00240 if (res == EBUSY) { 00241 current = time(NULL); 00242 if ((current - seconds) && (!((current - seconds) % 5))) { 00243 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", 00244 filename, lineno, func, (int)(current - seconds), mutex_name); 00245 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", 00246 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], 00247 t->func[t->reentrancy-1], mutex_name); 00248 } 00249 usleep(200); 00250 } 00251 } while (res == EBUSY); 00252 } 00253 #else 00254 #ifdef HAVE_MTX_PROFILE 00255 ast_mark(mtx_prof, 1); 00256 res = pthread_mutex_trylock(&t->mutex); 00257 ast_mark(mtx_prof, 0); 00258 if (res) 00259 #endif 00260 res = pthread_mutex_lock(&t->mutex); 00261 #endif /* DETECT_DEADLOCKS */ 00262 00263 if (!res) { 00264 if (t->reentrancy < AST_MAX_REENTRANCY) { 00265 t->file[t->reentrancy] = filename; 00266 t->lineno[t->reentrancy] = lineno; 00267 t->func[t->reentrancy] = func; 00268 t->thread[t->reentrancy] = pthread_self(); 00269 t->reentrancy++; 00270 } else { 00271 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", 00272 filename, lineno, func, mutex_name); 00273 } 00274 } else { 00275 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n", 00276 filename, lineno, func, strerror(errno)); 00277 DO_THREAD_CRASH; 00278 } 00279 00280 return res; 00281 } 00282 00283 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, 00284 const char* mutex_name, ast_mutex_t *t) 00285 { 00286 int res; 00287 int canlog = strcmp(filename, "logger.c"); 00288 00289 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) 00290 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00291 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00292 filename, lineno, func, mutex_name); 00293 ast_mutex_init(t); 00294 } 00295 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ 00296 00297 if (!(res = pthread_mutex_trylock(&t->mutex))) { 00298 if (t->reentrancy < AST_MAX_REENTRANCY) { 00299 t->file[t->reentrancy] = filename; 00300 t->lineno[t->reentrancy] = lineno; 00301 t->func[t->reentrancy] = func; 00302 t->thread[t->reentrancy] = pthread_self(); 00303 t->reentrancy++; 00304 } else { 00305 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", 00306 filename, lineno, func, mutex_name); 00307 } 00308 } else { 00309 __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n", 00310 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); 00311 } 00312 00313 return res; 00314 } 00315 00316 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, 00317 const char *mutex_name, ast_mutex_t *t) 00318 { 00319 int res; 00320 int canlog = strcmp(filename, "logger.c"); 00321 00322 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS 00323 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00324 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00325 filename, lineno, func, mutex_name); 00326 } 00327 #endif 00328 00329 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) { 00330 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n", 00331 filename, lineno, func, mutex_name); 00332 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", 00333 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); 00334 DO_THREAD_CRASH; 00335 } 00336 00337 if (--t->reentrancy < 0) { 00338 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n", 00339 filename, lineno, func, mutex_name); 00340 t->reentrancy = 0; 00341 } 00342 00343 if (t->reentrancy < AST_MAX_REENTRANCY) { 00344 t->file[t->reentrancy] = NULL; 00345 t->lineno[t->reentrancy] = 0; 00346 t->func[t->reentrancy] = NULL; 00347 t->thread[t->reentrancy] = 0; 00348 } 00349 00350 if ((res = pthread_mutex_unlock(&t->mutex))) { 00351 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 00352 filename, lineno, func, strerror(res)); 00353 DO_THREAD_CRASH; 00354 } 00355 00356 return res; 00357 } 00358 00359 static inline int __ast_cond_init(const char *filename, int lineno, const char *func, 00360 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr) 00361 { 00362 return pthread_cond_init(cond, cond_attr); 00363 } 00364 00365 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func, 00366 const char *cond_name, ast_cond_t *cond) 00367 { 00368 return pthread_cond_signal(cond); 00369 } 00370 00371 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func, 00372 const char *cond_name, ast_cond_t *cond) 00373 { 00374 return pthread_cond_broadcast(cond); 00375 } 00376 00377 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func, 00378 const char *cond_name, ast_cond_t *cond) 00379 { 00380 return pthread_cond_destroy(cond); 00381 } 00382 00383 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func, 00384 const char *cond_name, const char *mutex_name, 00385 ast_cond_t *cond, ast_mutex_t *t) 00386 { 00387 int res; 00388 int canlog = strcmp(filename, "logger.c"); 00389 00390 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS 00391 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00392 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00393 filename, lineno, func, mutex_name); 00394 } 00395 #endif 00396 00397 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) { 00398 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n", 00399 filename, lineno, func, mutex_name); 00400 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", 00401 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); 00402 DO_THREAD_CRASH; 00403 } 00404 00405 if (--t->reentrancy < 0) { 00406 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n", 00407 filename, lineno, func, mutex_name); 00408 t->reentrancy = 0; 00409 } 00410 00411 if (t->reentrancy < AST_MAX_REENTRANCY) { 00412 t->file[t->reentrancy] = NULL; 00413 t->lineno[t->reentrancy] = 0; 00414 t->func[t->reentrancy] = NULL; 00415 t->thread[t->reentrancy] = 0; 00416 } 00417 00418 if ((res = pthread_cond_wait(cond, &t->mutex))) { 00419 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 00420 filename, lineno, func, strerror(res)); 00421 DO_THREAD_CRASH; 00422 } else { 00423 if (t->reentrancy < AST_MAX_REENTRANCY) { 00424 t->file[t->reentrancy] = filename; 00425 t->lineno[t->reentrancy] = lineno; 00426 t->func[t->reentrancy] = func; 00427 t->thread[t->reentrancy] = pthread_self(); 00428 t->reentrancy++; 00429 } else { 00430 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", 00431 filename, lineno, func, mutex_name); 00432 } 00433 } 00434 00435 return res; 00436 } 00437 00438 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func, 00439 const char *cond_name, const char *mutex_name, ast_cond_t *cond, 00440 ast_mutex_t *t, const struct timespec *abstime) 00441 { 00442 int res; 00443 int canlog = strcmp(filename, "logger.c"); 00444 00445 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS 00446 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { 00447 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n", 00448 filename, lineno, func, mutex_name); 00449 } 00450 #endif 00451 00452 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) { 00453 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n", 00454 filename, lineno, func, mutex_name); 00455 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", 00456 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); 00457 DO_THREAD_CRASH; 00458 } 00459 00460 if (--t->reentrancy < 0) { 00461 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n", 00462 filename, lineno, func, mutex_name); 00463 t->reentrancy = 0; 00464 } 00465 00466 if (t->reentrancy < AST_MAX_REENTRANCY) { 00467 t->file[t->reentrancy] = NULL; 00468 t->lineno[t->reentrancy] = 0; 00469 t->func[t->reentrancy] = NULL; 00470 t->thread[t->reentrancy] = 0; 00471 } 00472 00473 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) { 00474 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 00475 filename, lineno, func, strerror(res)); 00476 DO_THREAD_CRASH; 00477 } else { 00478 if (t->reentrancy < AST_MAX_REENTRANCY) { 00479 t->file[t->reentrancy] = filename; 00480 t->lineno[t->reentrancy] = lineno; 00481 t->func[t->reentrancy] = func; 00482 t->thread[t->reentrancy] = pthread_self(); 00483 t->reentrancy++; 00484 } else { 00485 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", 00486 filename, lineno, func, mutex_name); 00487 } 00488 } 00489 00490 return res; 00491 } 00492 00493 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) 00494 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) 00495 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) 00496 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) 00497 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr) 00498 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond) 00499 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond) 00500 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond) 00501 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex) 00502 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time) 00503 00504 #else /* !DEBUG_THREADS */ 00505 00506 00507 typedef pthread_mutex_t ast_mutex_t; 00508 00509 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE) 00510 00511 static inline int ast_mutex_init(ast_mutex_t *pmutex) 00512 { 00513 pthread_mutexattr_t attr; 00514 00515 pthread_mutexattr_init(&attr); 00516 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND); 00517 00518 return pthread_mutex_init(pmutex, &attr); 00519 } 00520 00521 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a) 00522 00523 static inline int ast_mutex_unlock(ast_mutex_t *pmutex) 00524 { 00525 return pthread_mutex_unlock(pmutex); 00526 } 00527 00528 static inline int ast_mutex_destroy(ast_mutex_t *pmutex) 00529 { 00530 return pthread_mutex_destroy(pmutex); 00531 } 00532 00533 static inline int ast_mutex_lock(ast_mutex_t *pmutex) 00534 { 00535 __MTX_PROF(pmutex); 00536 } 00537 00538 static inline int ast_mutex_trylock(ast_mutex_t *pmutex) 00539 { 00540 return pthread_mutex_trylock(pmutex); 00541 } 00542 00543 typedef pthread_cond_t ast_cond_t; 00544 00545 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr) 00546 { 00547 return pthread_cond_init(cond, cond_attr); 00548 } 00549 00550 static inline int ast_cond_signal(ast_cond_t *cond) 00551 { 00552 return pthread_cond_signal(cond); 00553 } 00554 00555 static inline int ast_cond_broadcast(ast_cond_t *cond) 00556 { 00557 return pthread_cond_broadcast(cond); 00558 } 00559 00560 static inline int ast_cond_destroy(ast_cond_t *cond) 00561 { 00562 return pthread_cond_destroy(cond); 00563 } 00564 00565 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t) 00566 { 00567 return pthread_cond_wait(cond, t); 00568 } 00569 00570 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime) 00571 { 00572 return pthread_cond_timedwait(cond, t, abstime); 00573 } 00574 00575 #endif /* !DEBUG_THREADS */ 00576 00577 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) 00578 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope 00579 constructors/destructors to create/destroy mutexes. */ 00580 #define __AST_MUTEX_DEFINE(scope, mutex) \ 00581 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \ 00582 static void __attribute__ ((constructor)) init_##mutex(void) \ 00583 { \ 00584 ast_mutex_init(&mutex); \ 00585 } \ 00586 static void __attribute__ ((destructor)) fini_##mutex(void) \ 00587 { \ 00588 ast_mutex_destroy(&mutex); \ 00589 } 00590 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */ 00591 /* By default, use static initialization of mutexes. */ 00592 #define __AST_MUTEX_DEFINE(scope, mutex) \ 00593 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE 00594 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ 00595 00596 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t 00597 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock 00598 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock 00599 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock 00600 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init 00601 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy 00602 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t 00603 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init 00604 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy 00605 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal 00606 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast 00607 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait 00608 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait 00609 00610 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex) 00611 00612 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__ 00613 00614 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__ 00615 00616 #ifndef __linux__ 00617 #define pthread_create __use_ast_pthread_create_instead__ 00618 #endif 00619 00620 typedef pthread_rwlock_t ast_rwlock_t; 00621 00622 static inline int ast_rwlock_init(ast_rwlock_t *prwlock) 00623 { 00624 pthread_rwlockattr_t attr; 00625 00626 pthread_rwlockattr_init(&attr); 00627 00628 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP 00629 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP); 00630 #endif 00631 00632 return pthread_rwlock_init(prwlock, &attr); 00633 } 00634 00635 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock) 00636 { 00637 return pthread_rwlock_destroy(prwlock); 00638 } 00639 00640 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock) 00641 { 00642 return pthread_rwlock_unlock(prwlock); 00643 } 00644 00645 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock) 00646 { 00647 return pthread_rwlock_rdlock(prwlock); 00648 } 00649 00650 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock) 00651 { 00652 return pthread_rwlock_tryrdlock(prwlock); 00653 } 00654 00655 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock) 00656 { 00657 return pthread_rwlock_wrlock(prwlock); 00658 } 00659 00660 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock) 00661 { 00662 return pthread_rwlock_trywrlock(prwlock); 00663 } 00664 00665 /* Statically declared read/write locks */ 00666 00667 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER 00668 #define __AST_RWLOCK_DEFINE(scope, rwlock) \ 00669 scope ast_rwlock_t rwlock; \ 00670 static void __attribute__ ((constructor)) init_##rwlock(void) \ 00671 { \ 00672 ast_rwlock_init(&rwlock); \ 00673 } \ 00674 static void __attribute__ ((destructor)) fini_##rwlock(void) \ 00675 { \ 00676 ast_rwlock_destroy(&rwlock); \ 00677 } 00678 #else 00679 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER 00680 #define __AST_RWLOCK_DEFINE(scope, rwlock) \ 00681 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE 00682 #endif 00683 00684 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock) 00685 00686 /* 00687 * Initial support for atomic instructions. 00688 * For platforms that have it, use the native cpu instruction to 00689 * implement them. For other platforms, resort to a 'slow' version 00690 * (defined in utils.c) that protects the atomic instruction with 00691 * a single lock. 00692 * The slow versions is always available, for testing purposes, 00693 * as ast_atomic_fetchadd_int_slow() 00694 */ 00695 00696 int ast_atomic_fetchadd_int_slow(volatile int *p, int v); 00697 00698 #include "asterisk/inline_api.h" 00699 00700 #if defined(HAVE_OSX_ATOMICS) 00701 #include "libkern/OSAtomic.h" 00702 #endif 00703 00704 /*! \brief Atomically add v to *p and return * the previous value of *p. 00705 * This can be used to handle reference counts, and the return value 00706 * can be used to generate unique identifiers. 00707 */ 00708 00709 #if defined(HAVE_GCC_ATOMICS) 00710 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), 00711 { 00712 return __sync_fetch_and_add(p, v); 00713 }) 00714 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4) 00715 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), 00716 { 00717 return OSAtomicAdd32(v, (int32_t *) p); 00718 }) 00719 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8) 00720 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), 00721 { 00722 return OSAtomicAdd64(v, (int64_t *) p); 00723 #elif defined (__i386__) 00724 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), 00725 { 00726 __asm __volatile ( 00727 " lock xaddl %0, %1 ; " 00728 : "+r" (v), /* 0 (result) */ 00729 "=m" (*p) /* 1 */ 00730 : "m" (*p)); /* 2 */ 00731 return (v); 00732 }) 00733 #else /* low performance version in utils.c */ 00734 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v), 00735 { 00736 return ast_atomic_fetchadd_int_slow(p, v); 00737 }) 00738 #endif 00739 00740 /*! \brief decrement *p by 1 and return true if the variable has reached 0. 00741 * Useful e.g. to check if a refcount has reached 0. 00742 */ 00743 #if defined(HAVE_GCC_ATOMICS) 00744 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p), 00745 { 00746 return __sync_sub_and_fetch(p, 1) == 0; 00747 }) 00748 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4) 00749 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p), 00750 { 00751 return OSAtomicAdd32( -1, (int32_t *) p) == 0; 00752 }) 00753 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8) 00754 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p), 00755 { 00756 return OSAtomicAdd64( -1, (int64_t *) p) == 0; 00757 #else 00758 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p), 00759 { 00760 int a = ast_atomic_fetchadd_int(p, -1); 00761 return a == 1; /* true if the value is 0 now (so it was 1 previously) */ 00762 }) 00763 #endif 00764 00765 #ifndef DEBUG_CHANNEL_LOCKS 00766 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 00767 in the Makefile, print relevant output for debugging */ 00768 #define ast_channel_lock(x) ast_mutex_lock(&x->lock) 00769 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 00770 in the Makefile, print relevant output for debugging */ 00771 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock) 00772 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 00773 in the Makefile, print relevant output for debugging */ 00774 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock) 00775 #else 00776 00777 struct ast_channel; 00778 00779 /*! \brief Lock AST channel (and print debugging output) 00780 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */ 00781 int ast_channel_lock(struct ast_channel *chan); 00782 00783 /*! \brief Unlock AST channel (and print debugging output) 00784 \note You need to enable DEBUG_CHANNEL_LOCKS for this function 00785 */ 00786 int ast_channel_unlock(struct ast_channel *chan); 00787 00788 /*! \brief Lock AST channel (and print debugging output) 00789 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */ 00790 int ast_channel_trylock(struct ast_channel *chan); 00791 #endif 00792 00793 #endif /* _ASTERISK_LOCK_H */