Fix typo and missing format string in a fprintf in lock.h
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * General Asterisk channel definitions.
5  * 
6  * Copyright (C) 1999-2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #ifndef _ASTERISK_LOCK_H
15 #define _ASTERISK_LOCK_H
16
17 #include <pthread.h>
18 #include <netdb.h>
19 #include <time.h>
20 #include <sys/param.h>
21
22 #define AST_PTHREADT_NULL (pthread_t) -1
23 #define AST_PTHREADT_STOP (pthread_t) -2
24
25 #ifdef __APPLE__
26 /* Provide the Linux initializers for MacOS X */
27 #define PTHREAD_MUTEX_RECURSIVE_NP                                      PTHREAD_MUTEX_RECURSIVE
28 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP           { 0x4d555458, \
29                                                                                                            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
30                                                                                                                  0x20 } }
31 #endif
32
33 #ifdef BSD
34 #ifdef __GNUC__
35 #define AST_MUTEX_INIT_W_CONSTRUCTORS
36 #else
37 #define AST_MUTEX_INIT_ON_FIRST_USE
38 #endif
39 #endif /* BSD */
40
41 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
42    and will not run without them. */
43 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
44 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
45 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
46 #else
47 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
48 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
49 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
50
51 #ifdef DEBUG_THREADS
52
53 #ifdef THREAD_CRASH
54 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
55 #endif
56
57 #include <errno.h>
58 #include <string.h>
59 #include <stdio.h>
60 #include <unistd.h>
61
62 #define AST_MUTEX_INIT_VALUE      { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, NULL, 0 }
63
64 struct ast_mutex_info {
65         pthread_mutex_t mutex;
66         char *file;
67         int lineno;
68         int reentrancy;
69         char *func;
70         pthread_t thread;
71 };
72
73 typedef struct ast_mutex_info ast_mutex_t;
74
75 static inline int __ast_pthread_mutex_init_attr(char *filename, int lineno, char *func,
76                                                 char* mutex_name, ast_mutex_t *t,
77                                                 pthread_mutexattr_t *attr) 
78 {
79 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
80         if ((t->mutex) != ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
81                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
82                         filename, lineno, func, mutex_name);
83                 fprintf(stderr, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
84                         t->file, t->lineno, t->func, mutex_name);
85 #ifdef THREAD_CRASH
86                 DO_THREAD_CRASH;
87 #endif
88                 return 0;
89         }
90 #endif
91         t->file = filename;
92         t->lineno = lineno;
93         t->func = func;
94         t->thread  = 0;
95         t->reentrancy = 0;
96         return pthread_mutex_init(&t->mutex, attr);
97 }
98
99 static inline int __ast_pthread_mutex_init(char *filename, int lineno, char *func,
100                                                 char *mutex_name, ast_mutex_t *t)
101 {
102         static pthread_mutexattr_t  attr;
103         pthread_mutexattr_init(&attr);
104         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
105         return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
106 }
107
108 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
109 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
110
111 static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func,
112                                                 char *mutex_name, ast_mutex_t *t)
113 {
114         int res;
115 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
116         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
117                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
118                         filename, lineno, func, mutex_name);
119         }
120 #endif
121         res = pthread_mutex_trylock(&t->mutex);
122         switch (res) {
123         case 0:
124                 pthread_mutex_unlock(&t->mutex);
125                 break;
126         case EINVAL:
127                 fprintf(stderr, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
128                         filename, lineno, func, mutex_name);
129                 break;
130         case EBUSY:
131                 fprintf(stderr, "%s line %d (%s): Error: attemp to destroy locked mutex '%s'.\n",
132                         filename, lineno, func, mutex_name);
133                 fprintf(stderr, "%s line %d (%s): Error: '%s' was locked here.\n",
134                         t->file, t->lineno, t->func, mutex_name);
135                 break;
136         }
137         res = pthread_mutex_destroy(&t->mutex);
138         if (res) 
139                 fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
140                                 filename, lineno, func, strerror(res));
141 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
142         else
143                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
144 #endif
145         t->file = filename;
146         t->lineno = lineno;
147         t->func = func;
148         return res;
149 }
150
151 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
152
153 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
154 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
155  constrictors/destructors to create/destroy mutexes.  */
156 #define __AST_MUTEX_DEFINE(scope,mutex) \
157         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
158 static void  __attribute__ ((constructor)) init_##mutex(void) \
159 { \
160         ast_mutex_init(&mutex); \
161 } \
162 static void  __attribute__ ((destructor)) fini_##mutex(void) \
163 { \
164         ast_mutex_destroy(&mutex); \
165 }
166 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
167 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
168  first use.  The performance impact on FreeBSD should be small since
169  the pthreads library does this itself to initialize errror checking
170  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
171  does the initialization itself on first use. */ 
172 #define __AST_MUTEX_DEFINE(scope,mutex) \
173         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
174 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
175 /* By default, use static initialization of mutexes.*/ 
176 #define __AST_MUTEX_DEFINE(scope,mutex) \
177         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
178 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
179
180
181
182 static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func,
183                                            char* mutex_name, ast_mutex_t *t)
184 {
185         int res;
186 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
187         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
188 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
189                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
190                         filename, lineno, func, mutex_name);
191 #endif
192                 ast_mutex_init(t);
193         }
194 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
195 #ifdef DETECT_DEADLOCKS
196         {
197                 time_t seconds seconds = time(NULL);
198                 do {
199                         res = pthread_mutex_trylock(&t->mutex);
200                         if (res == EBUSY) {
201                                 if ((time(NULL) - seconds) % 5) {
202                                         fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
203                                                 filename, lineno, func, (time(NULL) - seconds), mutex_name);
204                                         fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
205                                                 t->file, t->lineno, t->func, mutex_name);
206                                 }
207                                 usleep(200);
208                         }
209                 } while (res == EBUSY);
210         }
211 #else
212         res = pthread_mutex_lock(&t->mutex);
213 #endif /*  DETECT_DEADLOCKS */
214         if (!res) {
215                 t->reentrancy++;
216                 t->file = filename;
217                 t->lineno = lineno;
218                 t->func = func;
219                 t->thread = pthread_self();
220         } else {
221                 fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
222                         filename, lineno, func, strerror(errno));
223 #ifdef THREAD_CRASH
224                 DO_THREAD_CRASH;
225 #endif
226         }
227         return res;
228 }
229
230 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
231
232 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
233                                               char* mutex_name, ast_mutex_t *t)
234 {
235         int res;
236 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
237         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
238 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
239                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
240                         filename, lineno, func, mutex_name);
241 #endif
242                 ast_mutex_init(t);
243         }
244 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
245         res = pthread_mutex_trylock(&t->mutex);
246         if (!res) {
247                 t->reentrancy++;
248                 t->file = filename;
249                 t->lineno = lineno;
250                 t->func = func;
251                 t->thread = pthread_self();
252         }
253         return res;
254 }
255
256 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
257
258 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
259                         char* mutex_name, ast_mutex_t *t) {
260         int res;
261 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
262         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
263                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
264                         filename, lineno, func, mutex_name);
265         }
266 #endif
267         --t->reentrancy;
268         if (t->reentrancy < 0) {
269                 fprintf(stderr, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
270                         filename, lineno, func, mutex_name);
271                 t->reentrancy = 0;
272         }
273         if (!t->reentrancy) {
274                 t->file = NULL;
275                 t->lineno = 0;
276                 t->func = NULL;
277                 t->thread = 0;
278         }
279         res = pthread_mutex_unlock(&t->mutex);
280         if (res) {
281                 fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
282                                 filename, lineno, func, strerror(res));
283 #ifdef THREAD_CRASH
284                 DO_THREAD_CRASH;
285 #endif
286         }
287         return res;
288 }
289
290 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
291
292 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
293 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
294 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
295 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
296 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
297 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
298
299 #else /* DEBUG_THREADS */
300
301
302 #define AST_MUTEX_INIT_VALUE    PTHREAD_MUTEX_INIT_VALUE
303
304
305 typedef pthread_mutex_t ast_mutex_t;
306
307 static inline int ast_mutex_init(ast_mutex_t *pmutex)
308 {
309         pthread_mutexattr_t attr;
310         pthread_mutexattr_init(&attr);
311         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
312         return pthread_mutex_init(pmutex, &attr);
313 }
314 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
315 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
316 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
317
318 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
319 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
320  constrictors/destructors to create/destroy mutexes.  */ 
321 #define __AST_MUTEX_DEFINE(scope,mutex) \
322         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
323 static void  __attribute__ ((constructor)) init_##mutex(void) \
324 { \
325         ast_mutex_init(&mutex); \
326 } \
327 static void  __attribute__ ((destructor)) fini_##mutex(void) \
328 { \
329         ast_mutex_destroy(&mutex); \
330 }
331
332 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
333 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
334
335 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
336 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
337  first use.  The performance impact on FreeBSD should be small since
338  the pthreads library does this itself to initialize errror checking
339  (defaulty type) mutexes.*/ 
340 #define __AST_MUTEX_DEFINE(scope,mutex) \
341         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
342
343 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
344 {
345         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
346                 ast_mutex_init(pmutex);
347         return pthread_mutex_lock(pmutex);
348 }
349 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
350 {
351         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
352                 ast_mutex_init(pmutex);
353         return pthread_mutex_trylock(pmutex);
354 }
355 #else
356 /* By default, use static initialization of mutexes.*/ 
357 #define __AST_MUTEX_DEFINE(scope,mutex) \
358         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
359 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
360 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
361 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
362
363 #endif /* DEBUG_THREADS */
364
365 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
366 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
367
368 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
369
370 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
371 #ifndef __linux__
372 #define pthread_create __use_ast_pthread_create_instead__
373 #endif
374
375 #endif