Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:49 2007

Asterisk developer's documentation :: Codename Pineapple


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

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen