Fri Aug 24 02:22:15 2007

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 } }
00107 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00108                              { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 } }
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 };
00122 
00123 typedef struct ast_mutex_info ast_mutex_t;
00124 
00125 typedef pthread_cond_t ast_cond_t;
00126 
00127 static pthread_mutex_t empty_mutex;
00128 
00129 /*!
00130  * \brief Store lock info for the current thread
00131  *
00132  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
00133  * that information about this lock can be stored in this thread's
00134  * lock info struct.  The lock is marked as pending as the thread is waiting
00135  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
00136  */
00137 void ast_store_lock_info(const char *filename, int line_num, 
00138    const char *func, const char *lock_name, void *lock_addr);
00139 
00140 /*!
00141  * \brief Mark the last lock as acquired
00142  */
00143 void ast_mark_lock_acquired(void);
00144 
00145 /*!
00146  * \brief remove lock info for the current thread
00147  *
00148  * this gets called by ast_mutex_unlock so that information on the lock can
00149  * be removed from the current thread's lock info struct.
00150  */
00151 void ast_remove_lock_info(void *lock_addr);
00152 
00153 static void __attribute__((constructor)) init_empty_mutex(void)
00154 {
00155    memset(&empty_mutex, 0, sizeof(empty_mutex));
00156 }
00157 
00158 static inline int __ast_pthread_mutex_init_attr(int track, const char *filename, int lineno, const char *func,
00159                   const char *mutex_name, ast_mutex_t *t,
00160                   pthread_mutexattr_t *attr) 
00161 {
00162 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00163    int canlog = strcmp(filename, "logger.c");
00164 
00165    if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00166       if ((t->mutex) != (empty_mutex)) {
00167          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
00168                   filename, lineno, func, mutex_name);
00169          __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
00170                   t->file[0], t->lineno[0], t->func[0], mutex_name);
00171          DO_THREAD_CRASH;
00172          return 0;
00173       }
00174    }
00175 #endif
00176 
00177    t->file[0] = filename;
00178    t->lineno[0] = lineno;
00179    t->func[0] = func;
00180    t->thread[0]  = 0;
00181    t->reentrancy = 0;
00182    t->track = track;
00183 
00184    return pthread_mutex_init(&t->mutex, attr);
00185 }
00186 
00187 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
00188                   const char *mutex_name, ast_mutex_t *t)
00189 {
00190    static pthread_mutexattr_t  attr;
00191 
00192    pthread_mutexattr_init(&attr);
00193    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00194 
00195    return __ast_pthread_mutex_init_attr(track, filename, lineno, func, mutex_name, t, &attr);
00196 }
00197 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00198 #define ast_mutex_init_notracking(pmutex) \
00199    __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00200 
00201 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00202                   const char *mutex_name, ast_mutex_t *t)
00203 {
00204    int res;
00205    int canlog = strcmp(filename, "logger.c");
00206 
00207 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00208    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00209       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00210                filename, lineno, func, mutex_name);
00211    }
00212 #endif
00213 
00214    res = pthread_mutex_trylock(&t->mutex);
00215    switch (res) {
00216    case 0:
00217       pthread_mutex_unlock(&t->mutex);
00218       break;
00219    case EINVAL:
00220       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00221               filename, lineno, func, mutex_name);
00222       break;
00223    case EBUSY:
00224       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00225                filename, lineno, func, mutex_name);
00226       __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00227                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00228       break;
00229    }
00230 
00231    if ((res = pthread_mutex_destroy(&t->mutex)))
00232       __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
00233                filename, lineno, func, strerror(res));
00234 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00235    else
00236       t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00237 #endif
00238    t->file[0] = filename;
00239    t->lineno[0] = lineno;
00240    t->func[0] = func;
00241 
00242    return res;
00243 }
00244 
00245 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00246                                            const char* mutex_name, ast_mutex_t *t)
00247 {
00248    int res;
00249    int canlog = strcmp(filename, "logger.c");
00250 
00251    if (t->track)
00252       ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
00253 
00254 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00255    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00256       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00257              filename, lineno, func, mutex_name);
00258       ast_mutex_init(t);
00259    }
00260 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00261 
00262 #ifdef DETECT_DEADLOCKS
00263    {
00264       time_t seconds = time(NULL);
00265       time_t current;
00266       do {
00267 #ifdef   HAVE_MTX_PROFILE
00268          ast_mark(mtx_prof, 1);
00269 #endif
00270          res = pthread_mutex_trylock(&t->mutex);
00271 #ifdef   HAVE_MTX_PROFILE
00272          ast_mark(mtx_prof, 0);
00273 #endif
00274          if (res == EBUSY) {
00275             current = time(NULL);
00276             if ((current - seconds) && (!((current - seconds) % 5))) {
00277                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00278                         filename, lineno, func, (int)(current - seconds), mutex_name);
00279                __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00280                         t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
00281                         t->func[t->reentrancy-1], mutex_name);
00282             }
00283             usleep(200);
00284          }
00285       } while (res == EBUSY);
00286    }
00287 #else
00288 #ifdef   HAVE_MTX_PROFILE
00289    ast_mark(mtx_prof, 1);
00290    res = pthread_mutex_trylock(&t->mutex);
00291    ast_mark(mtx_prof, 0);
00292    if (res)
00293 #endif
00294    res = pthread_mutex_lock(&t->mutex);
00295 #endif /* DETECT_DEADLOCKS */
00296 
00297    if (!res) {
00298       if (t->track)
00299          ast_mark_lock_acquired();
00300       if (t->reentrancy < AST_MAX_REENTRANCY) {
00301          t->file[t->reentrancy] = filename;
00302          t->lineno[t->reentrancy] = lineno;
00303          t->func[t->reentrancy] = func;
00304          t->thread[t->reentrancy] = pthread_self();
00305          t->reentrancy++;
00306       } else {
00307          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00308                         filename, lineno, func, mutex_name);
00309       }
00310    } else {
00311       if (t->track)
00312          ast_remove_lock_info(&t->mutex);
00313       __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00314                filename, lineno, func, strerror(res));
00315       DO_THREAD_CRASH;
00316    }
00317 
00318    return res;
00319 }
00320 
00321 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00322                                               const char* mutex_name, ast_mutex_t *t)
00323 {
00324    int res;
00325    int canlog = strcmp(filename, "logger.c");
00326 
00327 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00328    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00329       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00330                filename, lineno, func, mutex_name);
00331       ast_mutex_init(t);
00332    }
00333 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00334 
00335    if (t->track)
00336       ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
00337 
00338    if (!(res = pthread_mutex_trylock(&t->mutex))) {
00339       if (t->track)
00340          ast_mark_lock_acquired();
00341       if (t->reentrancy < AST_MAX_REENTRANCY) {
00342          t->file[t->reentrancy] = filename;
00343          t->lineno[t->reentrancy] = lineno;
00344          t->func[t->reentrancy] = func;
00345          t->thread[t->reentrancy] = pthread_self();
00346          t->reentrancy++;
00347       } else {
00348          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00349                   filename, lineno, func, mutex_name);
00350       }
00351    } else if (t->track) {
00352          ast_remove_lock_info(&t->mutex);
00353    }
00354 
00355    return res;
00356 }
00357 
00358 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00359                     const char *mutex_name, ast_mutex_t *t)
00360 {
00361    int res;
00362    int canlog = strcmp(filename, "logger.c");
00363 
00364 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00365    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00366       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00367                filename, lineno, func, mutex_name);
00368    }
00369 #endif
00370 
00371    if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00372       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00373                filename, lineno, func, mutex_name);
00374       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00375                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00376       DO_THREAD_CRASH;
00377    }
00378 
00379    if (--t->reentrancy < 0) {
00380       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00381                filename, lineno, func, mutex_name);
00382       t->reentrancy = 0;
00383    }
00384 
00385    if (t->reentrancy < AST_MAX_REENTRANCY) {
00386       t->file[t->reentrancy] = NULL;
00387       t->lineno[t->reentrancy] = 0;
00388       t->func[t->reentrancy] = NULL;
00389       t->thread[t->reentrancy] = 0;
00390    }
00391 
00392    if (t->track)
00393       ast_remove_lock_info(&t->mutex);
00394 
00395    if ((res = pthread_mutex_unlock(&t->mutex))) {
00396       __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
00397                filename, lineno, func, strerror(res));
00398       DO_THREAD_CRASH;
00399    }
00400 
00401    return res;
00402 }
00403 
00404 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00405               const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00406 {
00407    return pthread_cond_init(cond, cond_attr);
00408 }
00409 
00410 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00411                 const char *cond_name, ast_cond_t *cond)
00412 {
00413    return pthread_cond_signal(cond);
00414 }
00415 
00416 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00417                    const char *cond_name, ast_cond_t *cond)
00418 {
00419    return pthread_cond_broadcast(cond);
00420 }
00421 
00422 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00423                  const char *cond_name, ast_cond_t *cond)
00424 {
00425    return pthread_cond_destroy(cond);
00426 }
00427 
00428 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00429               const char *cond_name, const char *mutex_name,
00430               ast_cond_t *cond, ast_mutex_t *t)
00431 {
00432    int res;
00433    int canlog = strcmp(filename, "logger.c");
00434 
00435 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00436    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00437       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00438                filename, lineno, func, mutex_name);
00439    }
00440 #endif
00441 
00442    if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00443       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00444                filename, lineno, func, mutex_name);
00445       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00446                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00447       DO_THREAD_CRASH;
00448    }
00449 
00450    if (--t->reentrancy < 0) {
00451       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00452                filename, lineno, func, mutex_name);
00453       t->reentrancy = 0;
00454    }
00455 
00456    if (t->reentrancy < AST_MAX_REENTRANCY) {
00457       t->file[t->reentrancy] = NULL;
00458       t->lineno[t->reentrancy] = 0;
00459       t->func[t->reentrancy] = NULL;
00460       t->thread[t->reentrancy] = 0;
00461    }
00462 
00463    if (t->track)
00464       ast_remove_lock_info(&t->mutex);
00465 
00466    if ((res = pthread_cond_wait(cond, &t->mutex))) {
00467       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
00468                filename, lineno, func, strerror(res));
00469       DO_THREAD_CRASH;
00470    } else {
00471       if (t->track)
00472          ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
00473 
00474       if (t->reentrancy < AST_MAX_REENTRANCY) {
00475          t->file[t->reentrancy] = filename;
00476          t->lineno[t->reentrancy] = lineno;
00477          t->func[t->reentrancy] = func;
00478          t->thread[t->reentrancy] = pthread_self();
00479          t->reentrancy++;
00480       } else {
00481          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00482                         filename, lineno, func, mutex_name);
00483       }
00484    }
00485 
00486    return res;
00487 }
00488 
00489 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00490                    const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00491                    ast_mutex_t *t, const struct timespec *abstime)
00492 {
00493    int res;
00494    int canlog = strcmp(filename, "logger.c");
00495 
00496 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00497    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00498       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00499                filename, lineno, func, mutex_name);
00500    }
00501 #endif
00502 
00503    if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00504       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00505                filename, lineno, func, mutex_name);
00506       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00507                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00508       DO_THREAD_CRASH;
00509    }
00510 
00511    if (--t->reentrancy < 0) {
00512       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00513                filename, lineno, func, mutex_name);
00514       t->reentrancy = 0;
00515    }
00516 
00517    if (t->reentrancy < AST_MAX_REENTRANCY) {
00518       t->file[t->reentrancy] = NULL;
00519       t->lineno[t->reentrancy] = 0;
00520       t->func[t->reentrancy] = NULL;
00521       t->thread[t->reentrancy] = 0;
00522    }
00523 
00524    if (t->track)
00525       ast_remove_lock_info(&t->mutex);
00526 
00527    if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00528       __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
00529                filename, lineno, func, strerror(res));
00530       DO_THREAD_CRASH;
00531    } else {
00532       if (t->track)
00533          ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
00534 
00535       if (t->reentrancy < AST_MAX_REENTRANCY) {
00536          t->file[t->reentrancy] = filename;
00537          t->lineno[t->reentrancy] = lineno;
00538          t->func[t->reentrancy] = func;
00539          t->thread[t->reentrancy] = pthread_self();
00540          t->reentrancy++;
00541       } else {
00542          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00543                         filename, lineno, func, mutex_name);
00544       }
00545    }
00546 
00547    return res;
00548 }
00549 
00550 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00551 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00552 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00553 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00554 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00555 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00556 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00557 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00558 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00559 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00560 
00561 #else /* !DEBUG_THREADS */
00562 
00563 
00564 typedef pthread_mutex_t ast_mutex_t;
00565 
00566 #define AST_MUTEX_INIT_VALUE  ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00567 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00568    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00569 
00570 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
00571 
00572 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00573 {
00574    pthread_mutexattr_t attr;
00575 
00576    pthread_mutexattr_init(&attr);
00577    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00578 
00579    return pthread_mutex_init(pmutex, &attr);
00580 }
00581 
00582 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00583 
00584 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
00585 {
00586    return pthread_mutex_unlock(pmutex);
00587 }
00588 
00589 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
00590 {
00591    return pthread_mutex_destroy(pmutex);
00592 }
00593 
00594 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00595 {
00596    __MTX_PROF(pmutex);
00597 }
00598 
00599 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00600 {
00601    return pthread_mutex_trylock(pmutex);
00602 }
00603 
00604 typedef pthread_cond_t ast_cond_t;
00605 
00606 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
00607 {
00608    return pthread_cond_init(cond, cond_attr);
00609 }
00610 
00611 static inline int ast_cond_signal(ast_cond_t *cond)
00612 {
00613    return pthread_cond_signal(cond);
00614 }
00615 
00616 static inline int ast_cond_broadcast(ast_cond_t *cond)
00617 {
00618    return pthread_cond_broadcast(cond);
00619 }
00620 
00621 static inline int ast_cond_destroy(ast_cond_t *cond)
00622 {
00623    return pthread_cond_destroy(cond);
00624 }
00625 
00626 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
00627 {
00628    return pthread_cond_wait(cond, t);
00629 }
00630 
00631 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
00632 {
00633    return pthread_cond_timedwait(cond, t, abstime);
00634 }
00635 
00636 #endif /* !DEBUG_THREADS */
00637 
00638 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00639 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00640  constructors/destructors to create/destroy mutexes.  */
00641 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00642    scope ast_mutex_t mutex = init_val; \
00643 static void  __attribute__ ((constructor)) init_##mutex(void) \
00644 { \
00645    if (track) \
00646       ast_mutex_init(&mutex); \
00647    else \
00648       ast_mutex_init_notracking(&mutex); \
00649 } \
00650 static void  __attribute__ ((destructor)) fini_##mutex(void) \
00651 { \
00652    ast_mutex_destroy(&mutex); \
00653 }
00654 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
00655 /* By default, use static initialization of mutexes. */ 
00656 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00657    scope ast_mutex_t mutex = init_val
00658 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00659 
00660 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00661 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00662 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00663 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00664 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
00665 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
00666 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
00667 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
00668 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
00669 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
00670 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
00671 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
00672 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
00673 
00674 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
00675 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
00676 
00677 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00678 
00679 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00680 
00681 #ifndef __linux__
00682 #define pthread_create __use_ast_pthread_create_instead__
00683 #endif
00684 
00685 typedef pthread_rwlock_t ast_rwlock_t;
00686 
00687 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
00688 {
00689    pthread_rwlockattr_t attr;
00690 
00691    pthread_rwlockattr_init(&attr);
00692 
00693 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
00694    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
00695 #endif
00696 
00697    return pthread_rwlock_init(prwlock, &attr);
00698 }
00699 
00700 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
00701 {
00702    return pthread_rwlock_destroy(prwlock);
00703 }
00704 
00705 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
00706 {
00707    return pthread_rwlock_unlock(prwlock);
00708 }
00709 
00710 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
00711 {
00712    return pthread_rwlock_rdlock(prwlock);
00713 }
00714 
00715 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
00716 {
00717    return pthread_rwlock_tryrdlock(prwlock);
00718 }
00719 
00720 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
00721 {
00722    return pthread_rwlock_wrlock(prwlock);
00723 }
00724 
00725 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
00726 {
00727    return pthread_rwlock_trywrlock(prwlock);
00728 }
00729 
00730 /* Statically declared read/write locks */
00731 
00732 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
00733 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
00734         scope ast_rwlock_t rwlock; \
00735 static void  __attribute__ ((constructor)) init_##rwlock(void) \
00736 { \
00737         ast_rwlock_init(&rwlock); \
00738 } \
00739 static void  __attribute__ ((destructor)) fini_##rwlock(void) \
00740 { \
00741         ast_rwlock_destroy(&rwlock); \
00742 }
00743 #else
00744 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
00745 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
00746         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
00747 #endif
00748 
00749 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
00750 
00751 /*
00752  * Initial support for atomic instructions.
00753  * For platforms that have it, use the native cpu instruction to
00754  * implement them. For other platforms, resort to a 'slow' version
00755  * (defined in utils.c) that protects the atomic instruction with
00756  * a single lock.
00757  * The slow versions is always available, for testing purposes,
00758  * as ast_atomic_fetchadd_int_slow()
00759  */
00760 
00761 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
00762 
00763 #include "asterisk/inline_api.h"
00764 
00765 #if defined(HAVE_OSX_ATOMICS)
00766 #include "libkern/OSAtomic.h"
00767 #endif
00768 
00769 /*! \brief Atomically add v to *p and return * the previous value of *p.
00770  * This can be used to handle reference counts, and the return value
00771  * can be used to generate unique identifiers.
00772  */
00773 
00774 #if defined(HAVE_GCC_ATOMICS)
00775 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00776 {
00777    return __sync_fetch_and_add(p, v);
00778 })
00779 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
00780 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00781 {
00782    return OSAtomicAdd32(v, (int32_t *) p);
00783 })
00784 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
00785 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00786 {
00787    return OSAtomicAdd64(v, (int64_t *) p);
00788 #elif defined (__i386__)
00789 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00790 {
00791    __asm __volatile (
00792    "       lock   xaddl   %0, %1 ;        "
00793    : "+r" (v),                     /* 0 (result) */   
00794      "=m" (*p)                     /* 1 */
00795    : "m" (*p));                    /* 2 */
00796    return (v);
00797 })
00798 #else   /* low performance version in utils.c */
00799 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00800 {
00801    return ast_atomic_fetchadd_int_slow(p, v);
00802 })
00803 #endif
00804 
00805 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
00806  * Useful e.g. to check if a refcount has reached 0.
00807  */
00808 #if defined(HAVE_GCC_ATOMICS)
00809 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00810 {
00811    return __sync_sub_and_fetch(p, 1) == 0;
00812 })
00813 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
00814 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00815 {
00816    return OSAtomicAdd32( -1, (int32_t *) p) == 0;
00817 })
00818 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
00819 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00820 {
00821    return OSAtomicAdd64( -1, (int64_t *) p) == 0;
00822 #else
00823 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00824 {
00825    int a = ast_atomic_fetchadd_int(p, -1);
00826    return a == 1; /* true if the value is 0 now (so it was 1 previously) */
00827 })
00828 #endif
00829 
00830 #ifndef DEBUG_CHANNEL_LOCKS
00831 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
00832    in the Makefile, print relevant output for debugging */
00833 #define ast_channel_lock(x)      ast_mutex_lock(&x->lock)
00834 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
00835    in the Makefile, print relevant output for debugging */
00836 #define ast_channel_unlock(x)    ast_mutex_unlock(&x->lock)
00837 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
00838    in the Makefile, print relevant output for debugging */
00839 #define ast_channel_trylock(x)      ast_mutex_trylock(&x->lock)
00840 #else
00841 
00842 struct ast_channel;
00843 
00844 /*! \brief Lock AST channel (and print debugging output)
00845 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
00846 int ast_channel_lock(struct ast_channel *chan);
00847 
00848 /*! \brief Unlock AST channel (and print debugging output)
00849 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
00850 */
00851 int ast_channel_unlock(struct ast_channel *chan);
00852 
00853 /*! \brief Lock AST channel (and print debugging output)
00854 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
00855 int ast_channel_trylock(struct ast_channel *chan);
00856 #endif
00857 
00858 #endif /* _ASTERISK_LOCK_H */

Generated on Fri Aug 24 02:22:15 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1