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

Generated on Fri Sep 11 13:44:59 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7