Mon Mar 31 07:38:03 2008

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

Generated on Mon Mar 31 07:38:03 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1