Main Page   Alphabetical List   Data Structures   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 seconds = time(NULL);
00196       do {
00197          res = pthread_mutex_trylock(&t->mutex);
00198          if (res == EBUSY) {
00199             if ((time(NULL) - seconds) % 5) {
00200                fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00201                   filename, lineno, func, (time(NULL) - seconds), mutex_name);
00202                fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
00203                   t->file, t->lineno, t->func, mutex_name);
00204             }
00205             usleep(200);
00206          }
00207       } while (res == EBUSY);
00208    }
00209 #else
00210    res = pthread_mutex_lock(&t->mutex);
00211 #endif /*  DETECT_DEADLOCKS */
00212    if (!res) {
00213       t->file = filename;
00214       t->lineno = lineno;
00215       t->func = func;
00216       t->thread = pthread_self();
00217    } else {
00218       fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
00219          filename, lineno, func, strerror(errno));
00220 #ifdef THREAD_CRASH
00221       DO_THREAD_CRASH;
00222 #endif
00223    }
00224    return res;
00225 }
00226 
00227 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00228 
00229 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
00230                                               char* mutex_name, ast_mutex_t *t)
00231 {
00232    int res;
00233 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
00234    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00235 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00236       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00237          filename, lineno, func, mutex_name);
00238 #endif
00239       ast_mutex_init(t);
00240    }
00241 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
00242    res = pthread_mutex_trylock(&t->mutex);
00243    if (!res) {
00244       t->file = filename;
00245       t->lineno = lineno;
00246       t->func = func;
00247       t->thread = pthread_self();
00248    }
00249    return res;
00250 }
00251 
00252 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00253 
00254 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
00255          char* mutex_name, ast_mutex_t *t) {
00256    int res;
00257 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00258    if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
00259       fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00260          filename, lineno, func, mutex_name);
00261    }
00262 #endif
00263    /* Assumes lock is actually held */
00264    t->file = NULL;
00265    t->lineno = 0;
00266    t->func = NULL;
00267    t->thread = 0;
00268    res = pthread_mutex_unlock(&t->mutex);
00269    if (res) {
00270       fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
00271             filename, lineno, func, strerror(res));
00272 #ifdef THREAD_CRASH
00273       DO_THREAD_CRASH;
00274 #endif
00275    }
00276    return res;
00277 }
00278 
00279 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00280 
00281 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00282 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00283 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00284 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00285 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
00286 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
00287 
00288 #else /* DEBUG_THREADS */
00289 
00290 
00291 #define AST_MUTEX_INIT_VALUE  PTHREAD_MUTEX_INIT_VALUE
00292 
00293 
00294 typedef pthread_mutex_t ast_mutex_t;
00295 
00296 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00297 {
00298    pthread_mutexattr_t attr;
00299    pthread_mutexattr_init(&attr);
00300    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00301    return pthread_mutex_init(pmutex, &attr);
00302 }
00303 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00304 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
00305 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
00306 
00307 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00308 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00309  constrictors/destructors to create/destroy mutexes.  */ 
00310 #define __AST_MUTEX_DEFINE(scope,mutex) \
00311    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
00312 static void  __attribute__ ((constructor)) init_##mutex(void) \
00313 { \
00314    ast_mutex_init(&mutex); \
00315 } \
00316 static void  __attribute__ ((destructor)) fini_##mutex(void) \
00317 { \
00318    ast_mutex_destroy(&mutex); \
00319 }
00320 
00321 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
00322 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
00323 
00324 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
00325 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
00326  first use.  The performance impact on FreeBSD should be small since
00327  the pthreads library does this itself to initialize errror checking
00328  (defaulty type) mutexes.*/ 
00329 #define __AST_MUTEX_DEFINE(scope,mutex) \
00330    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00331 
00332 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00333 {
00334    if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
00335       ast_mutex_init(pmutex);
00336    return pthread_mutex_lock(pmutex);
00337 }
00338 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00339 {
00340    if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
00341       ast_mutex_init(pmutex);
00342    return pthread_mutex_trylock(pmutex);
00343 }
00344 #else
00345 /* By default, use static initialization of mutexes.*/ 
00346 #define __AST_MUTEX_DEFINE(scope,mutex) \
00347    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00348 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
00349 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
00350 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00351 
00352 #endif /* DEBUG_THREADS */
00353 
00354 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
00355 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
00356 
00357 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00358 
00359 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00360 #define pthread_create __use_ast_pthread_create_instead__
00361 
00362 #endif

Generated on Thu Oct 28 11:32:54 2004 for Asterisk by doxygen1.2.15