Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

lock.h

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * General Asterisk channel definitions.
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #ifndef _ASTERISK_LOCK_H
00015 #define _ASTERISK_LOCK_H
00016 
00017 #include <pthread.h>
00018 #include <netdb.h>
00019 #include <time.h>
00020 #include <sys/param.h>
00021 
00022 #define AST_PTHREADT_NULL (pthread_t) -1
00023 #define AST_PTHREADT_STOP (pthread_t) -2
00024 
00025 #ifdef __APPLE__
00026 /* Provide the Linux initializers for MacOS X */
00027 #define PTHREAD_MUTEX_RECURSIVE_NP              PTHREAD_MUTEX_RECURSIVE
00028 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP      { 0x4d555458, \
00029                                           { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
00030                                            0x20 } }
00031 #endif
00032 
00033 #ifdef BSD
00034 #ifdef __GNUC__
00035 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00036 #else
00037 #define AST_MUTEX_INIT_ON_FIRST_USE
00038 #endif
00039 #endif /* BSD */
00040 
00041 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
00042    and will not run without them. */
00043 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00044 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00045 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE_NP
00046 #else
00047 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00048 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE
00049 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
00050 
00051 #ifdef DEBUG_THREADS
00052 
00053 #ifdef THREAD_CRASH
00054 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00055 #endif
00056 
00057 #include <errno.h>
00058 #include <string.h>
00059 #include <stdio.h>
00060 #include <unistd.h>
00061 
00062 #define AST_MUTEX_INIT_VALUE      { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, NULL, 0 }
00063 
00064 struct ast_mutex_info {
00065    pthread_mutex_t mutex;
00066    char *file;
00067    int lineno;
00068    char *func;
00069    pthread_t thread;
00070 };
00071 
00072 typedef struct ast_mutex_info ast_mutex_t;
00073 
00074 static inline int __ast_pthread_mutex_init_attr(char *filename, int lineno, char *func,
00075                   char* mutex_name, ast_mutex_t *t,
00076                   pthread_mutexattr_t *attr) 
00077 {
00078 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00079    if ((t->mutex) != ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00080       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
00081          filename, lineno, func, mutex_name);
00082       fprintf(stderr, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
00083          t->file, t->lineno, t->func, mutex_name);
00084 #ifdef THREAD_CRASH
00085       DO_THREAD_CRASH;
00086 #endif
00087       return 0;
00088    }
00089 #endif
00090    t->file = filename;
00091    t->lineno = lineno;
00092    t->func = func;
00093    t->thread  = 0;
00094    return pthread_mutex_init(&t->mutex, attr);
00095 }
00096 
00097 static inline int __ast_pthread_mutex_init(char *filename, int lineno, char *func,
00098                   char *mutex_name, ast_mutex_t *t)
00099 {
00100    static pthread_mutexattr_t  attr;
00101    pthread_mutexattr_init(&attr);
00102    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00103    return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
00104 }
00105 
00106 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00107 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
00108 
00109 static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func,
00110                   char *mutex_name, ast_mutex_t *t)
00111 {
00112    int res;
00113 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00114    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00115       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00116          filename, lineno, func, mutex_name);
00117    }
00118 #endif
00119    res = pthread_mutex_trylock(&t->mutex);
00120    switch (res) {
00121    case 0:
00122       pthread_mutex_unlock(&t->mutex);
00123       break;
00124    case EINVAL:
00125       fprintf(stderr, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00126          filename, lineno, func, mutex_name);
00127       break;
00128    case EBUSY:
00129       fprintf(stderr, "%s line %d (%s): Error: attemp to destroy locked mutex '%s'.\n",
00130          filename, lineno, func, mutex_name);
00131       fprintf(stderr, "%s line %d (%s): Error: '%s' was locked here.\n",
00132          t->file, t->lineno, t->func, mutex_name);
00133       break;
00134    }
00135    res = pthread_mutex_destroy(&t->mutex);
00136    if (res) 
00137       fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
00138             filename, lineno, func, strerror(res));
00139 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00140    else
00141       t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00142 #endif
00143    t->file = filename;
00144    t->lineno = lineno;
00145    t->func = func;
00146    return res;
00147 }
00148 
00149 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00150 
00151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00152 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00153  constrictors/destructors to create/destroy mutexes.  */
00154 #define __AST_MUTEX_DEFINE(scope,mutex) \
00155    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
00156 static void  __attribute__ ((constructor)) init_##mutex(void) \
00157 { \
00158    ast_mutex_init(&mutex); \
00159 } \
00160 static void  __attribute__ ((destructor)) fini_##mutex(void) \
00161 { \
00162    ast_mutex_destroy(&mutex); \
00163 }
00164 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
00165 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
00166  first use.  The performance impact on FreeBSD should be small since
00167  the pthreads library does this itself to initialize errror checking
00168  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
00169  does the initialization itself on first use. */ 
00170 #define __AST_MUTEX_DEFINE(scope,mutex) \
00171    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00172 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00173 /* By default, use static initialization of mutexes.*/ 
00174 #define __AST_MUTEX_DEFINE(scope,mutex) \
00175    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00176 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00177 
00178 
00179 
00180 static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func,
00181                                            char* mutex_name, ast_mutex_t *t)
00182 {
00183    int res;
00184 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
00185    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00186 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00187       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00188          filename, lineno, func, mutex_name);
00189 #endif
00190       ast_mutex_init(t);
00191    }
00192 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
00193 #ifdef DETECT_DEADLOCKS
00194    {
00195       time_t seconds = time(NULL);
00196       time_t current;
00197       do {
00198          res = pthread_mutex_trylock(&t->mutex);
00199          if (res == EBUSY) {
00200             current = time(NULL);
00201             if ((current - seconds) && (!((current - seconds) % 5))) {
00202                fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00203                   filename, lineno, func, (int)(current - seconds), mutex_name);
00204                fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
00205                   t->file, t->lineno, t->func, mutex_name);
00206             }
00207             usleep(200);
00208          }
00209       } while (res == EBUSY);
00210    }
00211 #else
00212    res = pthread_mutex_lock(&t->mutex);
00213 #endif /*  DETECT_DEADLOCKS */
00214    if (!res) {
00215       t->file = filename;
00216       t->lineno = lineno;
00217       t->func = func;
00218       t->thread = pthread_self();
00219    } else {
00220       fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
00221          filename, lineno, func, strerror(errno));
00222 #ifdef THREAD_CRASH
00223       DO_THREAD_CRASH;
00224 #endif
00225    }
00226    return res;
00227 }
00228 
00229 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00230 
00231 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
00232                                               char* mutex_name, ast_mutex_t *t)
00233 {
00234    int res;
00235 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
00236    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00237 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00238       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00239          filename, lineno, func, mutex_name);
00240 #endif
00241       ast_mutex_init(t);
00242    }
00243 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
00244    res = pthread_mutex_trylock(&t->mutex);
00245    if (!res) {
00246       t->file = filename;
00247       t->lineno = lineno;
00248       t->func = func;
00249       t->thread = pthread_self();
00250    }
00251    return res;
00252 }
00253 
00254 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00255 
00256 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
00257          char* mutex_name, ast_mutex_t *t) {
00258    int res;
00259 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00260    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00261       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00262          filename, lineno, func, mutex_name);
00263    }
00264 #endif
00265    /* Assumes lock is actually held */
00266    t->file = NULL;
00267    t->lineno = 0;
00268    t->func = NULL;
00269    t->thread = 0;
00270    res = pthread_mutex_unlock(&t->mutex);
00271    if (res) {
00272       fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
00273             filename, lineno, func, strerror(res));
00274 #ifdef THREAD_CRASH
00275       DO_THREAD_CRASH;
00276 #endif
00277    }
00278    return res;
00279 }
00280 
00281 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00282 
00283 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00284 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00285 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00286 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00287 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
00288 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
00289 
00290 #else /* DEBUG_THREADS */
00291 
00292 
00293 #define AST_MUTEX_INIT_VALUE  PTHREAD_MUTEX_INIT_VALUE
00294 
00295 
00296 typedef pthread_mutex_t ast_mutex_t;
00297 
00298 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00299 {
00300    pthread_mutexattr_t attr;
00301    pthread_mutexattr_init(&attr);
00302    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00303    return pthread_mutex_init(pmutex, &attr);
00304 }
00305 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00306 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
00307 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
00308 
00309 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00310 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00311  constrictors/destructors to create/destroy mutexes.  */ 
00312 #define __AST_MUTEX_DEFINE(scope,mutex) \
00313    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
00314 static void  __attribute__ ((constructor)) init_##mutex(void) \
00315 { \
00316    ast_mutex_init(&mutex); \
00317 } \
00318 static void  __attribute__ ((destructor)) fini_##mutex(void) \
00319 { \
00320    ast_mutex_destroy(&mutex); \
00321 }
00322 
00323 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
00324 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
00325 
00326 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
00327 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
00328  first use.  The performance impact on FreeBSD should be small since
00329  the pthreads library does this itself to initialize errror checking
00330  (defaulty type) mutexes.*/ 
00331 #define __AST_MUTEX_DEFINE(scope,mutex) \
00332    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00333 
00334 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00335 {
00336    if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
00337       ast_mutex_init(pmutex);
00338    return pthread_mutex_lock(pmutex);
00339 }
00340 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00341 {
00342    if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
00343       ast_mutex_init(pmutex);
00344    return pthread_mutex_trylock(pmutex);
00345 }
00346 #else
00347 /* By default, use static initialization of mutexes.*/ 
00348 #define __AST_MUTEX_DEFINE(scope,mutex) \
00349    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00350 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
00351 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
00352 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00353 
00354 #endif /* DEBUG_THREADS */
00355 
00356 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
00357 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
00358 
00359 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00360 
00361 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00362 #define pthread_create __use_ast_pthread_create_instead__
00363 
00364 #endif

Generated on Sat Nov 25 19:09:38 2006 for Asterisk by  doxygen 1.4.2