Thu Oct 11 06:42:08 2012

Asterisk developer's documentation


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 #include <unistd.h>
00053 
00054 #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
00055 #include "asterisk/time.h"
00056 #endif
00057 #include "asterisk/logger.h"
00058 #include "asterisk/compiler.h"
00059 
00060 /* internal macro to profile mutexes. Only computes the delay on
00061  * non-blocking calls.
00062  */
00063 #ifndef  HAVE_MTX_PROFILE
00064 #define  __MTX_PROF(a)  return pthread_mutex_lock((a))
00065 #else
00066 #define  __MTX_PROF(a)  do {        \
00067    int i;               \
00068    /* profile only non-blocking events */ \
00069    ast_mark(mtx_prof, 1);        \
00070    i = pthread_mutex_trylock((a));     \
00071    ast_mark(mtx_prof, 0);        \
00072    if (!i)              \
00073       return i;         \
00074    else              \
00075       return pthread_mutex_lock((a)); \
00076    } while (0)
00077 #endif   /* HAVE_MTX_PROFILE */
00078 
00079 #define AST_PTHREADT_NULL (pthread_t) -1
00080 #define AST_PTHREADT_STOP (pthread_t) -2
00081 
00082 #if defined(SOLARIS) || defined(BSD)
00083 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00084 #endif /* SOLARIS || BSD */
00085 
00086 /* Asterisk REQUIRES recursive (not error checking) mutexes
00087    and will not run without them. */
00088 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
00089 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00090 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE_NP
00091 #else
00092 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00093 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE
00094 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
00095 
00096 #ifdef DEBUG_THREADS
00097 
00098 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00099 
00100 #ifdef THREAD_CRASH
00101 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00102 #else
00103 #define DO_THREAD_CRASH do { } while (0)
00104 #endif
00105 
00106 #include <errno.h>
00107 #include <string.h>
00108 #include <stdio.h>
00109 
00110 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00111 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00112                              { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00113 
00114 #define AST_MAX_REENTRANCY 10
00115 
00116 struct ast_mutex_info {
00117    pthread_mutex_t mutex;
00118    /*! Track which thread holds this lock */
00119    unsigned int track:1;
00120    const char *file[AST_MAX_REENTRANCY];
00121    int lineno[AST_MAX_REENTRANCY];
00122    int reentrancy;
00123    const char *func[AST_MAX_REENTRANCY];
00124    pthread_t thread[AST_MAX_REENTRANCY];
00125    pthread_mutex_t reentr_mutex;
00126 };
00127 
00128 typedef struct ast_mutex_info ast_mutex_t;
00129 
00130 typedef pthread_cond_t ast_cond_t;
00131 
00132 static pthread_mutex_t empty_mutex;
00133 
00134 enum ast_lock_type {
00135    AST_MUTEX,
00136    AST_RDLOCK,
00137    AST_WRLOCK,
00138 };
00139 
00140 /*!
00141  * \brief Store lock info for the current thread
00142  *
00143  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
00144  * that information about this lock can be stored in this thread's
00145  * lock info struct.  The lock is marked as pending as the thread is waiting
00146  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
00147  */
00148 #if !defined(LOW_MEMORY)
00149 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00150    int line_num, const char *func, const char *lock_name, void *lock_addr);
00151 #else
00152 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
00153 #endif
00154 
00155 
00156 /*!
00157  * \brief Mark the last lock as acquired
00158  */
00159 #if !defined(LOW_MEMORY)
00160 void ast_mark_lock_acquired(void *lock_addr);
00161 #else
00162 #define ast_mark_lock_acquired(ignore)
00163 #endif
00164 
00165 /*!
00166  * \brief Mark the last lock as failed (trylock)
00167  */
00168 #if !defined(LOW_MEMORY)
00169 void ast_mark_lock_failed(void *lock_addr);
00170 #else
00171 #define ast_mark_lock_failed(ignore)
00172 #endif
00173 
00174 /*!
00175  * \brief remove lock info for the current thread
00176  *
00177  * this gets called by ast_mutex_unlock so that information on the lock can
00178  * be removed from the current thread's lock info struct.
00179  */
00180 #if !defined(LOW_MEMORY)
00181 void ast_remove_lock_info(void *lock_addr);
00182 #else
00183 #define ast_remove_lock_info(ignore)
00184 #endif
00185 
00186 /*!
00187  * \brief retrieve lock info for the specified mutex
00188  *
00189  * this gets called during deadlock avoidance, so that the information may
00190  * be preserved as to what location originally acquired the lock.
00191  */
00192 #if !defined(LOW_MEMORY)
00193 int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size);
00194 #else
00195 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
00196 #endif
00197 
00198 /*!
00199  * \brief Unlock a lock briefly
00200  *
00201  * used during deadlock avoidance, to preserve the original location where
00202  * a lock was originally acquired.
00203  */
00204 #define DEADLOCK_AVOIDANCE(lock) \
00205    do { \
00206       char __filename[80], __func[80], __mutex_name[80]; \
00207       int __lineno; \
00208       int __res2, __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00209       __res2 = ast_mutex_unlock(lock); \
00210       usleep(1); \
00211       if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
00212          if (__res2 == 0) { \
00213             ast_mutex_lock(lock); \
00214          } else { \
00215             ast_log(LOG_WARNING, "Could not unlock mutex '%s': %s and no lock info found!  I will NOT try to relock.\n", #lock, strerror(__res2)); \
00216          } \
00217       } else { \
00218          if (__res2 == 0) { \
00219             __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00220          } else { \
00221             ast_log(LOG_WARNING, "Could not unlock mutex '%s': %s.  {{{Originally locked at %s line %d: (%s) '%s'}}}  I will NOT try to relock.\n", #lock, strerror(__res2), __filename, __lineno, __func, __mutex_name); \
00222          } \
00223       } \
00224    } while (0)
00225 
00226 static void __attribute__((constructor)) init_empty_mutex(void)
00227 {
00228    memset(&empty_mutex, 0, sizeof(empty_mutex));
00229 }
00230 
00231 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
00232 {
00233    pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
00234 }
00235 
00236 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
00237 {
00238    pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
00239 }
00240 
00241 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
00242 {
00243    int i;
00244    pthread_mutexattr_t reentr_attr;
00245 
00246    for (i = 0; i < AST_MAX_REENTRANCY; i++) {
00247       p_ast_mutex->file[i] = NULL;
00248       p_ast_mutex->lineno[i] = 0;
00249       p_ast_mutex->func[i] = NULL;
00250       p_ast_mutex->thread[i] = 0;
00251    }
00252 
00253    p_ast_mutex->reentrancy = 0;
00254 
00255    pthread_mutexattr_init(&reentr_attr);
00256    pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
00257    pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
00258    pthread_mutexattr_destroy(&reentr_attr);
00259 }
00260 
00261 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
00262 {
00263    pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
00264 }
00265 
00266 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
00267                   const char *mutex_name, ast_mutex_t *t) 
00268 {
00269    int res;
00270    pthread_mutexattr_t  attr;
00271 
00272 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00273 
00274    if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00275 /*
00276       int canlog = strcmp(filename, "logger.c") & track;
00277       __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
00278                filename, lineno, func, mutex_name);
00279       DO_THREAD_CRASH;
00280 */
00281       return 0;
00282    }
00283 
00284 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00285 
00286    ast_reentrancy_init(t);
00287    t->track = track;
00288 
00289    pthread_mutexattr_init(&attr);
00290    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00291 
00292    res = pthread_mutex_init(&t->mutex, &attr);
00293    pthread_mutexattr_destroy(&attr);
00294    return res;
00295 }
00296 
00297 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00298 #define ast_mutex_init_notracking(pmutex) \
00299    __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00300 
00301 #define  ROFFSET  ((t->reentrancy > 0) ? (t->reentrancy-1) : 0)
00302 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00303                   const char *mutex_name, ast_mutex_t *t)
00304 {
00305    int res;
00306    int canlog = strcmp(filename, "logger.c") & t->track;
00307 
00308 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00309    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00310       /* Don't try to uninitialize non initialized mutex
00311        * This may no effect on linux
00312        * And always ganerate core on *BSD with 
00313        * linked libpthread
00314        * This not error condition if the mutex created on the fly.
00315        */
00316       __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
00317                filename, lineno, func, mutex_name);
00318       return 0;
00319    }
00320 #endif
00321 
00322    res = pthread_mutex_trylock(&t->mutex);
00323    switch (res) {
00324    case 0:
00325       pthread_mutex_unlock(&t->mutex);
00326       break;
00327    case EINVAL:
00328       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00329               filename, lineno, func, mutex_name);
00330       break;
00331    case EBUSY:
00332       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00333                filename, lineno, func, mutex_name);
00334       ast_reentrancy_lock(t);
00335       __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00336              t->file[ROFFSET], t->lineno[ROFFSET], t->func[ROFFSET], mutex_name);
00337       ast_reentrancy_unlock(t);
00338       break;
00339    }
00340 
00341    if ((res = pthread_mutex_destroy(&t->mutex)))
00342       __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
00343                filename, lineno, func, mutex_name, strerror(res));
00344    ast_reentrancy_lock(t);
00345    t->file[0] = filename;
00346    t->lineno[0] = lineno;
00347    t->func[0] = func;
00348    t->reentrancy = 0;
00349    t->thread[0] = 0;
00350    ast_reentrancy_unlock(t);
00351    delete_reentrancy_cs(t);
00352 
00353    return res;
00354 }
00355 
00356 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00357                                            const char* mutex_name, ast_mutex_t *t)
00358 {
00359    int res;
00360    int canlog = strcmp(filename, "logger.c") & t->track;
00361 
00362 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00363    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00364       /* Don't warn abount uninitialized mutex.
00365        * Simple try to initialize it.
00366        * May be not needed in linux system.
00367        */
00368       res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00369       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00370          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00371                 filename, lineno, func, mutex_name);
00372          return res;
00373       }     
00374    }
00375 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00376 
00377    if (t->track)
00378       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00379 
00380 #ifdef DETECT_DEADLOCKS
00381    {
00382       time_t seconds = time(NULL);
00383       time_t wait_time, reported_wait = 0;
00384       do {
00385 #ifdef   HAVE_MTX_PROFILE
00386          ast_mark(mtx_prof, 1);
00387 #endif
00388          res = pthread_mutex_trylock(&t->mutex);
00389 #ifdef   HAVE_MTX_PROFILE
00390          ast_mark(mtx_prof, 0);
00391 #endif
00392          if (res == EBUSY) {
00393             wait_time = time(NULL) - seconds;
00394             if (wait_time > reported_wait && (wait_time % 5) == 0) {
00395                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00396                         filename, lineno, func, (int) wait_time, mutex_name);
00397                ast_reentrancy_lock(t);
00398                __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00399                         t->file[ROFFSET], t->lineno[ROFFSET],
00400                         t->func[ROFFSET], mutex_name);
00401                ast_reentrancy_unlock(t);
00402                reported_wait = wait_time;
00403             }
00404             usleep(200);
00405          }
00406       } while (res == EBUSY);
00407    }
00408 #else
00409 #ifdef   HAVE_MTX_PROFILE
00410    ast_mark(mtx_prof, 1);
00411    res = pthread_mutex_trylock(&t->mutex);
00412    ast_mark(mtx_prof, 0);
00413    if (res)
00414 #endif
00415    res = pthread_mutex_lock(&t->mutex);
00416 #endif /* DETECT_DEADLOCKS */
00417 
00418    if (!res) {
00419       ast_reentrancy_lock(t);
00420       if (t->reentrancy < AST_MAX_REENTRANCY) {
00421          t->file[t->reentrancy] = filename;
00422          t->lineno[t->reentrancy] = lineno;
00423          t->func[t->reentrancy] = func;
00424          t->thread[t->reentrancy] = pthread_self();
00425          t->reentrancy++;
00426       } else {
00427          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00428                         filename, lineno, func, mutex_name);
00429       }
00430       ast_reentrancy_unlock(t);
00431       if (t->track)
00432          ast_mark_lock_acquired(&t->mutex);
00433    } else {
00434       if (t->track)
00435          ast_remove_lock_info(&t->mutex);
00436       __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00437                filename, lineno, func, strerror(res));
00438       DO_THREAD_CRASH;
00439    }
00440 
00441    return res;
00442 }
00443 
00444 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00445                                               const char* mutex_name, ast_mutex_t *t) attribute_warn_unused_result;
00446 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00447                                               const char* mutex_name, ast_mutex_t *t)
00448 {
00449    int res;
00450    int canlog = strcmp(filename, "logger.c") & t->track;
00451 
00452 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00453    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00454       /* Don't warn abount uninitialized mutex.
00455        * Simple try to initialize it.
00456        * May be not needed in linux system.
00457        */
00458       res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00459       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00460          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00461                 filename, lineno, func, mutex_name);
00462          return res;
00463       }     
00464    }
00465 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00466 
00467    if (t->track)
00468       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00469 
00470    if (!(res = pthread_mutex_trylock(&t->mutex))) {
00471       ast_reentrancy_lock(t);
00472       if (t->reentrancy < AST_MAX_REENTRANCY) {
00473          t->file[t->reentrancy] = filename;
00474          t->lineno[t->reentrancy] = lineno;
00475          t->func[t->reentrancy] = func;
00476          t->thread[t->reentrancy] = pthread_self();
00477          t->reentrancy++;
00478       } else {
00479          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00480                   filename, lineno, func, mutex_name);
00481       }
00482       ast_reentrancy_unlock(t);
00483       if (t->track)
00484          ast_mark_lock_acquired(&t->mutex);
00485    } else if (t->track) {
00486       ast_mark_lock_failed(&t->mutex);
00487    }
00488 
00489    return res;
00490 }
00491 
00492 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00493                     const char *mutex_name, ast_mutex_t *t)
00494 {
00495    int res;
00496    int canlog = strcmp(filename, "logger.c") & t->track;
00497 
00498 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00499    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00500       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00501                filename, lineno, func, mutex_name);
00502       res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00503       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00504          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00505                 filename, lineno, func, mutex_name);
00506       }
00507       return res;
00508    }
00509 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00510 
00511    ast_reentrancy_lock(t);
00512    if (t->reentrancy && (t->thread[ROFFSET] != pthread_self())) {
00513       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00514                filename, lineno, func, mutex_name);
00515       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00516                t->file[ROFFSET], t->lineno[ROFFSET], t->func[ROFFSET], mutex_name);
00517       DO_THREAD_CRASH;
00518    }
00519 
00520    if (--t->reentrancy < 0) {
00521       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00522                filename, lineno, func, mutex_name);
00523       t->reentrancy = 0;
00524    }
00525 
00526    if (t->reentrancy < AST_MAX_REENTRANCY) {
00527       t->file[t->reentrancy] = NULL;
00528       t->lineno[t->reentrancy] = 0;
00529       t->func[t->reentrancy] = NULL;
00530       t->thread[t->reentrancy] = 0;
00531    }
00532    ast_reentrancy_unlock(t);
00533 
00534    if (t->track)
00535       ast_remove_lock_info(&t->mutex);
00536 
00537    if ((res = pthread_mutex_unlock(&t->mutex))) {
00538       __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
00539                filename, lineno, func, strerror(res));
00540       DO_THREAD_CRASH;
00541    }
00542 
00543    return res;
00544 }
00545 
00546 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00547               const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00548 {
00549    return pthread_cond_init(cond, cond_attr);
00550 }
00551 
00552 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00553                 const char *cond_name, ast_cond_t *cond)
00554 {
00555    return pthread_cond_signal(cond);
00556 }
00557 
00558 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00559                    const char *cond_name, ast_cond_t *cond)
00560 {
00561    return pthread_cond_broadcast(cond);
00562 }
00563 
00564 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00565                  const char *cond_name, ast_cond_t *cond)
00566 {
00567    return pthread_cond_destroy(cond);
00568 }
00569 
00570 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00571               const char *cond_name, const char *mutex_name,
00572               ast_cond_t *cond, ast_mutex_t *t)
00573 {
00574    int res;
00575    int canlog = strcmp(filename, "logger.c") & t->track;
00576 
00577 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00578    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00579       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00580                filename, lineno, func, mutex_name);
00581       res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00582       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00583          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00584                 filename, lineno, func, mutex_name);
00585       }
00586       return res;
00587    }
00588 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00589 
00590    ast_reentrancy_lock(t);
00591    if (t->reentrancy && (t->thread[ROFFSET] != pthread_self())) {
00592       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00593                filename, lineno, func, mutex_name);
00594       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00595                t->file[ROFFSET], t->lineno[ROFFSET], t->func[ROFFSET], mutex_name);
00596       DO_THREAD_CRASH;
00597    }
00598 
00599    if (--t->reentrancy < 0) {
00600       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00601                filename, lineno, func, mutex_name);
00602       t->reentrancy = 0;
00603    }
00604 
00605    if (t->reentrancy < AST_MAX_REENTRANCY) {
00606       t->file[t->reentrancy] = NULL;
00607       t->lineno[t->reentrancy] = 0;
00608       t->func[t->reentrancy] = NULL;
00609       t->thread[t->reentrancy] = 0;
00610    }
00611    ast_reentrancy_unlock(t);
00612 
00613    if (t->track)
00614       ast_remove_lock_info(&t->mutex);
00615 
00616    if ((res = pthread_cond_wait(cond, &t->mutex))) {
00617       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
00618                filename, lineno, func, strerror(res));
00619       DO_THREAD_CRASH;
00620    } else {
00621       ast_reentrancy_lock(t);
00622       if (t->reentrancy < AST_MAX_REENTRANCY) {
00623          t->file[t->reentrancy] = filename;
00624          t->lineno[t->reentrancy] = lineno;
00625          t->func[t->reentrancy] = func;
00626          t->thread[t->reentrancy] = pthread_self();
00627          t->reentrancy++;
00628       } else {
00629          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00630                         filename, lineno, func, mutex_name);
00631       }
00632       ast_reentrancy_unlock(t);
00633 
00634       if (t->track)
00635          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00636    }
00637 
00638    return res;
00639 }
00640 
00641 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00642                    const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00643                    ast_mutex_t *t, const struct timespec *abstime)
00644 {
00645    int res;
00646    int canlog = strcmp(filename, "logger.c") & t->track;
00647 
00648 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00649    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00650       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00651                filename, lineno, func, mutex_name);
00652       res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00653       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00654          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00655                 filename, lineno, func, mutex_name);
00656       }
00657       return res;
00658    }
00659 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00660 
00661    ast_reentrancy_lock(t);
00662    if (t->reentrancy && (t->thread[ROFFSET] != pthread_self())) {
00663       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00664                filename, lineno, func, mutex_name);
00665       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00666                t->file[ROFFSET], t->lineno[ROFFSET], t->func[ROFFSET], mutex_name);
00667       DO_THREAD_CRASH;
00668    }
00669 
00670    if (--t->reentrancy < 0) {
00671       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00672                filename, lineno, func, mutex_name);
00673       t->reentrancy = 0;
00674    }
00675 
00676    if (t->reentrancy < AST_MAX_REENTRANCY) {
00677       t->file[t->reentrancy] = NULL;
00678       t->lineno[t->reentrancy] = 0;
00679       t->func[t->reentrancy] = NULL;
00680       t->thread[t->reentrancy] = 0;
00681    }
00682    ast_reentrancy_unlock(t);
00683 
00684    if (t->track)
00685       ast_remove_lock_info(&t->mutex);
00686 
00687    if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00688       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
00689                filename, lineno, func, strerror(res));
00690       DO_THREAD_CRASH;
00691    } else {
00692       ast_reentrancy_lock(t);
00693       if (t->reentrancy < AST_MAX_REENTRANCY) {
00694          t->file[t->reentrancy] = filename;
00695          t->lineno[t->reentrancy] = lineno;
00696          t->func[t->reentrancy] = func;
00697          t->thread[t->reentrancy] = pthread_self();
00698          t->reentrancy++;
00699       } else {
00700          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00701                         filename, lineno, func, mutex_name);
00702       }
00703       ast_reentrancy_unlock(t);
00704 
00705       if (t->track)
00706          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00707    }
00708 
00709    return res;
00710 }
00711 
00712 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00713 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00714 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00715 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00716 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00717 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00718 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00719 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00720 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00721 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00722 
00723 #else /* !DEBUG_THREADS */
00724 
00725 #define  DEADLOCK_AVOIDANCE(lock) \
00726    do { \
00727       int __res; \
00728       if (!(__res = ast_mutex_unlock(lock))) { \
00729          usleep(1); \
00730          ast_mutex_lock(lock); \
00731       } else { \
00732          ast_log(LOG_WARNING, "Failed to unlock mutex '%s' (%s).  I will NOT try to relock. {{{ THIS IS A BUG. }}}\n", #lock, strerror(__res)); \
00733       } \
00734    } while (0)
00735 
00736 
00737 typedef pthread_mutex_t ast_mutex_t;
00738 
00739 #define AST_MUTEX_INIT_VALUE  ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00740 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00741    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00742 
00743 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
00744 
00745 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00746 {
00747    int res;
00748    pthread_mutexattr_t attr;
00749 
00750    pthread_mutexattr_init(&attr);
00751    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00752 
00753    res = pthread_mutex_init(pmutex, &attr);
00754    pthread_mutexattr_destroy(&attr);
00755    return res;
00756 }
00757 
00758 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00759 
00760 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
00761 {
00762    return pthread_mutex_unlock(pmutex);
00763 }
00764 
00765 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
00766 {
00767    return pthread_mutex_destroy(pmutex);
00768 }
00769 
00770 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00771 {
00772    __MTX_PROF(pmutex);
00773 }
00774 
00775 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00776 {
00777    return pthread_mutex_trylock(pmutex);
00778 }
00779 
00780 typedef pthread_cond_t ast_cond_t;
00781 
00782 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
00783 {
00784    return pthread_cond_init(cond, cond_attr);
00785 }
00786 
00787 static inline int ast_cond_signal(ast_cond_t *cond)
00788 {
00789    return pthread_cond_signal(cond);
00790 }
00791 
00792 static inline int ast_cond_broadcast(ast_cond_t *cond)
00793 {
00794    return pthread_cond_broadcast(cond);
00795 }
00796 
00797 static inline int ast_cond_destroy(ast_cond_t *cond)
00798 {
00799    return pthread_cond_destroy(cond);
00800 }
00801 
00802 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
00803 {
00804    return pthread_cond_wait(cond, t);
00805 }
00806 
00807 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
00808 {
00809    return pthread_cond_timedwait(cond, t, abstime);
00810 }
00811 
00812 #endif /* !DEBUG_THREADS */
00813 
00814 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00815 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00816  destructors to destroy mutexes and create it on the fly.  */
00817 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00818    scope ast_mutex_t mutex = init_val; \
00819 static void  __attribute__((constructor)) init_##mutex(void) \
00820 { \
00821    if (track) \
00822       ast_mutex_init(&mutex); \
00823    else \
00824       ast_mutex_init_notracking(&mutex); \
00825 } \
00826 static void  __attribute__((destructor)) fini_##mutex(void) \
00827 { \
00828    ast_mutex_destroy(&mutex); \
00829 }
00830 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
00831 /* By default, use static initialization of mutexes. */ 
00832 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00833    scope ast_mutex_t mutex = init_val
00834 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00835 
00836 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00837 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00838 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00839 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00840 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
00841 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
00842 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
00843 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
00844 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
00845 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
00846 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
00847 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
00848 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
00849 
00850 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
00851 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
00852 
00853 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00854 
00855 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00856 
00857 #ifndef __linux__
00858 #define pthread_create __use_ast_pthread_create_instead__
00859 #endif
00860 
00861 typedef pthread_rwlock_t ast_rwlock_t;
00862 
00863 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
00864 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
00865 #else
00866 #define AST_RWLOCK_INIT_VALUE NULL
00867 #endif
00868 
00869 #ifdef DEBUG_THREADS
00870 
00871 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00872 
00873 
00874 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00875 {
00876    int res;
00877    pthread_rwlockattr_t attr;
00878 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00879         int canlog = strcmp(filename, "logger.c");
00880 
00881         if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00882       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
00883             filename, lineno, func, rwlock_name);
00884       return 0;
00885    }
00886 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00887    pthread_rwlockattr_init(&attr);
00888 
00889 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
00890    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
00891 #endif
00892 
00893    res = pthread_rwlock_init(prwlock, &attr);
00894    pthread_rwlockattr_destroy(&attr);
00895    return res;
00896 }
00897 
00898 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00899 
00900 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00901 {
00902    int res;
00903    int canlog = strcmp(filename, "logger.c");
00904 
00905 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00906    if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00907       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00908                filename, lineno, func, rwlock_name);
00909       return 0;
00910    }
00911 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00912    
00913    if ((res = pthread_rwlock_destroy(prwlock)))
00914       __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
00915             filename, lineno, func, rwlock_name, strerror(res));
00916 
00917    return res;
00918 }
00919 
00920 #define ast_rwlock_unlock(a) \
00921    _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00922 
00923 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
00924    const char *file, int line, const char *func)
00925 {
00926    int res;
00927 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00928    int canlog = strcmp(file, "logger.c");
00929 
00930    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00931       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00932                file, line, func, name);
00933       res = __ast_rwlock_init(file, line, func, name, lock);
00934       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00935          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00936                file, line, func, name);
00937       }
00938       return res;
00939    }
00940 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00941    
00942    res = pthread_rwlock_unlock(lock);
00943    ast_remove_lock_info(lock);
00944    return res;
00945 }
00946 
00947 #define ast_rwlock_rdlock(a) \
00948    _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00949 
00950 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
00951    const char *file, int line, const char *func)
00952 {
00953    int res;
00954 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00955    int canlog = strcmp(file, "logger.c");
00956    
00957    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00958        /* Don't warn abount uninitialized lock.
00959         * Simple try to initialize it.
00960         * May be not needed in linux system.
00961         */
00962       res = __ast_rwlock_init(file, line, func, name, lock);
00963       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00964          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00965                file, line, func, name);
00966          return res;
00967       }
00968    }
00969 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00970    
00971    ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
00972    res = pthread_rwlock_rdlock(lock);
00973    if (!res)
00974       ast_mark_lock_acquired(lock);
00975    else
00976       ast_remove_lock_info(lock);
00977    return res;
00978 }
00979 
00980 #define ast_rwlock_wrlock(a) \
00981    _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00982 
00983 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
00984    const char *file, int line, const char *func)
00985 {
00986    int res;
00987 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00988    int canlog = strcmp(file, "logger.c");
00989    
00990    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00991        /* Don't warn abount uninitialized lock.
00992         * Simple try to initialize it.
00993         * May be not needed in linux system.
00994         */
00995       res = __ast_rwlock_init(file, line, func, name, lock);
00996       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00997          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00998                file, line, func, name);
00999          return res;
01000       }
01001    }
01002 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01003 
01004    ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01005    res = pthread_rwlock_wrlock(lock);
01006    if (!res)
01007       ast_mark_lock_acquired(lock);
01008    else
01009       ast_remove_lock_info(lock);
01010    return res;
01011 }
01012 
01013 #define ast_rwlock_timedrdlock(a,b) \
01014    _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01015 
01016 static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *lock, const char *name,
01017    const struct timespec *abs_timeout, const char *file, int line, const char *func)
01018 {
01019    int res;
01020 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01021    int canlog = strcmp(file, "logger.c");
01022    
01023    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01024        /* Don't warn abount uninitialized lock.
01025         * Simple try to initialize it.
01026         * May be not needed in linux system.
01027         */
01028       res = __ast_rwlock_init(file, line, func, name, lock);
01029       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01030          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01031                file, line, func, name);
01032          return res;
01033       }
01034    }
01035 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01036    
01037    ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
01038 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01039    res = pthread_rwlock_timedrdlock(lock, abs_timeout);
01040 #else
01041    do {
01042       struct timeval _start = ast_tvnow(), _diff;
01043       for (;;) {
01044          if (!(res = pthread_rwlock_tryrdlock(lock))) {
01045             break;
01046          }
01047          _diff = ast_tvsub(ast_tvnow(), _start);
01048          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01049             break;
01050          }
01051          usleep(1);
01052       }
01053    } while (0);
01054 #endif
01055    if (!res)
01056       ast_mark_lock_acquired(lock);
01057    else
01058       ast_remove_lock_info(lock);
01059    return res;
01060 }
01061 
01062 #define ast_rwlock_timedwrlock(a,b) \
01063    _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01064 
01065 static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *lock, const char *name,
01066    const struct timespec *abs_timeout, const char *file, int line, const char *func)
01067 {
01068    int res;
01069 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01070    int canlog = strcmp(file, "logger.c");
01071    
01072    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01073        /* Don't warn abount uninitialized lock.
01074         * Simple try to initialize it.
01075         * May be not needed in linux system.
01076         */
01077       res = __ast_rwlock_init(file, line, func, name, lock);
01078       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01079          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01080                file, line, func, name);
01081          return res;
01082       }
01083    }
01084 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01085 
01086    ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01087 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01088    res = pthread_rwlock_timedwrlock(lock, abs_timeout);
01089 #else
01090    do {
01091       struct timeval _start = ast_tvnow(), _diff;
01092       for (;;) {
01093          if (!(res = pthread_rwlock_trywrlock(lock))) {
01094             break;
01095          }
01096          _diff = ast_tvsub(ast_tvnow(), _start);
01097          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01098             break;
01099          }
01100          usleep(1);
01101       }
01102    } while (0);
01103 #endif
01104    if (!res)
01105       ast_mark_lock_acquired(lock);
01106    else
01107       ast_remove_lock_info(lock);
01108    return res;
01109 }
01110 
01111 #define ast_rwlock_tryrdlock(a) \
01112    _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01113 
01114 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
01115    const char *file, int line, const char *func)
01116 {
01117    int res;
01118 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01119    int canlog = strcmp(file, "logger.c");
01120    
01121    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01122        /* Don't warn abount uninitialized lock.
01123         * Simple try to initialize it.
01124         * May be not needed in linux system.
01125         */
01126       res = __ast_rwlock_init(file, line, func, name, lock);
01127       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01128          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01129                file, line, func, name);
01130          return res;
01131       }
01132    }
01133 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01134 
01135    ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
01136    res = pthread_rwlock_tryrdlock(lock);
01137    if (!res)
01138       ast_mark_lock_acquired(lock);
01139    else
01140       ast_remove_lock_info(lock);
01141    return res;
01142 }
01143 
01144 #define ast_rwlock_trywrlock(a) \
01145    _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01146 
01147 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
01148    const char *file, int line, const char *func)
01149 {
01150    int res;
01151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01152    int canlog = strcmp(file, "logger.c");
01153    
01154    if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01155        /* Don't warn abount uninitialized lock.
01156         * Simple try to initialize it.
01157         * May be not needed in linux system.
01158         */
01159       res = __ast_rwlock_init(file, line, func, name, lock);
01160       if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01161          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01162                file, line, func, name);
01163          return res;
01164       }
01165    }
01166 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01167 
01168    ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01169    res = pthread_rwlock_trywrlock(lock);
01170    if (!res)
01171       ast_mark_lock_acquired(lock);
01172    else
01173       ast_remove_lock_info(lock);
01174    return res;
01175 }
01176 
01177 #else /* !DEBUG_THREADS */
01178 
01179 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
01180 {
01181    int res;
01182    pthread_rwlockattr_t attr;
01183 
01184    pthread_rwlockattr_init(&attr);
01185 
01186 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01187    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01188 #endif
01189 
01190    res = pthread_rwlock_init(prwlock, &attr);
01191    pthread_rwlockattr_destroy(&attr);
01192    return res;
01193 }
01194 
01195 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
01196 {
01197    return pthread_rwlock_destroy(prwlock);
01198 }
01199 
01200 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
01201 {
01202    return pthread_rwlock_unlock(prwlock);
01203 }
01204 
01205 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
01206 {
01207    return pthread_rwlock_rdlock(prwlock);
01208 }
01209 
01210 static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01211 {
01212    int res;
01213 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01214    res = pthread_rwlock_timedrdlock(prwlock, abs_timeout);
01215 #else
01216    struct timeval _start = ast_tvnow(), _diff;
01217    for (;;) {
01218       if (!(res = pthread_rwlock_tryrdlock(prwlock))) {
01219          break;
01220       }
01221       _diff = ast_tvsub(ast_tvnow(), _start);
01222       if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01223          break;
01224       }
01225       usleep(1);
01226    }
01227 #endif
01228    return res;
01229 }
01230 
01231 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
01232 {
01233    return pthread_rwlock_tryrdlock(prwlock);
01234 }
01235 
01236 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
01237 {
01238    return pthread_rwlock_wrlock(prwlock);
01239 }
01240 
01241 static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01242 {
01243    int res;
01244 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01245    res = pthread_rwlock_timedwrlock(prwlock, abs_timeout);
01246 #else
01247    do {
01248       struct timeval _start = ast_tvnow(), _diff;
01249       for (;;) {
01250          if (!(res = pthread_rwlock_trywrlock(prwlock))) {
01251             break;
01252          }
01253          _diff = ast_tvsub(ast_tvnow(), _start);
01254          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01255             break;
01256          }
01257          usleep(1);
01258       }
01259    } while (0);
01260 #endif
01261    return res;
01262 }
01263 
01264 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
01265 {
01266    return pthread_rwlock_trywrlock(prwlock);
01267 }
01268 #endif /* !DEBUG_THREADS */
01269 
01270 /* Statically declared read/write locks */
01271 
01272 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
01273 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01274         scope ast_rwlock_t rwlock; \
01275 static void  __attribute__((constructor)) init_##rwlock(void) \
01276 { \
01277         ast_rwlock_init(&rwlock); \
01278 } \
01279 static void  __attribute__((destructor)) fini_##rwlock(void) \
01280 { \
01281         ast_rwlock_destroy(&rwlock); \
01282 }
01283 #else
01284 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01285         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
01286 #endif
01287 
01288 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
01289 
01290 /*
01291  * Initial support for atomic instructions.
01292  * For platforms that have it, use the native cpu instruction to
01293  * implement them. For other platforms, resort to a 'slow' version
01294  * (defined in utils.c) that protects the atomic instruction with
01295  * a single lock.
01296  * The slow versions is always available, for testing purposes,
01297  * as ast_atomic_fetchadd_int_slow()
01298  */
01299 
01300 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
01301 
01302 #include "asterisk/inline_api.h"
01303 
01304 #if defined(HAVE_OSX_ATOMICS)
01305 #include "libkern/OSAtomic.h"
01306 #endif
01307 
01308 /*! \brief Atomically add v to *p and return * the previous value of *p.
01309  * This can be used to handle reference counts, and the return value
01310  * can be used to generate unique identifiers.
01311  */
01312 
01313 #if defined(HAVE_GCC_ATOMICS)
01314 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01315 {
01316    return __sync_fetch_and_add(p, v);
01317 })
01318 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01319 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01320 {
01321    return OSAtomicAdd32(v, (int32_t *) p) - v;
01322 })
01323 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01324 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01325 {
01326    return OSAtomicAdd64(v, (int64_t *) p) - v;
01327 #elif defined (__i386__)
01328 #ifdef sun
01329 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01330 {
01331    __asm __volatile (
01332    "       lock;  xaddl   %0, %1 ;        "
01333    : "+r" (v),                     /* 0 (result) */   
01334      "=m" (*p)                     /* 1 */
01335    : "m" (*p));                    /* 2 */
01336    return (v);
01337 })
01338 #else /* ifndef sun */
01339 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01340 {
01341    __asm __volatile (
01342    "       lock   xaddl   %0, %1 ;        "
01343    : "+r" (v),                     /* 0 (result) */   
01344      "=m" (*p)                     /* 1 */
01345    : "m" (*p));                    /* 2 */
01346    return (v);
01347 })
01348 #endif
01349 #else   /* low performance version in utils.c */
01350 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01351 {
01352    return ast_atomic_fetchadd_int_slow(p, v);
01353 })
01354 #endif
01355 
01356 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
01357  * Useful e.g. to check if a refcount has reached 0.
01358  */
01359 #if defined(HAVE_GCC_ATOMICS)
01360 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01361 {
01362    return __sync_sub_and_fetch(p, 1) == 0;
01363 })
01364 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01365 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01366 {
01367    return OSAtomicAdd32( -1, (int32_t *) p) == 0;
01368 })
01369 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01370 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01371 {
01372    return OSAtomicAdd64( -1, (int64_t *) p) == 0;
01373 #else
01374 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01375 {
01376    int a = ast_atomic_fetchadd_int(p, -1);
01377    return a == 1; /* true if the value is 0 now (so it was 1 previously) */
01378 })
01379 #endif
01380 
01381 #ifndef DEBUG_CHANNEL_LOCKS
01382 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
01383    in the Makefile, print relevant output for debugging */
01384 #define ast_channel_lock(x)      ast_mutex_lock(&x->lock)
01385 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
01386    in the Makefile, print relevant output for debugging */
01387 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
01388 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
01389    in the Makefile, print relevant output for debugging */
01390 #define ast_channel_trylock(x)      ast_mutex_trylock(&x->lock)
01391 #else
01392 
01393 struct ast_channel;
01394 
01395 #define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01396 /*! \brief Lock AST channel (and print debugging output)
01397 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
01398 int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
01399 
01400 #define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01401 /*! \brief Unlock AST channel (and print debugging output)
01402 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
01403 */
01404 int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
01405 
01406 #define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01407 /*! \brief Lock AST channel (and print debugging output)
01408 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
01409 int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func) attribute_warn_unused_result;
01410 #endif
01411 
01412 #endif /* _ASTERISK_LOCK_H */

Generated on Thu Oct 11 06:42:08 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6