Thu Apr 28 2011 16:56:47

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 Asterisk locking-related definitions:
00021  * - ast_mutext_t, ast_rwlock_t and related functions;
00022  * - atomic arithmetic instructions;
00023  * - wrappers for channel locking.
00024  *
00025  * - See \ref LockDef
00026  */
00027 
00028 /*! \page LockDef Asterisk thread locking models
00029  *
00030  * This file provides different implementation of the functions,
00031  * depending on the platform, the use of DEBUG_THREADS, and the way
00032  * module-level mutexes are initialized.
00033  *
00034  *  - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
00035  *        this is done at compile time, and is the way used on Linux.
00036  *        This method is not applicable to all platforms e.g. when the
00037  *        initialization needs that some code is run.
00038  *
00039  *  - \b through constructors: for each mutex, a constructor function is
00040  *        defined, which then runs when the program (or the module)
00041  *        starts. The problem with this approach is that there is a
00042  *        lot of code duplication (a new block of code is created for
00043  *        each mutex). Also, it does not prevent a user from declaring
00044  *        a global mutex without going through the wrapper macros,
00045  *        so sane programming practices are still required.
00046  */
00047 
00048 #ifndef _ASTERISK_LOCK_H
00049 #define _ASTERISK_LOCK_H
00050 
00051 #include <pthread.h>
00052 #include <time.h>
00053 #include <sys/param.h>
00054 #ifdef HAVE_BKTR
00055 #include <execinfo.h>
00056 #endif
00057 
00058 #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
00059 #include "asterisk/time.h"
00060 #endif
00061 #include "asterisk/logger.h"
00062 #include "asterisk/compiler.h"
00063 
00064 /* internal macro to profile mutexes. Only computes the delay on
00065  * non-blocking calls.
00066  */
00067 #ifndef  HAVE_MTX_PROFILE
00068 #define  __MTX_PROF(a)  return pthread_mutex_lock((a))
00069 #else
00070 #define  __MTX_PROF(a)  do {        \
00071    int i;               \
00072    /* profile only non-blocking events */ \
00073    ast_mark(mtx_prof, 1);        \
00074    i = pthread_mutex_trylock((a));     \
00075    ast_mark(mtx_prof, 0);        \
00076    if (!i)              \
00077       return i;         \
00078    else              \
00079       return pthread_mutex_lock((a)); \
00080    } while (0)
00081 #endif   /* HAVE_MTX_PROFILE */
00082 
00083 #define AST_PTHREADT_NULL (pthread_t) -1
00084 #define AST_PTHREADT_STOP (pthread_t) -2
00085 
00086 #if (defined(SOLARIS) || defined(BSD))
00087 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00088 #endif /* SOLARIS || BSD */
00089 
00090 /* Asterisk REQUIRES recursive (not error checking) mutexes
00091    and will not run without them. */
00092 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
00093 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00094 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE_NP
00095 #else
00096 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00097 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE
00098 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
00099 
00100 /*
00101  * Definition of ast_mutex_t, ast_cont_d and related functions with/without debugging
00102  * (search for DEBUG_THREADS to find the start/end of the sections).
00103  *
00104  * The non-debug code contains just wrappers for the corresponding pthread functions.
00105  * The debug code tracks usage and tries to identify deadlock situations.
00106  */
00107 #ifdef DEBUG_THREADS
00108 
00109 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00110 
00111 #ifdef THREAD_CRASH
00112 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00113 #else
00114 #define DO_THREAD_CRASH do { } while (0)
00115 #endif
00116 
00117 #include <errno.h>
00118 
00119 #ifdef HAVE_BKTR
00120 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE }
00121 
00122 #else
00123 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00124 #endif
00125 
00126 #define AST_MUTEX_INIT_VALUE { AST_LOCK_TRACK_INIT_VALUE, 1, PTHREAD_MUTEX_INIT_VALUE }
00127 #define AST_MUTEX_INIT_VALUE_NOTRACKING { AST_LOCK_TRACK_INIT_VALUE, 0, PTHREAD_MUTEX_INIT_VALUE }
00128 
00129 #define AST_MAX_REENTRANCY 10
00130 
00131 struct ast_channel;
00132 
00133 struct ast_lock_track {
00134    const char *file[AST_MAX_REENTRANCY];
00135    int lineno[AST_MAX_REENTRANCY];
00136    int reentrancy;
00137    const char *func[AST_MAX_REENTRANCY];
00138    pthread_t thread[AST_MAX_REENTRANCY];
00139 #ifdef HAVE_BKTR
00140    struct ast_bt backtrace[AST_MAX_REENTRANCY];
00141 #endif
00142    pthread_mutex_t reentr_mutex;
00143 };
00144 
00145 struct ast_mutex_info {
00146    /*! Track which thread holds this mutex */
00147    struct ast_lock_track track;
00148    unsigned int tracking:1;
00149    pthread_mutex_t mutex;
00150 };
00151 
00152 typedef struct ast_mutex_info ast_mutex_t;
00153 
00154 typedef pthread_cond_t ast_cond_t;
00155 
00156 enum ast_lock_type {
00157    AST_MUTEX,
00158    AST_RDLOCK,
00159    AST_WRLOCK,
00160 };
00161 
00162 /*!
00163  * \brief Store lock info for the current thread
00164  *
00165  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
00166  * that information about this lock can be stored in this thread's
00167  * lock info struct.  The lock is marked as pending as the thread is waiting
00168  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
00169  */
00170 #if !defined(LOW_MEMORY)
00171 #ifdef HAVE_BKTR
00172 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00173    int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt);
00174 #else
00175 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00176    int line_num, const char *func, const char *lock_name, void *lock_addr);
00177 #endif /* HAVE_BKTR */
00178 
00179 #else
00180 
00181 #ifdef HAVE_BKTR
00182 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD)
00183 #else
00184 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
00185 #endif /* HAVE_BKTR */
00186 #endif /* !defined(LOW_MEMORY) */
00187 
00188 /*!
00189  * \brief Mark the last lock as acquired
00190  */
00191 #if !defined(LOW_MEMORY)
00192 void ast_mark_lock_acquired(void *lock_addr);
00193 #else
00194 #define ast_mark_lock_acquired(ignore)
00195 #endif
00196 
00197 /*!
00198  * \brief Mark the last lock as failed (trylock)
00199  */
00200 #if !defined(LOW_MEMORY)
00201 void ast_mark_lock_failed(void *lock_addr);
00202 #else
00203 #define ast_mark_lock_failed(ignore)
00204 #endif
00205 
00206 /*!
00207  * \brief remove lock info for the current thread
00208  *
00209  * this gets called by ast_mutex_unlock so that information on the lock can
00210  * be removed from the current thread's lock info struct.
00211  */
00212 #if !defined(LOW_MEMORY)
00213 #ifdef HAVE_BKTR
00214 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt);
00215 #else
00216 void ast_remove_lock_info(void *lock_addr);
00217 #endif /* HAVE_BKTR */
00218 #else
00219 #ifdef HAVE_BKTR
00220 #define ast_remove_lock_info(ignore,me)
00221 #else
00222 #define ast_remove_lock_info(ignore)
00223 #endif /* HAVE_BKTR */
00224 #endif /* !defined(LOW_MEMORY) */
00225 
00226 #ifdef HAVE_BKTR
00227 static inline void __dump_backtrace(struct ast_bt *bt, int canlog)
00228 {
00229    char **strings;
00230 
00231    ssize_t i;
00232 
00233    strings = backtrace_symbols(bt->addresses, bt->num_frames);
00234 
00235    for (i = 0; i < bt->num_frames; i++)
00236       __ast_mutex_logger("%s\n", strings[i]);
00237 
00238    free(strings);
00239 }
00240 #endif
00241 
00242 /*!
00243  * \brief log info for the current lock with ast_log().
00244  *
00245  * this function would be mostly for debug. If you come across a lock
00246  * that is unexpectedly but momentarily locked, and you wonder who
00247  * are fighting with for the lock, this routine could be called, IF
00248  * you have the thread debugging stuff turned on.
00249  * \param this_lock_addr lock address to return lock information
00250  * \since 1.6.1
00251  */
00252 void log_show_lock(void *this_lock_addr);
00253 
00254 /*!
00255  * \brief retrieve lock info for the specified mutex
00256  *
00257  * this gets called during deadlock avoidance, so that the information may
00258  * be preserved as to what location originally acquired the lock.
00259  */
00260 #if !defined(LOW_MEMORY)
00261 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);
00262 #else
00263 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
00264 #endif
00265 
00266 /*!
00267  * \brief Unlock a lock briefly
00268  *
00269  * used during deadlock avoidance, to preserve the original location where
00270  * a lock was originally acquired.
00271  */
00272 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
00273    do { \
00274       char __filename[80], __func[80], __mutex_name[80]; \
00275       int __lineno; \
00276       int __res = ast_find_lock_info(&chan->lock_dont_use, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00277       int __res2 = ast_channel_unlock(chan); \
00278       usleep(1); \
00279       if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
00280          if (__res2) { \
00281             ast_log(LOG_WARNING, "Could not unlock channel '%s': %s and no lock info found!  I will NOT try to relock.\n", #chan, strerror(__res2)); \
00282          } else { \
00283             ast_channel_lock(chan); \
00284          } \
00285       } else { \
00286          if (__res2) { \
00287             ast_log(LOG_WARNING, "Could not unlock channel '%s': %s.  {{{Originally locked at %s line %d: (%s) '%s'}}}  I will NOT try to relock.\n", #chan, strerror(__res2), __filename, __lineno, __func, __mutex_name); \
00288          } else { \
00289             __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, &chan->lock_dont_use); \
00290          } \
00291       } \
00292    } while (0)
00293 
00294 #define DEADLOCK_AVOIDANCE(lock) \
00295    do { \
00296       char __filename[80], __func[80], __mutex_name[80]; \
00297       int __lineno; \
00298       int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00299       int __res2 = ast_mutex_unlock(lock); \
00300       usleep(1); \
00301       if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
00302          if (__res2 == 0) { \
00303             ast_mutex_lock(lock); \
00304          } else { \
00305             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)); \
00306          } \
00307       } else { \
00308          if (__res2 == 0) { \
00309             __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00310          } else { \
00311             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); \
00312          } \
00313       } \
00314    } while (0)
00315 
00316 /*!
00317  * \brief Deadlock avoidance unlock
00318  *
00319  * In certain deadlock avoidance scenarios, there is more than one lock to be
00320  * unlocked and relocked.  Therefore, this pair of macros is provided for that
00321  * purpose.  Note that every DLA_UNLOCK _MUST_ be paired with a matching
00322  * DLA_LOCK.  The intent of this pair of macros is to be used around another
00323  * set of deadlock avoidance code, mainly CHANNEL_DEADLOCK_AVOIDANCE, as the
00324  * locking order specifies that we may safely lock a channel, followed by its
00325  * pvt, with no worries about a deadlock.  In any other scenario, this macro
00326  * may not be safe to use.
00327  */
00328 #define DLA_UNLOCK(lock) \
00329    do { \
00330       char __filename[80], __func[80], __mutex_name[80]; \
00331       int __lineno; \
00332       int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00333       int __res2 = ast_mutex_unlock(lock);
00334 
00335 /*!
00336  * \brief Deadlock avoidance lock
00337  *
00338  * In certain deadlock avoidance scenarios, there is more than one lock to be
00339  * unlocked and relocked.  Therefore, this pair of macros is provided for that
00340  * purpose.  Note that every DLA_UNLOCK _MUST_ be paired with a matching
00341  * DLA_LOCK.  The intent of this pair of macros is to be used around another
00342  * set of deadlock avoidance code, mainly CHANNEL_DEADLOCK_AVOIDANCE, as the
00343  * locking order specifies that we may safely lock a channel, followed by its
00344  * pvt, with no worries about a deadlock.  In any other scenario, this macro
00345  * may not be safe to use.
00346  */
00347 #define DLA_LOCK(lock) \
00348       if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
00349          if (__res2) { \
00350             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)); \
00351          } else { \
00352             ast_mutex_lock(lock); \
00353          } \
00354       } else { \
00355          if (__res2) { \
00356             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); \
00357          } else { \
00358             __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00359          } \
00360       } \
00361    } while (0)
00362 
00363 static inline void ast_reentrancy_lock(struct ast_lock_track *lt)
00364 {
00365    pthread_mutex_lock(&lt->reentr_mutex);
00366 }
00367 
00368 static inline void ast_reentrancy_unlock(struct ast_lock_track *lt)
00369 {
00370    pthread_mutex_unlock(&lt->reentr_mutex);
00371 }
00372 
00373 static inline void ast_reentrancy_init(struct ast_lock_track *lt)
00374 {
00375    int i;
00376    pthread_mutexattr_t reentr_attr;
00377 
00378    for (i = 0; i < AST_MAX_REENTRANCY; i++) {
00379       lt->file[i] = NULL;
00380       lt->lineno[i] = 0;
00381       lt->func[i] = NULL;
00382       lt->thread[i] = 0;
00383 #ifdef HAVE_BKTR
00384       memset(&lt->backtrace[i], 0, sizeof(lt->backtrace[i]));
00385 #endif
00386    }
00387 
00388    lt->reentrancy = 0;
00389 
00390    pthread_mutexattr_init(&reentr_attr);
00391    pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
00392    pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
00393    pthread_mutexattr_destroy(&reentr_attr);
00394 }
00395 
00396 static inline void delete_reentrancy_cs(struct ast_lock_track *lt)
00397 {
00398    pthread_mutex_destroy(&lt->reentr_mutex);
00399 }
00400 
00401 static inline int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
00402                   const char *mutex_name, ast_mutex_t *t)
00403 {
00404    int res;
00405    pthread_mutexattr_t  attr;
00406 
00407 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00408 
00409    if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00410 /*
00411       int canlog = strcmp(filename, "logger.c") & track;
00412       __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
00413                filename, lineno, func, mutex_name);
00414       DO_THREAD_CRASH;
00415 */
00416       return 0;
00417    }
00418 
00419 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00420 
00421    ast_reentrancy_init(&t->track);
00422    t->tracking = tracking;
00423 
00424    pthread_mutexattr_init(&attr);
00425    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00426 
00427    res = pthread_mutex_init(&t->mutex, &attr);
00428    pthread_mutexattr_destroy(&attr);
00429    return res;
00430 }
00431 
00432 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00433 #define ast_mutex_init_notracking(pmutex) \
00434    __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00435 
00436 #define  ROFFSET  ((lt->reentrancy > 0) ? (lt->reentrancy-1) : 0)
00437 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00438                   const char *mutex_name, ast_mutex_t *t)
00439 {
00440    int res;
00441    struct ast_lock_track *lt;
00442    int canlog = strcmp(filename, "logger.c") & t->tracking;
00443 
00444 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00445    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00446       /* Don't try to uninitialize non initialized mutex
00447        * This may no effect on linux
00448        * And always ganerate core on *BSD with
00449        * linked libpthread
00450        * This not error condition if the mutex created on the fly.
00451        */
00452       __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
00453                filename, lineno, func, mutex_name);
00454       return 0;
00455    }
00456 #endif
00457 
00458    lt = &t->track;
00459 
00460    res = pthread_mutex_trylock(&t->mutex);
00461    switch (res) {
00462    case 0:
00463       pthread_mutex_unlock(&t->mutex);
00464       break;
00465    case EINVAL:
00466       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00467               filename, lineno, func, mutex_name);
00468       break;
00469    case EBUSY:
00470       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00471                filename, lineno, func, mutex_name);
00472       ast_reentrancy_lock(lt);
00473       __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00474              lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00475 #ifdef HAVE_BKTR
00476       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
00477 #endif
00478       ast_reentrancy_unlock(lt);
00479       break;
00480    }
00481 
00482 
00483    if ((res = pthread_mutex_destroy(&t->mutex))) {
00484       __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
00485                filename, lineno, func, mutex_name, strerror(res));
00486    }
00487    ast_reentrancy_lock(lt);
00488    lt->file[0] = filename;
00489    lt->lineno[0] = lineno;
00490    lt->func[0] = func;
00491    lt->reentrancy = 0;
00492    lt->thread[0] = 0;
00493 #ifdef HAVE_BKTR
00494    memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
00495 #endif
00496    ast_reentrancy_unlock(lt);
00497    delete_reentrancy_cs(lt);
00498 
00499    return res;
00500 }
00501 
00502 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00503                                            const char* mutex_name, ast_mutex_t *t)
00504 {
00505    int res;
00506    struct ast_lock_track *lt = &t->track;
00507    int canlog = strcmp(filename, "logger.c") & t->tracking;
00508 #ifdef HAVE_BKTR
00509    struct ast_bt *bt = NULL;
00510 #endif
00511 
00512 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00513    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00514       /* Don't warn abount uninitialized mutex.
00515        * Simple try to initialize it.
00516        * May be not needed in linux system.
00517        */
00518       res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00519       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00520          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00521                 filename, lineno, func, mutex_name);
00522          return res;
00523       }
00524    }
00525 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00526 
00527    if (t->tracking) {
00528 #ifdef HAVE_BKTR
00529       ast_reentrancy_lock(lt);
00530       if (lt->reentrancy != AST_MAX_REENTRANCY) {
00531          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
00532          bt = &lt->backtrace[lt->reentrancy];
00533       }
00534       ast_reentrancy_unlock(lt);
00535       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00536 #else
00537       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00538 #endif
00539    }
00540 
00541 #ifdef DETECT_DEADLOCKS
00542    {
00543       time_t seconds = time(NULL);
00544       time_t wait_time, reported_wait = 0;
00545       do {
00546 #ifdef   HAVE_MTX_PROFILE
00547          ast_mark(mtx_prof, 1);
00548 #endif
00549          res = pthread_mutex_trylock(&t->mutex);
00550 #ifdef   HAVE_MTX_PROFILE
00551          ast_mark(mtx_prof, 0);
00552 #endif
00553          if (res == EBUSY) {
00554             wait_time = time(NULL) - seconds;
00555             if (wait_time > reported_wait && (wait_time % 5) == 0) {
00556                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00557                         filename, lineno, func, (int) wait_time, mutex_name);
00558                ast_reentrancy_lock(lt);
00559 #ifdef HAVE_BKTR
00560                __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
00561 #endif
00562                __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00563                         lt->file[ROFFSET], lt->lineno[ROFFSET],
00564                         lt->func[ROFFSET], mutex_name);
00565 #ifdef HAVE_BKTR
00566                __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
00567 #endif
00568                ast_reentrancy_unlock(lt);
00569                reported_wait = wait_time;
00570             }
00571             usleep(200);
00572          }
00573       } while (res == EBUSY);
00574    }
00575 #else
00576 #ifdef   HAVE_MTX_PROFILE
00577    ast_mark(mtx_prof, 1);
00578    res = pthread_mutex_trylock(&t->mutex);
00579    ast_mark(mtx_prof, 0);
00580    if (res)
00581 #endif
00582    res = pthread_mutex_lock(&t->mutex);
00583 #endif /* DETECT_DEADLOCKS */
00584 
00585    if (!res) {
00586       ast_reentrancy_lock(lt);
00587       if (lt->reentrancy < AST_MAX_REENTRANCY) {
00588          lt->file[lt->reentrancy] = filename;
00589          lt->lineno[lt->reentrancy] = lineno;
00590          lt->func[lt->reentrancy] = func;
00591          lt->thread[lt->reentrancy] = pthread_self();
00592          lt->reentrancy++;
00593       } else {
00594          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00595                         filename, lineno, func, mutex_name);
00596       }
00597       ast_reentrancy_unlock(lt);
00598       if (t->tracking) {
00599          ast_mark_lock_acquired(t);
00600       }
00601    } else {
00602 #ifdef HAVE_BKTR
00603       if (lt->reentrancy) {
00604          ast_reentrancy_lock(lt);
00605          bt = &lt->backtrace[lt->reentrancy-1];
00606          ast_reentrancy_unlock(lt);
00607       } else {
00608          bt = NULL;
00609       }
00610       if (t->tracking) {
00611          ast_remove_lock_info(t, bt);
00612       }
00613 #else
00614       if (t->tracking) {
00615          ast_remove_lock_info(t);
00616       }
00617 #endif
00618       __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00619                filename, lineno, func, strerror(res));
00620       DO_THREAD_CRASH;
00621    }
00622 
00623    return res;
00624 }
00625 
00626 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00627                                               const char* mutex_name, ast_mutex_t *t)
00628 {
00629    int res;
00630    struct ast_lock_track *lt= &t->track;
00631    int canlog = strcmp(filename, "logger.c") & t->tracking;
00632 #ifdef HAVE_BKTR
00633    struct ast_bt *bt = NULL;
00634 #endif
00635 
00636 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00637    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00638       /* Don't warn abount uninitialized mutex.
00639        * Simple try to initialize it.
00640        * May be not needed in linux system.
00641        */
00642       res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00643       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00644          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00645                 filename, lineno, func, mutex_name);
00646          return res;
00647       }
00648    }
00649 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00650 
00651    if (t->tracking) {
00652 #ifdef HAVE_BKTR
00653       ast_reentrancy_lock(lt);
00654       if (lt->reentrancy != AST_MAX_REENTRANCY) {
00655          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
00656          bt = &lt->backtrace[lt->reentrancy];
00657       }
00658       ast_reentrancy_unlock(lt);
00659       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00660 #else
00661       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00662 #endif
00663    }
00664 
00665    if (!(res = pthread_mutex_trylock(&t->mutex))) {
00666       ast_reentrancy_lock(lt);
00667       if (lt->reentrancy < AST_MAX_REENTRANCY) {
00668          lt->file[lt->reentrancy] = filename;
00669          lt->lineno[lt->reentrancy] = lineno;
00670          lt->func[lt->reentrancy] = func;
00671          lt->thread[lt->reentrancy] = pthread_self();
00672          lt->reentrancy++;
00673       } else {
00674          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00675                   filename, lineno, func, mutex_name);
00676       }
00677       ast_reentrancy_unlock(lt);
00678       if (t->tracking) {
00679          ast_mark_lock_acquired(t);
00680       }
00681    } else if (t->tracking) {
00682       ast_mark_lock_failed(t);
00683    }
00684 
00685    return res;
00686 }
00687 
00688 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00689                     const char *mutex_name, ast_mutex_t *t)
00690 {
00691    int res;
00692    struct ast_lock_track *lt = &t->track;
00693    int canlog = strcmp(filename, "logger.c") & t->tracking;
00694 #ifdef HAVE_BKTR
00695    struct ast_bt *bt = NULL;
00696 #endif
00697 
00698 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00699    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00700       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00701                filename, lineno, func, mutex_name);
00702       res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00703       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00704          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00705                 filename, lineno, func, mutex_name);
00706       }
00707       return res;
00708    }
00709 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00710 
00711    ast_reentrancy_lock(lt);
00712    if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00713       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00714                filename, lineno, func, mutex_name);
00715       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00716                lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00717 #ifdef HAVE_BKTR
00718       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
00719 #endif
00720       DO_THREAD_CRASH;
00721    }
00722 
00723    if (--lt->reentrancy < 0) {
00724       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00725                filename, lineno, func, mutex_name);
00726       lt->reentrancy = 0;
00727    }
00728 
00729    if (lt->reentrancy < AST_MAX_REENTRANCY) {
00730       lt->file[lt->reentrancy] = NULL;
00731       lt->lineno[lt->reentrancy] = 0;
00732       lt->func[lt->reentrancy] = NULL;
00733       lt->thread[lt->reentrancy] = 0;
00734    }
00735 
00736 #ifdef HAVE_BKTR
00737    if (lt->reentrancy) {
00738       bt = &lt->backtrace[lt->reentrancy - 1];
00739    }
00740 #endif
00741    ast_reentrancy_unlock(lt);
00742 
00743    if (t->tracking) {
00744 #ifdef HAVE_BKTR
00745       ast_remove_lock_info(t, bt);
00746 #else
00747       ast_remove_lock_info(t);
00748 #endif
00749    }
00750 
00751    if ((res = pthread_mutex_unlock(&t->mutex))) {
00752       __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
00753                filename, lineno, func, strerror(res));
00754       DO_THREAD_CRASH;
00755    }
00756 
00757    return res;
00758 }
00759 
00760 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00761               const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00762 {
00763    return pthread_cond_init(cond, cond_attr);
00764 }
00765 
00766 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00767                 const char *cond_name, ast_cond_t *cond)
00768 {
00769    return pthread_cond_signal(cond);
00770 }
00771 
00772 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00773                    const char *cond_name, ast_cond_t *cond)
00774 {
00775    return pthread_cond_broadcast(cond);
00776 }
00777 
00778 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00779                  const char *cond_name, ast_cond_t *cond)
00780 {
00781    return pthread_cond_destroy(cond);
00782 }
00783 
00784 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00785               const char *cond_name, const char *mutex_name,
00786               ast_cond_t *cond, ast_mutex_t *t)
00787 {
00788    int res;
00789    struct ast_lock_track *lt= &t->track;
00790    int canlog = strcmp(filename, "logger.c") & t->tracking;
00791 #ifdef HAVE_BKTR
00792    struct ast_bt *bt = NULL;
00793 #endif
00794 
00795 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00796    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00797       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00798                filename, lineno, func, mutex_name);
00799       res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00800       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00801          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00802                 filename, lineno, func, mutex_name);
00803       }
00804       return res;
00805    }
00806 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00807 
00808    ast_reentrancy_lock(lt);
00809    if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00810       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00811                filename, lineno, func, mutex_name);
00812       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00813                lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00814 #ifdef HAVE_BKTR
00815       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
00816 #endif
00817       DO_THREAD_CRASH;
00818    }
00819 
00820    if (--lt->reentrancy < 0) {
00821       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00822                filename, lineno, func, mutex_name);
00823       lt->reentrancy = 0;
00824    }
00825 
00826    if (lt->reentrancy < AST_MAX_REENTRANCY) {
00827       lt->file[lt->reentrancy] = NULL;
00828       lt->lineno[lt->reentrancy] = 0;
00829       lt->func[lt->reentrancy] = NULL;
00830       lt->thread[lt->reentrancy] = 0;
00831    }
00832 
00833 #ifdef HAVE_BKTR
00834    if (lt->reentrancy) {
00835       bt = &lt->backtrace[lt->reentrancy - 1];
00836    }
00837 #endif
00838    ast_reentrancy_unlock(lt);
00839 
00840    if (t->tracking) {
00841 #ifdef HAVE_BKTR
00842       ast_remove_lock_info(t, bt);
00843 #else
00844       ast_remove_lock_info(t);
00845 #endif
00846    }
00847 
00848    if ((res = pthread_cond_wait(cond, &t->mutex))) {
00849       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00850                filename, lineno, func, strerror(res));
00851       DO_THREAD_CRASH;
00852    } else {
00853       ast_reentrancy_lock(lt);
00854       if (lt->reentrancy < AST_MAX_REENTRANCY) {
00855          lt->file[lt->reentrancy] = filename;
00856          lt->lineno[lt->reentrancy] = lineno;
00857          lt->func[lt->reentrancy] = func;
00858          lt->thread[lt->reentrancy] = pthread_self();
00859 #ifdef HAVE_BKTR
00860          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
00861          bt = &lt->backtrace[lt->reentrancy];
00862 #endif
00863          lt->reentrancy++;
00864       } else {
00865          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00866                         filename, lineno, func, mutex_name);
00867       }
00868       ast_reentrancy_unlock(lt);
00869 
00870       if (t->tracking) {
00871 #ifdef HAVE_BKTR
00872          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00873 #else
00874          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00875 #endif
00876       }
00877    }
00878 
00879    return res;
00880 }
00881 
00882 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00883                    const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00884                    ast_mutex_t *t, const struct timespec *abstime)
00885 {
00886    int res;
00887    struct ast_lock_track *lt = &t->track;
00888    int canlog = strcmp(filename, "logger.c") & t->tracking;
00889 #ifdef HAVE_BKTR
00890    struct ast_bt *bt = NULL;
00891 #endif
00892 
00893 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
00894    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00895       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00896                filename, lineno, func, mutex_name);
00897       res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00898       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00899          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00900                 filename, lineno, func, mutex_name);
00901       }
00902       return res;
00903    }
00904 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00905 
00906    ast_reentrancy_lock(lt);
00907    if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00908       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00909                filename, lineno, func, mutex_name);
00910       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00911                lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00912 #ifdef HAVE_BKTR
00913       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
00914 #endif
00915       DO_THREAD_CRASH;
00916    }
00917 
00918    if (--lt->reentrancy < 0) {
00919       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00920                filename, lineno, func, mutex_name);
00921       lt->reentrancy = 0;
00922    }
00923 
00924    if (lt->reentrancy < AST_MAX_REENTRANCY) {
00925       lt->file[lt->reentrancy] = NULL;
00926       lt->lineno[lt->reentrancy] = 0;
00927       lt->func[lt->reentrancy] = NULL;
00928       lt->thread[lt->reentrancy] = 0;
00929    }
00930 #ifdef HAVE_BKTR
00931    if (lt->reentrancy) {
00932       bt = &lt->backtrace[lt->reentrancy - 1];
00933    }
00934 #endif
00935    ast_reentrancy_unlock(lt);
00936 
00937    if (t->tracking) {
00938 #ifdef HAVE_BKTR
00939       ast_remove_lock_info(t, bt);
00940 #else
00941       ast_remove_lock_info(t);
00942 #endif
00943    }
00944 
00945    if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00946       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00947                filename, lineno, func, strerror(res));
00948       DO_THREAD_CRASH;
00949    } else {
00950       ast_reentrancy_lock(lt);
00951       if (lt->reentrancy < AST_MAX_REENTRANCY) {
00952          lt->file[lt->reentrancy] = filename;
00953          lt->lineno[lt->reentrancy] = lineno;
00954          lt->func[lt->reentrancy] = func;
00955          lt->thread[lt->reentrancy] = pthread_self();
00956 #ifdef HAVE_BKTR
00957          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
00958          bt = &lt->backtrace[lt->reentrancy];
00959 #endif
00960          lt->reentrancy++;
00961       } else {
00962          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00963                         filename, lineno, func, mutex_name);
00964       }
00965       ast_reentrancy_unlock(lt);
00966 
00967       if (t->tracking) {
00968 #ifdef HAVE_BKTR
00969          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00970 #else
00971          ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00972 #endif
00973       }
00974    }
00975 
00976    return res;
00977 }
00978 
00979 #define ast_mutex_destroy(a)        __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00980 #define ast_mutex_lock(a)        __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00981 #define ast_mutex_unlock(a)         __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00982 #define ast_mutex_trylock(a)        __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00983 #define ast_cond_init(cond, attr)      __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00984 #define ast_cond_destroy(cond)         __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00985 #define ast_cond_signal(cond)       __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00986 #define ast_cond_broadcast(cond)    __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00987 #define ast_cond_wait(cond, mutex)     __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00988 #define ast_cond_timedwait(cond, mutex, time)   __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00989 
00990 struct ast_rwlock_info {
00991    /*! Track which thread holds this lock */
00992    struct ast_lock_track track;
00993    unsigned int tracking:1;
00994    pthread_rwlock_t lock;
00995 };
00996 
00997 typedef struct ast_rwlock_info ast_rwlock_t;
00998 
00999 /*!
01000  * \brief wrapper for rwlock with tracking enabled
01001  * \return 0 on success, non zero for error
01002  * \since 1.6.1
01003  */
01004 #define ast_rwlock_init(rwlock) __ast_rwlock_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
01005 
01006 /*!
01007  * \brief wrapper for ast_rwlock_init with tracking disabled
01008  * \return 0 on success, non zero for error
01009  * \since 1.6.1
01010  */
01011 #define ast_rwlock_init_notracking(rwlock) __ast_rwlock_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
01012 
01013 #define ast_rwlock_destroy(rwlock)  __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
01014 #define ast_rwlock_unlock(a)     _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01015 #define ast_rwlock_rdlock(a)     _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01016 #define ast_rwlock_wrlock(a)     _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01017 #define ast_rwlock_tryrdlock(a)     _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01018 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01019 
01020 
01021 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
01022 #define __AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
01023 #else  /* HAVE_PTHREAD_RWLOCK_INITIALIZER */
01024 #define __AST_RWLOCK_INIT_VALUE {0}
01025 #endif /* HAVE_PTHREAD_RWLOCK_INITIALIZER */
01026 
01027 #define AST_RWLOCK_INIT_VALUE \
01028    { AST_LOCK_TRACK_INIT_VALUE, 1, __AST_RWLOCK_INIT_VALUE }
01029 #define AST_RWLOCK_INIT_VALUE_NOTRACKING \
01030    { AST_LOCK_TRACK_INIT_VALUE, 0, __AST_RWLOCK_INIT_VALUE }
01031 
01032 static inline int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
01033 {
01034    int res;
01035    struct ast_lock_track *lt= &t->track;
01036    pthread_rwlockattr_t attr;
01037 
01038 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01039    int canlog = strcmp(filename, "logger.c") & t->tracking;
01040 
01041    if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01042       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
01043             filename, lineno, func, rwlock_name);
01044       return 0;
01045    }
01046 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01047 
01048    ast_reentrancy_init(lt);
01049    t->tracking = tracking;
01050    pthread_rwlockattr_init(&attr);
01051 
01052 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01053    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01054 #endif
01055 
01056    res = pthread_rwlock_init(&t->lock, &attr);
01057    pthread_rwlockattr_destroy(&attr);
01058    return res;
01059 }
01060 
01061 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
01062 {
01063    int res;
01064    struct ast_lock_track *lt = &t->track;
01065    int canlog = strcmp(filename, "logger.c") & t->tracking;
01066 
01067 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01068    if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01069       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
01070                filename, lineno, func, rwlock_name);
01071       return 0;
01072    }
01073 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01074 
01075    if ((res = pthread_rwlock_destroy(&t->lock))) {
01076       __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
01077             filename, lineno, func, rwlock_name, strerror(res));
01078    }
01079    ast_reentrancy_lock(lt);
01080    lt->file[0] = filename;
01081    lt->lineno[0] = lineno;
01082    lt->func[0] = func;
01083    lt->reentrancy = 0;
01084    lt->thread[0] = 0;
01085 #ifdef HAVE_BKTR
01086    memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
01087 #endif
01088    ast_reentrancy_unlock(lt);
01089    delete_reentrancy_cs(lt);
01090 
01091    return res;
01092 }
01093 
01094 static inline int _ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
01095    const char *filename, int line, const char *func)
01096 {
01097    int res;
01098    struct ast_lock_track *lt = &t->track;
01099    int canlog = strcmp(filename, "logger.c") & t->tracking;
01100 #ifdef HAVE_BKTR
01101    struct ast_bt *bt = NULL;
01102 #endif
01103    int lock_found = 0;
01104 
01105 
01106 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01107    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01108       __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
01109                filename, line, func, name);
01110       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01111       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01112          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01113                filename, line, func, name);
01114       }
01115       return res;
01116    }
01117 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01118 
01119    ast_reentrancy_lock(lt);
01120    if (lt->reentrancy) {
01121       int i;
01122       pthread_t self = pthread_self();
01123       for (i = lt->reentrancy - 1; i >= 0; --i) {
01124          if (lt->thread[i] == self) {
01125             lock_found = 1;
01126             if (i != lt->reentrancy - 1) {
01127                lt->file[i] = lt->file[lt->reentrancy - 1];
01128                lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
01129                lt->func[i] = lt->func[lt->reentrancy - 1];
01130                lt->thread[i] = lt->thread[lt->reentrancy - 1];
01131             }
01132 #ifdef HAVE_BKTR
01133             bt = &lt->backtrace[i];
01134 #endif
01135             lt->file[lt->reentrancy - 1] = NULL;
01136             lt->lineno[lt->reentrancy - 1] = 0;
01137             lt->func[lt->reentrancy - 1] = NULL;
01138             lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
01139             break;
01140          }
01141       }
01142    }
01143 
01144    if (lock_found && --lt->reentrancy < 0) {
01145       __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
01146             filename, line, func, name);
01147       lt->reentrancy = 0;
01148    }
01149 
01150    ast_reentrancy_unlock(lt);
01151 
01152    if (t->tracking) {
01153 #ifdef HAVE_BKTR
01154       ast_remove_lock_info(t, bt);
01155 #else
01156       ast_remove_lock_info(t);
01157 #endif
01158    }
01159 
01160    if ((res = pthread_rwlock_unlock(&t->lock))) {
01161       __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
01162             filename, line, func, strerror(res));
01163       DO_THREAD_CRASH;
01164    }
01165 
01166    return res;
01167 }
01168 
01169 static inline int _ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
01170    const char *filename, int line, const char *func)
01171 {
01172    int res;
01173    struct ast_lock_track *lt = &t->track;
01174    int canlog = strcmp(filename, "logger.c") & t->tracking;
01175 #ifdef HAVE_BKTR
01176    struct ast_bt *bt = NULL;
01177 #endif
01178 
01179 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01180    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01181        /* Don't warn abount uninitialized lock.
01182         * Simple try to initialize it.
01183         * May be not needed in linux system.
01184         */
01185       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01186       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01187          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01188                filename, line, func, name);
01189          return res;
01190       }
01191    }
01192 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01193 
01194    if (t->tracking) {
01195 #ifdef HAVE_BKTR
01196       ast_reentrancy_lock(lt);
01197       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01198          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01199          bt = &lt->backtrace[lt->reentrancy];
01200       }
01201       ast_reentrancy_unlock(lt);
01202       ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
01203 #else
01204       ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
01205 #endif
01206    }
01207 
01208 #ifdef DETECT_DEADLOCKS
01209    {
01210       time_t seconds = time(NULL);
01211       time_t wait_time, reported_wait = 0;
01212       do {
01213          res = pthread_rwlock_tryrdlock(&t->lock);
01214          if (res == EBUSY) {
01215             wait_time = time(NULL) - seconds;
01216             if (wait_time > reported_wait && (wait_time % 5) == 0) {
01217                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
01218                   filename, line, func, (int)wait_time, name);
01219                ast_reentrancy_lock(lt);
01220 #ifdef HAVE_BKTR
01221                __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
01222 #endif
01223                __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
01224                      lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
01225                      lt->func[lt->reentrancy-1], name);
01226 #ifdef HAVE_BKTR
01227                __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
01228 #endif
01229                ast_reentrancy_unlock(lt);
01230                reported_wait = wait_time;
01231             }
01232             usleep(200);
01233          }
01234       } while (res == EBUSY);
01235    }
01236 #else /* !DETECT_DEADLOCKS */
01237    res = pthread_rwlock_rdlock(&t->lock);
01238 #endif /* !DETECT_DEADLOCKS */
01239 
01240    if (!res) {
01241       ast_reentrancy_lock(lt);
01242       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01243          lt->file[lt->reentrancy] = filename;
01244          lt->lineno[lt->reentrancy] = line;
01245          lt->func[lt->reentrancy] = func;
01246          lt->thread[lt->reentrancy] = pthread_self();
01247          lt->reentrancy++;
01248       }
01249       ast_reentrancy_unlock(lt);
01250       if (t->tracking) {
01251          ast_mark_lock_acquired(t);
01252       }
01253    } else {
01254 #ifdef HAVE_BKTR
01255       if (lt->reentrancy) {
01256          ast_reentrancy_lock(lt);
01257          bt = &lt->backtrace[lt->reentrancy-1];
01258          ast_reentrancy_unlock(lt);
01259       } else {
01260          bt = NULL;
01261       }
01262       if (t->tracking) {
01263          ast_remove_lock_info(t, bt);
01264       }
01265 #else
01266       if (t->tracking) {
01267          ast_remove_lock_info(t);
01268       }
01269 #endif
01270       __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01271             filename, line, func, strerror(res));
01272       DO_THREAD_CRASH;
01273    }
01274    return res;
01275 }
01276 
01277 static inline int _ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
01278    const char *filename, int line, const char *func)
01279 {
01280    int res;
01281    struct ast_lock_track *lt = &t->track;
01282    int canlog = strcmp(filename, "logger.c") & t->tracking;
01283 #ifdef HAVE_BKTR
01284    struct ast_bt *bt = NULL;
01285 #endif
01286 
01287 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01288    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01289        /* Don't warn abount uninitialized lock.
01290         * Simple try to initialize it.
01291         * May be not needed in linux system.
01292         */
01293       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01294       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01295          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01296                filename, line, func, name);
01297          return res;
01298       }
01299    }
01300 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01301 
01302    if (t->tracking) {
01303 #ifdef HAVE_BKTR
01304       ast_reentrancy_lock(lt);
01305       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01306          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01307          bt = &lt->backtrace[lt->reentrancy];
01308       }
01309       ast_reentrancy_unlock(lt);
01310       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01311 #else
01312       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01313 #endif
01314    }
01315 #ifdef DETECT_DEADLOCKS
01316    {
01317       time_t seconds = time(NULL);
01318       time_t wait_time, reported_wait = 0;
01319       do {
01320          res = pthread_rwlock_trywrlock(&t->lock);
01321          if (res == EBUSY) {
01322             wait_time = time(NULL) - seconds;
01323             if (wait_time > reported_wait && (wait_time % 5) == 0) {
01324                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
01325                   filename, line, func, (int)wait_time, name);
01326                ast_reentrancy_lock(lt);
01327 #ifdef HAVE_BKTR
01328                __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
01329 #endif
01330                __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
01331                      lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
01332                      lt->func[lt->reentrancy-1], name);
01333 #ifdef HAVE_BKTR
01334                __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
01335 #endif
01336                ast_reentrancy_unlock(lt);
01337                reported_wait = wait_time;
01338             }
01339             usleep(200);
01340          }
01341       } while (res == EBUSY);
01342    }
01343 #else /* !DETECT_DEADLOCKS */
01344    res = pthread_rwlock_wrlock(&t->lock);
01345 #endif /* !DETECT_DEADLOCKS */
01346 
01347    if (!res) {
01348       ast_reentrancy_lock(lt);
01349       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01350          lt->file[lt->reentrancy] = filename;
01351          lt->lineno[lt->reentrancy] = line;
01352          lt->func[lt->reentrancy] = func;
01353          lt->thread[lt->reentrancy] = pthread_self();
01354          lt->reentrancy++;
01355       }
01356       ast_reentrancy_unlock(lt);
01357       if (t->tracking) {
01358          ast_mark_lock_acquired(t);
01359       }
01360    } else {
01361 #ifdef HAVE_BKTR
01362       if (lt->reentrancy) {
01363          ast_reentrancy_lock(lt);
01364          bt = &lt->backtrace[lt->reentrancy-1];
01365          ast_reentrancy_unlock(lt);
01366       } else {
01367          bt = NULL;
01368       }
01369       if (t->tracking) {
01370          ast_remove_lock_info(t, bt);
01371       }
01372 #else
01373       if (t->tracking) {
01374          ast_remove_lock_info(t);
01375       }
01376 #endif
01377       __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
01378             filename, line, func, strerror(res));
01379       DO_THREAD_CRASH;
01380    }
01381    return res;
01382 }
01383 
01384 #define ast_rwlock_timedrdlock(a, b) \
01385    _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01386 
01387 static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
01388    const struct timespec *abs_timeout, const char *filename, int line, const char *func)
01389 {
01390    int res;
01391    struct ast_lock_track *lt = &t->track;
01392    int canlog = strcmp(filename, "logger.c") & t->tracking;
01393 #ifdef HAVE_BKTR
01394    struct ast_bt *bt = NULL;
01395 #endif
01396 
01397 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01398    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01399        /* Don't warn abount uninitialized lock.
01400         * Simple try to initialize it.
01401         * May be not needed in linux system.
01402         */
01403       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01404       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01405          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01406                filename, line, func, name);
01407          return res;
01408       }
01409    }
01410 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01411 
01412    if (t->tracking) {
01413 #ifdef HAVE_BKTR
01414       ast_reentrancy_lock(lt);
01415       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01416          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01417          bt = &lt->backtrace[lt->reentrancy];
01418       }
01419       ast_reentrancy_unlock(lt);
01420       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01421 #else
01422       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01423 #endif
01424    }
01425 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01426    res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
01427 #else
01428    do {
01429       struct timeval _start = ast_tvnow(), _diff;
01430       for (;;) {
01431          if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
01432             break;
01433          }
01434          _diff = ast_tvsub(ast_tvnow(), _start);
01435          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01436             break;
01437          }
01438          usleep(1);
01439       }
01440    } while (0);
01441 #endif
01442    if (!res) {
01443       ast_reentrancy_lock(lt);
01444       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01445          lt->file[lt->reentrancy] = filename;
01446          lt->lineno[lt->reentrancy] = line;
01447          lt->func[lt->reentrancy] = func;
01448          lt->thread[lt->reentrancy] = pthread_self();
01449          lt->reentrancy++;
01450       }
01451       ast_reentrancy_unlock(lt);
01452       if (t->tracking) {
01453          ast_mark_lock_acquired(t);
01454       }
01455    } else {
01456 #ifdef HAVE_BKTR
01457       if (lt->reentrancy) {
01458          ast_reentrancy_lock(lt);
01459          bt = &lt->backtrace[lt->reentrancy-1];
01460          ast_reentrancy_unlock(lt);
01461       } else {
01462          bt = NULL;
01463       }
01464       if (t->tracking) {
01465          ast_remove_lock_info(t, bt);
01466       }
01467 #else
01468       if (t->tracking) {
01469          ast_remove_lock_info(t);
01470       }
01471 #endif
01472       __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01473             filename, line, func, strerror(res));
01474       DO_THREAD_CRASH;
01475    }
01476    return res;
01477 }
01478 
01479 #define ast_rwlock_timedwrlock(a, b) \
01480    _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01481 
01482 static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
01483    const struct timespec *abs_timeout, const char *filename, int line, const char *func)
01484 {
01485    int res;
01486    struct ast_lock_track *lt = &t->track;
01487    int canlog = strcmp(filename, "logger.c") & t->tracking;
01488 #ifdef HAVE_BKTR
01489    struct ast_bt *bt = NULL;
01490 #endif
01491 
01492 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01493    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01494        /* Don't warn abount uninitialized lock.
01495         * Simple try to initialize it.
01496         * May be not needed in linux system.
01497         */
01498       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01499       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01500          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01501                filename, line, func, name);
01502          return res;
01503       }
01504    }
01505 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01506 
01507    if (t->tracking) {
01508 #ifdef HAVE_BKTR
01509       ast_reentrancy_lock(lt);
01510       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01511          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01512          bt = &lt->backtrace[lt->reentrancy];
01513       }
01514       ast_reentrancy_unlock(lt);
01515       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01516 #else
01517       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01518 #endif
01519    }
01520 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01521    res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
01522 #else
01523    do {
01524       struct timeval _start = ast_tvnow(), _diff;
01525       for (;;) {
01526          if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
01527             break;
01528          }
01529          _diff = ast_tvsub(ast_tvnow(), _start);
01530          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01531             break;
01532          }
01533          usleep(1);
01534       }
01535    } while (0);
01536 #endif
01537    if (!res) {
01538       ast_reentrancy_lock(lt);
01539       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01540          lt->file[lt->reentrancy] = filename;
01541          lt->lineno[lt->reentrancy] = line;
01542          lt->func[lt->reentrancy] = func;
01543          lt->thread[lt->reentrancy] = pthread_self();
01544          lt->reentrancy++;
01545       }
01546       ast_reentrancy_unlock(lt);
01547       if (t->tracking) {
01548          ast_mark_lock_acquired(t);
01549       }
01550    } else {
01551 #ifdef HAVE_BKTR
01552       if (lt->reentrancy) {
01553          ast_reentrancy_lock(lt);
01554          bt = &lt->backtrace[lt->reentrancy-1];
01555          ast_reentrancy_unlock(lt);
01556       } else {
01557          bt = NULL;
01558       }
01559       if (t->tracking) {
01560          ast_remove_lock_info(t, bt);
01561       }
01562 #else
01563       if (t->tracking) {
01564          ast_remove_lock_info(t);
01565       }
01566 #endif
01567       __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01568             filename, line, func, strerror(res));
01569       DO_THREAD_CRASH;
01570    }
01571    return res;
01572 }
01573 
01574 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
01575    const char *filename, int line, const char *func)
01576 {
01577    int res;
01578    struct ast_lock_track *lt = &t->track;
01579 #ifdef HAVE_BKTR
01580    struct ast_bt *bt = NULL;
01581 #endif
01582 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01583    int canlog = strcmp(filename, "logger.c") & t->tracking;
01584 
01585    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01586        /* Don't warn abount uninitialized lock.
01587         * Simple try to initialize it.
01588         * May be not needed in linux system.
01589         */
01590       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01591       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01592          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01593                filename, line, func, name);
01594          return res;
01595       }
01596    }
01597 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01598 
01599    if (t->tracking) {
01600 #ifdef HAVE_BKTR
01601       ast_reentrancy_lock(lt);
01602       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01603          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01604          bt = &lt->backtrace[lt->reentrancy];
01605       }
01606       ast_reentrancy_unlock(lt);
01607       ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
01608 #else
01609       ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
01610 #endif
01611    }
01612 
01613    if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
01614       ast_reentrancy_lock(lt);
01615       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01616          lt->file[lt->reentrancy] = filename;
01617          lt->lineno[lt->reentrancy] = line;
01618          lt->func[lt->reentrancy] = func;
01619          lt->thread[lt->reentrancy] = pthread_self();
01620          lt->reentrancy++;
01621       }
01622       ast_reentrancy_unlock(lt);
01623       if (t->tracking) {
01624          ast_mark_lock_acquired(t);
01625       }
01626    } else if (t->tracking) {
01627       ast_mark_lock_failed(t);
01628    }
01629    return res;
01630 }
01631 
01632 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
01633    const char *filename, int line, const char *func)
01634 {
01635    int res;
01636    struct ast_lock_track *lt= &t->track;
01637 #ifdef HAVE_BKTR
01638    struct ast_bt *bt = NULL;
01639 #endif
01640 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
01641    int canlog = strcmp(filename, "logger.c") & t->tracking;
01642 
01643    if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01644        /* Don't warn abount uninitialized lock.
01645         * Simple try to initialize it.
01646         * May be not needed in linux system.
01647         */
01648       res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01649       if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01650          __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01651                filename, line, func, name);
01652          return res;
01653       }
01654    }
01655 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01656 
01657    if (t->tracking) {
01658 #ifdef HAVE_BKTR
01659       ast_reentrancy_lock(lt);
01660       if (lt->reentrancy != AST_MAX_REENTRANCY) {
01661          ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
01662          bt = &lt->backtrace[lt->reentrancy];
01663       }
01664       ast_reentrancy_unlock(lt);
01665       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01666 #else
01667       ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01668 #endif
01669    }
01670 
01671    if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
01672       ast_reentrancy_lock(lt);
01673       if (lt->reentrancy < AST_MAX_REENTRANCY) {
01674          lt->file[lt->reentrancy] = filename;
01675          lt->lineno[lt->reentrancy] = line;
01676          lt->func[lt->reentrancy] = func;
01677          lt->thread[lt->reentrancy] = pthread_self();
01678          lt->reentrancy++;
01679       }
01680       ast_reentrancy_unlock(lt);
01681       if (t->tracking) {
01682          ast_mark_lock_acquired(t);
01683       }
01684    } else if (t->tracking) {
01685       ast_mark_lock_failed(t);
01686    }
01687    return res;
01688 }
01689 
01690 #else /* !DEBUG_THREADS */
01691 
01692 #define  CHANNEL_DEADLOCK_AVOIDANCE(chan) \
01693    ast_channel_unlock(chan); \
01694    usleep(1); \
01695    ast_channel_lock(chan);
01696 
01697 #define  DEADLOCK_AVOIDANCE(lock) \
01698    do { \
01699       int __res; \
01700       if (!(__res = ast_mutex_unlock(lock))) { \
01701          usleep(1); \
01702          ast_mutex_lock(lock); \
01703       } else { \
01704          ast_log(LOG_WARNING, "Failed to unlock mutex '%s' (%s).  I will NOT try to relock. {{{ THIS IS A BUG. }}}\n", #lock, strerror(__res)); \
01705       } \
01706    } while (0)
01707 
01708 #define DLA_UNLOCK(lock)   ast_mutex_unlock(lock)
01709 
01710 #define DLA_LOCK(lock)  ast_mutex_lock(lock)
01711 
01712 typedef pthread_mutex_t ast_mutex_t;
01713 
01714 #define AST_MUTEX_INIT_VALUE        ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
01715 #define AST_MUTEX_INIT_VALUE_NOTRACKING      ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
01716 
01717 #define ast_mutex_init_notracking(m)      ast_mutex_init(m)
01718 
01719 static inline int ast_mutex_init(ast_mutex_t *pmutex)
01720 {
01721    int res;
01722    pthread_mutexattr_t attr;
01723 
01724    pthread_mutexattr_init(&attr);
01725    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
01726 
01727    res = pthread_mutex_init(pmutex, &attr);
01728    pthread_mutexattr_destroy(&attr);
01729    return res;
01730 }
01731 
01732 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
01733 
01734 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
01735 {
01736    return pthread_mutex_unlock(pmutex);
01737 }
01738 
01739 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
01740 {
01741    return pthread_mutex_destroy(pmutex);
01742 }
01743 
01744 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
01745 {
01746    __MTX_PROF(pmutex);
01747 }
01748 
01749 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
01750 {
01751    return pthread_mutex_trylock(pmutex);
01752 }
01753 
01754 typedef pthread_cond_t ast_cond_t;
01755 
01756 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
01757 {
01758    return pthread_cond_init(cond, cond_attr);
01759 }
01760 
01761 static inline int ast_cond_signal(ast_cond_t *cond)
01762 {
01763    return pthread_cond_signal(cond);
01764 }
01765 
01766 static inline int ast_cond_broadcast(ast_cond_t *cond)
01767 {
01768    return pthread_cond_broadcast(cond);
01769 }
01770 
01771 static inline int ast_cond_destroy(ast_cond_t *cond)
01772 {
01773    return pthread_cond_destroy(cond);
01774 }
01775 
01776 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
01777 {
01778    return pthread_cond_wait(cond, t);
01779 }
01780 
01781 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
01782 {
01783    return pthread_cond_timedwait(cond, t, abstime);
01784 }
01785 
01786 
01787 typedef pthread_rwlock_t ast_rwlock_t;
01788 
01789 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
01790 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
01791 #else
01792 #define AST_RWLOCK_INIT_VALUE { 0 }
01793 #endif
01794 
01795 #define ast_rwlock_init_notracking(a) ast_rwlock_init(a)
01796 
01797 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
01798 {
01799    int res;
01800    pthread_rwlockattr_t attr;
01801 
01802    pthread_rwlockattr_init(&attr);
01803 
01804 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01805    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01806 #endif
01807 
01808    res = pthread_rwlock_init(prwlock, &attr);
01809    pthread_rwlockattr_destroy(&attr);
01810    return res;
01811 }
01812 
01813 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
01814 {
01815    return pthread_rwlock_destroy(prwlock);
01816 }
01817 
01818 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
01819 {
01820    return pthread_rwlock_unlock(prwlock);
01821 }
01822 
01823 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
01824 {
01825    return pthread_rwlock_rdlock(prwlock);
01826 }
01827 
01828 static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01829 {
01830    int res;
01831 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01832    res = pthread_rwlock_timedrdlock(prwlock, abs_timeout);
01833 #else
01834    struct timeval _start = ast_tvnow(), _diff;
01835    for (;;) {
01836       if (!(res = pthread_rwlock_tryrdlock(prwlock))) {
01837          break;
01838       }
01839       _diff = ast_tvsub(ast_tvnow(), _start);
01840       if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01841          break;
01842       }
01843       usleep(1);
01844    }
01845 #endif
01846    return res;
01847 }
01848 
01849 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
01850 {
01851    return pthread_rwlock_tryrdlock(prwlock);
01852 }
01853 
01854 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
01855 {
01856    return pthread_rwlock_wrlock(prwlock);
01857 }
01858 
01859 static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01860 {
01861    int res;
01862 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01863    res = pthread_rwlock_timedwrlock(prwlock, abs_timeout);
01864 #else
01865    do {
01866       struct timeval _start = ast_tvnow(), _diff;
01867       for (;;) {
01868          if (!(res = pthread_rwlock_trywrlock(prwlock))) {
01869             break;
01870          }
01871          _diff = ast_tvsub(ast_tvnow(), _start);
01872          if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01873             break;
01874          }
01875          usleep(1);
01876       }
01877    } while (0);
01878 #endif
01879    return res;
01880 }
01881 
01882 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
01883 {
01884    return pthread_rwlock_trywrlock(prwlock);
01885 }
01886 
01887 #endif /* !DEBUG_THREADS */
01888 
01889 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
01890 /*
01891  * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
01892  * and destructors to create/destroy global mutexes.
01893  */
01894 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)   \
01895    scope ast_mutex_t mutex = init_val;       \
01896 static void  __attribute__((constructor)) init_##mutex(void)   \
01897 {                       \
01898    if (track)                 \
01899       ast_mutex_init(&mutex);          \
01900    else                    \
01901       ast_mutex_init_notracking(&mutex);     \
01902 }                       \
01903                         \
01904 static void  __attribute__((destructor)) fini_##mutex(void) \
01905 {                       \
01906    ast_mutex_destroy(&mutex);          \
01907 }
01908 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
01909 /* By default, use static initialization of mutexes. */
01910 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)   scope ast_mutex_t mutex = init_val
01911 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
01912 
01913 #ifndef __CYGWIN__   /* temporary disabled for cygwin */
01914 #define pthread_mutex_t    use_ast_mutex_t_instead_of_pthread_mutex_t
01915 #define pthread_cond_t     use_ast_cond_t_instead_of_pthread_cond_t
01916 #endif
01917 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
01918 #define pthread_mutex_unlock  use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
01919 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
01920 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
01921 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
01922 #define pthread_cond_init  use_ast_cond_init_instead_of_pthread_cond_init
01923 #define pthread_cond_destroy  use_ast_cond_destroy_instead_of_pthread_cond_destroy
01924 #define pthread_cond_signal   use_ast_cond_signal_instead_of_pthread_cond_signal
01925 #define pthread_cond_broadcast   use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
01926 #define pthread_cond_wait  use_ast_cond_wait_instead_of_pthread_cond_wait
01927 #define pthread_cond_timedwait   use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
01928 
01929 #define AST_MUTEX_DEFINE_STATIC(mutex)       __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
01930 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex)  __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
01931 
01932 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
01933 
01934 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
01935 
01936 #ifndef __linux__
01937 #define pthread_create __use_ast_pthread_create_instead__
01938 #endif
01939 
01940 /* Statically declared read/write locks */
01941 
01942 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01943 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
01944         scope ast_rwlock_t rwlock = init_val; \
01945 static void  __attribute__((constructor)) init_##rwlock(void) \
01946 { \
01947    if (track) \
01948          ast_rwlock_init(&rwlock); \
01949    else \
01950       ast_rwlock_init_notracking(&rwlock); \
01951 } \
01952 static void  __attribute__((destructor)) fini_##rwlock(void) \
01953 { \
01954         ast_rwlock_destroy(&rwlock); \
01955 }
01956 #else
01957 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
01958         scope ast_rwlock_t rwlock = init_val
01959 #endif
01960 
01961 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
01962 #define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
01963 
01964 /*
01965  * Support for atomic instructions.
01966  * For platforms that have it, use the native cpu instruction to
01967  * implement them. For other platforms, resort to a 'slow' version
01968  * (defined in utils.c) that protects the atomic instruction with
01969  * a single lock.
01970  * The slow versions is always available, for testing purposes,
01971  * as ast_atomic_fetchadd_int_slow()
01972  */
01973 
01974 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
01975 
01976 #include "asterisk/inline_api.h"
01977 
01978 #if defined(HAVE_OSX_ATOMICS)
01979 #include "libkern/OSAtomic.h"
01980 #endif
01981 
01982 /*! \brief Atomically add v to *p and return * the previous value of *p.
01983  * This can be used to handle reference counts, and the return value
01984  * can be used to generate unique identifiers.
01985  */
01986 
01987 #if defined(HAVE_GCC_ATOMICS)
01988 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01989 {
01990    return __sync_fetch_and_add(p, v);
01991 })
01992 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01993 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01994 {
01995    return OSAtomicAdd32(v, (int32_t *) p) - v;
01996 })
01997 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01998 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01999 {
02000    return OSAtomicAdd64(v, (int64_t *) p) - v;
02001 #elif defined (__i386__) || defined(__x86_64__)
02002 #ifdef sun
02003 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
02004 {
02005    __asm __volatile (
02006    "       lock;  xaddl   %0, %1 ;        "
02007    : "+r" (v),                     /* 0 (result) */
02008      "=m" (*p)                     /* 1 */
02009    : "m" (*p));                    /* 2 */
02010    return (v);
02011 })
02012 #else /* ifndef sun */
02013 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
02014 {
02015    __asm __volatile (
02016    "       lock   xaddl   %0, %1 ;        "
02017    : "+r" (v),                     /* 0 (result) */
02018      "=m" (*p)                     /* 1 */
02019    : "m" (*p));                    /* 2 */
02020    return (v);
02021 })
02022 #endif
02023 #else   /* low performance version in utils.c */
02024 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
02025 {
02026    return ast_atomic_fetchadd_int_slow(p, v);
02027 })
02028 #endif
02029 
02030 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
02031  * Useful e.g. to check if a refcount has reached 0.
02032  */
02033 #if defined(HAVE_GCC_ATOMICS)
02034 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02035 {
02036    return __sync_sub_and_fetch(p, 1) == 0;
02037 })
02038 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
02039 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02040 {
02041    return OSAtomicAdd32( -1, (int32_t *) p) == 0;
02042 })
02043 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
02044 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02045 {
02046    return OSAtomicAdd64( -1, (int64_t *) p) == 0;
02047 #else
02048 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02049 {
02050    int a = ast_atomic_fetchadd_int(p, -1);
02051    return a == 1; /* true if the value is 0 now (so it was 1 previously) */
02052 })
02053 #endif
02054 
02055 #ifndef DEBUG_CHANNEL_LOCKS
02056 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
02057    in the Makefile, print relevant output for debugging */
02058 #define ast_channel_lock(x)      ast_mutex_lock(&x->lock_dont_use)
02059 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
02060    in the Makefile, print relevant output for debugging */
02061 #define ast_channel_unlock(x)    ast_mutex_unlock(&x->lock_dont_use)
02062 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
02063    in the Makefile, print relevant output for debugging */
02064 #define ast_channel_trylock(x)      ast_mutex_trylock(&x->lock_dont_use)
02065 #else
02066 
02067 #define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02068 /*! \brief Lock AST channel (and print debugging output)
02069 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
02070 int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02071 
02072 #define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02073 /*! \brief Unlock AST channel (and print debugging output)
02074 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
02075 */
02076 int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02077 
02078 #define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02079 /*! \brief Lock AST channel (and print debugging output)
02080 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
02081 int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02082 #endif
02083 
02084 #endif /* _ASTERISK_LOCK_H */