Wed Oct 28 11:45:39 2009

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

Generated on Wed Oct 28 11:45:39 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6